1 // ----------------------------------------------------------------------------
2 // - CloudViewer: www.cloudViewer.org -
3 // ----------------------------------------------------------------------------
4 // Copyright (c) 2018-2024 www.cloudViewer.org
5 // SPDX-License-Identifier: MIT
6 // ----------------------------------------------------------------------------
10 #include "mvs/gpu_mat_ref_image.h"
11 #include "util/cudacc.h"
17 __global__ void FilterKernel(const cudaTextureObject_t image_texture,
18 GpuMat<uint8_t> image,
19 GpuMat<float> sum_image,
20 GpuMat<float> squared_sum_image,
21 const int window_radius,
22 const int window_step,
23 const float sigma_spatial,
24 const float sigma_color) {
25 const size_t row = blockDim.y * blockIdx.y + threadIdx.y;
26 const size_t col = blockDim.x * blockIdx.x + threadIdx.x;
27 if (row >= image.GetHeight() || col >= image.GetWidth()) {
31 BilateralWeightComputer bilateral_weight_computer(sigma_spatial,
34 const float center_color = tex2D<float>(image_texture, col, row);
36 float color_sum = 0.0f;
37 float color_squared_sum = 0.0f;
38 float bilateral_weight_sum = 0.0f;
40 for (int window_row = -window_radius; window_row <= window_radius;
41 window_row += window_step) {
42 for (int window_col = -window_radius; window_col <= window_radius;
43 window_col += window_step) {
44 const float color = tex2D<float>(image_texture, col + window_col,
46 const float bilateral_weight = bilateral_weight_computer.Compute(
47 window_row, window_col, center_color, color);
48 color_sum += bilateral_weight * color;
49 color_squared_sum += bilateral_weight * color * color;
50 bilateral_weight_sum += bilateral_weight;
54 color_sum /= bilateral_weight_sum;
55 color_squared_sum /= bilateral_weight_sum;
57 image.Set(row, col, static_cast<uint8_t>(255.0f * center_color));
58 sum_image.Set(row, col, color_sum);
59 squared_sum_image.Set(row, col, color_squared_sum);
64 GpuMatRefImage::GpuMatRefImage(const size_t width, const size_t height)
65 : width_(width), height_(height) {
66 image.reset(new GpuMat<uint8_t>(width, height));
67 sum_image.reset(new GpuMat<float>(width, height));
68 squared_sum_image.reset(new GpuMat<float>(width, height));
71 void GpuMatRefImage::Filter(const uint8_t* image_data,
72 const size_t window_radius,
73 const size_t window_step,
74 const float sigma_spatial,
75 const float sigma_color) {
76 cudaTextureDesc texture_desc;
77 memset(&texture_desc, 0, sizeof(texture_desc));
78 texture_desc.addressMode[0] = cudaAddressModeBorder;
79 texture_desc.addressMode[1] = cudaAddressModeBorder;
80 texture_desc.addressMode[2] = cudaAddressModeBorder;
81 texture_desc.filterMode = cudaFilterModePoint;
82 texture_desc.readMode = cudaReadModeNormalizedFloat;
83 texture_desc.normalizedCoords = false;
84 auto image_texture = CudaArrayLayeredTexture<uint8_t>::FromHostArray(
85 texture_desc, width_, height_, 1, image_data);
87 const dim3 block_size(kBlockDimX, kBlockDimY);
88 const dim3 grid_size((width_ - 1) / block_size.x + 1,
89 (height_ - 1) / block_size.y + 1);
91 FilterKernel<<<grid_size, block_size>>>(
92 image_texture->GetObj(), *image, *sum_image, *squared_sum_image,
93 window_radius, window_step, sigma_spatial, sigma_color);
94 CUDA_SYNC_AND_CHECK();