|
| 1 | +// This file is part of OpenCV project. |
| 2 | +// It is subject to the license terms in the LICENSE file found in the top-level directory |
| 3 | +// of this distribution and at http://opencv.org/license.html. |
| 4 | + |
| 5 | +#include "ndsrvp_hal.hpp" |
| 6 | +#include "opencv2/imgproc/hal/interface.h" |
| 7 | +#include "cvutils.hpp" |
| 8 | + |
| 9 | +namespace cv { |
| 10 | + |
| 11 | +namespace ndsrvp { |
| 12 | + |
| 13 | +static void bilateralFilterProcess(uchar* dst_data, size_t dst_step, uchar* pad_data, size_t pad_step, |
| 14 | + int width, int height, int cn, int radius, int maxk, |
| 15 | + int* space_ofs, float *space_weight, float *color_weight) |
| 16 | +{ |
| 17 | + int i, j, k; |
| 18 | + |
| 19 | + for( i = 0; i < height; i++ ) |
| 20 | + { |
| 21 | + const uchar* sptr = pad_data + (i + radius) * pad_step + radius * cn; |
| 22 | + uchar* dptr = dst_data + i * dst_step; |
| 23 | + |
| 24 | + if( cn == 1 ) |
| 25 | + { |
| 26 | + std::vector<float> buf(width + width, 0.0); |
| 27 | + float *sum = &buf[0]; |
| 28 | + float *wsum = sum + width; |
| 29 | + k = 0; |
| 30 | + for(; k <= maxk-4; k+=4) |
| 31 | + { |
| 32 | + const uchar* ksptr0 = sptr + space_ofs[k]; |
| 33 | + const uchar* ksptr1 = sptr + space_ofs[k+1]; |
| 34 | + const uchar* ksptr2 = sptr + space_ofs[k+2]; |
| 35 | + const uchar* ksptr3 = sptr + space_ofs[k+3]; |
| 36 | + j = 0; |
| 37 | + for (; j < width; j++) |
| 38 | + { |
| 39 | + int rval = sptr[j]; |
| 40 | + |
| 41 | + int val = ksptr0[j]; |
| 42 | + float w = space_weight[k] * color_weight[std::abs(val - rval)]; |
| 43 | + wsum[j] += w; |
| 44 | + sum[j] += val * w; |
| 45 | + |
| 46 | + val = ksptr1[j]; |
| 47 | + w = space_weight[k+1] * color_weight[std::abs(val - rval)]; |
| 48 | + wsum[j] += w; |
| 49 | + sum[j] += val * w; |
| 50 | + |
| 51 | + val = ksptr2[j]; |
| 52 | + w = space_weight[k+2] * color_weight[std::abs(val - rval)]; |
| 53 | + wsum[j] += w; |
| 54 | + sum[j] += val * w; |
| 55 | + |
| 56 | + val = ksptr3[j]; |
| 57 | + w = space_weight[k+3] * color_weight[std::abs(val - rval)]; |
| 58 | + wsum[j] += w; |
| 59 | + sum[j] += val * w; |
| 60 | + } |
| 61 | + } |
| 62 | + for(; k < maxk; k++) |
| 63 | + { |
| 64 | + const uchar* ksptr = sptr + space_ofs[k]; |
| 65 | + j = 0; |
| 66 | + for (; j < width; j++) |
| 67 | + { |
| 68 | + int val = ksptr[j]; |
| 69 | + float w = space_weight[k] * color_weight[std::abs(val - sptr[j])]; |
| 70 | + wsum[j] += w; |
| 71 | + sum[j] += val * w; |
| 72 | + } |
| 73 | + } |
| 74 | + j = 0; |
| 75 | + for (; j < width; j++) |
| 76 | + { |
| 77 | + // overflow is not possible here => there is no need to use cv::saturate_cast |
| 78 | + ndsrvp_assert(fabs(wsum[j]) > 0); |
| 79 | + dptr[j] = (uchar)(sum[j] / wsum[j] + 0.5); |
| 80 | + } |
| 81 | + } |
| 82 | + else |
| 83 | + { |
| 84 | + ndsrvp_assert( cn == 3 ); |
| 85 | + std::vector<float> buf(width * 3 + width); |
| 86 | + float *sum_b = &buf[0]; |
| 87 | + float *sum_g = sum_b + width; |
| 88 | + float *sum_r = sum_g + width; |
| 89 | + float *wsum = sum_r + width; |
| 90 | + k = 0; |
| 91 | + for(; k <= maxk-4; k+=4) |
| 92 | + { |
| 93 | + const uchar* ksptr0 = sptr + space_ofs[k]; |
| 94 | + const uchar* ksptr1 = sptr + space_ofs[k+1]; |
| 95 | + const uchar* ksptr2 = sptr + space_ofs[k+2]; |
| 96 | + const uchar* ksptr3 = sptr + space_ofs[k+3]; |
| 97 | + const uchar* rsptr = sptr; |
| 98 | + j = 0; |
| 99 | + for(; j < width; j++, rsptr += 3, ksptr0 += 3, ksptr1 += 3, ksptr2 += 3, ksptr3 += 3) |
| 100 | + { |
| 101 | + int rb = rsptr[0], rg = rsptr[1], rr = rsptr[2]; |
| 102 | + |
| 103 | + int b = ksptr0[0], g = ksptr0[1], r = ksptr0[2]; |
| 104 | + float w = space_weight[k] * color_weight[std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)]; |
| 105 | + wsum[j] += w; |
| 106 | + sum_b[j] += b * w; sum_g[j] += g * w; sum_r[j] += r * w; |
| 107 | + |
| 108 | + b = ksptr1[0]; g = ksptr1[1]; r = ksptr1[2]; |
| 109 | + w = space_weight[k+1] * color_weight[std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)]; |
| 110 | + wsum[j] += w; |
| 111 | + sum_b[j] += b * w; sum_g[j] += g * w; sum_r[j] += r * w; |
| 112 | + |
| 113 | + b = ksptr2[0]; g = ksptr2[1]; r = ksptr2[2]; |
| 114 | + w = space_weight[k+2] * color_weight[std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)]; |
| 115 | + wsum[j] += w; |
| 116 | + sum_b[j] += b * w; sum_g[j] += g * w; sum_r[j] += r * w; |
| 117 | + |
| 118 | + b = ksptr3[0]; g = ksptr3[1]; r = ksptr3[2]; |
| 119 | + w = space_weight[k+3] * color_weight[std::abs(b - rb) + std::abs(g - rg) + std::abs(r - rr)]; |
| 120 | + wsum[j] += w; |
| 121 | + sum_b[j] += b * w; sum_g[j] += g * w; sum_r[j] += r * w; |
| 122 | + } |
| 123 | + } |
| 124 | + for(; k < maxk; k++) |
| 125 | + { |
| 126 | + const uchar* ksptr = sptr + space_ofs[k]; |
| 127 | + const uchar* rsptr = sptr; |
| 128 | + j = 0; |
| 129 | + for(; j < width; j++, ksptr += 3, rsptr += 3) |
| 130 | + { |
| 131 | + int b = ksptr[0], g = ksptr[1], r = ksptr[2]; |
| 132 | + float w = space_weight[k] * color_weight[std::abs(b - rsptr[0]) + std::abs(g - rsptr[1]) + std::abs(r - rsptr[2])]; |
| 133 | + wsum[j] += w; |
| 134 | + sum_b[j] += b * w; sum_g[j] += g * w; sum_r[j] += r * w; |
| 135 | + } |
| 136 | + } |
| 137 | + j = 0; |
| 138 | + for(; j < width; j++) |
| 139 | + { |
| 140 | + ndsrvp_assert(fabs(wsum[j]) > 0); |
| 141 | + wsum[j] = 1.f / wsum[j]; |
| 142 | + *(dptr++) = (uchar)(sum_b[j] * wsum[j] + 0.5); |
| 143 | + *(dptr++) = (uchar)(sum_g[j] * wsum[j] + 0.5); |
| 144 | + *(dptr++) = (uchar)(sum_r[j] * wsum[j] + 0.5); |
| 145 | + } |
| 146 | + } |
| 147 | + } |
| 148 | +} |
| 149 | + |
| 150 | +int bilateralFilter(const uchar* src_data, size_t src_step, |
| 151 | + uchar* dst_data, size_t dst_step, int width, int height, int depth, |
| 152 | + int cn, int d, double sigma_color, double sigma_space, int border_type) |
| 153 | +{ |
| 154 | + if( depth != CV_8U || !(cn == 1 || cn == 3) || src_data == dst_data) |
| 155 | + return CV_HAL_ERROR_NOT_IMPLEMENTED; |
| 156 | + |
| 157 | + int i, j, maxk, radius; |
| 158 | + |
| 159 | + if( sigma_color <= 0 ) |
| 160 | + sigma_color = 1; |
| 161 | + if( sigma_space <= 0 ) |
| 162 | + sigma_space = 1; |
| 163 | + |
| 164 | + double gauss_color_coeff = -0.5/(sigma_color * sigma_color); |
| 165 | + double gauss_space_coeff = -0.5/(sigma_space * sigma_space); |
| 166 | + |
| 167 | + if( d <= 0 ) |
| 168 | + radius = (int)(sigma_space * 1.5 + 0.5); |
| 169 | + else |
| 170 | + radius = d / 2; |
| 171 | + |
| 172 | + radius = MAX(radius, 1); |
| 173 | + d = radius * 2 + 1; |
| 174 | + |
| 175 | + // no enough submatrix info |
| 176 | + // fetch original image data |
| 177 | + const uchar *ogn_data = src_data; |
| 178 | + int ogn_step = src_step; |
| 179 | + |
| 180 | + // ROI fully used in the computation |
| 181 | + int cal_width = width + d - 1; |
| 182 | + int cal_height = height + d - 1; |
| 183 | + int cal_x = 0 - radius; // negative if left border exceeded |
| 184 | + int cal_y = 0 - radius; // negative if top border exceeded |
| 185 | + |
| 186 | + // calculate source border |
| 187 | + std::vector<uchar> padding; |
| 188 | + padding.resize(cal_width * cal_height * cn); |
| 189 | + uchar* pad_data = &padding[0]; |
| 190 | + int pad_step = cal_width * cn; |
| 191 | + |
| 192 | + uchar* pad_ptr; |
| 193 | + const uchar* ogn_ptr; |
| 194 | + std::vector<uchar> vec_zeros(cn, 0); |
| 195 | + for(i = 0; i < cal_height; i++) |
| 196 | + { |
| 197 | + int y = borderInterpolate(i + cal_y, height, border_type); |
| 198 | + if(y < 0) { |
| 199 | + memset(pad_data + i * pad_step, 0, cn * cal_width); |
| 200 | + continue; |
| 201 | + } |
| 202 | + |
| 203 | + // left border |
| 204 | + j = 0; |
| 205 | + for(; j + cal_x < 0; j++) |
| 206 | + { |
| 207 | + int x = borderInterpolate(j + cal_x, width, border_type); |
| 208 | + if(x < 0) // border constant return value -1 |
| 209 | + ogn_ptr = &vec_zeros[0]; |
| 210 | + else |
| 211 | + ogn_ptr = ogn_data + y * ogn_step + x * cn; |
| 212 | + pad_ptr = pad_data + i * pad_step + j * cn; |
| 213 | + memcpy(pad_ptr, ogn_ptr, cn); |
| 214 | + } |
| 215 | + |
| 216 | + // center |
| 217 | + int rborder = MIN(cal_width, width - cal_x); |
| 218 | + ogn_ptr = ogn_data + y * ogn_step + (j + cal_x) * cn; |
| 219 | + pad_ptr = pad_data + i * pad_step + j * cn; |
| 220 | + memcpy(pad_ptr, ogn_ptr, cn * (rborder - j)); |
| 221 | + |
| 222 | + // right border |
| 223 | + j = rborder; |
| 224 | + for(; j < cal_width; j++) |
| 225 | + { |
| 226 | + int x = borderInterpolate(j + cal_x, width, border_type); |
| 227 | + if(x < 0) // border constant return value -1 |
| 228 | + ogn_ptr = &vec_zeros[0]; |
| 229 | + else |
| 230 | + ogn_ptr = ogn_data + y * ogn_step + x * cn; |
| 231 | + pad_ptr = pad_data + i * pad_step + j * cn; |
| 232 | + memcpy(pad_ptr, ogn_ptr, cn); |
| 233 | + } |
| 234 | + } |
| 235 | + |
| 236 | + std::vector<float> _color_weight(cn * 256); |
| 237 | + std::vector<float> _space_weight(d * d); |
| 238 | + std::vector<int> _space_ofs(d * d); |
| 239 | + float* color_weight = &_color_weight[0]; |
| 240 | + float* space_weight = &_space_weight[0]; |
| 241 | + int* space_ofs = &_space_ofs[0]; |
| 242 | + |
| 243 | + // initialize color-related bilateral filter coefficients |
| 244 | + |
| 245 | + for( i = 0; i < 256 * cn; i++ ) |
| 246 | + color_weight[i] = (float)std::exp(i * i * gauss_color_coeff); |
| 247 | + |
| 248 | + // initialize space-related bilateral filter coefficients |
| 249 | + for( i = -radius, maxk = 0; i <= radius; i++ ) |
| 250 | + { |
| 251 | + j = -radius; |
| 252 | + |
| 253 | + for( ; j <= radius; j++ ) |
| 254 | + { |
| 255 | + double r = std::sqrt((double)i * i + (double)j * j); |
| 256 | + if( r > radius ) |
| 257 | + continue; |
| 258 | + space_weight[maxk] = (float)std::exp(r * r * gauss_space_coeff); |
| 259 | + space_ofs[maxk++] = (int)(i * pad_step + j * cn); |
| 260 | + } |
| 261 | + } |
| 262 | + |
| 263 | + bilateralFilterProcess(dst_data, dst_step, pad_data, pad_step, width, height, cn, radius, maxk, space_ofs, space_weight, color_weight); |
| 264 | + |
| 265 | + return CV_HAL_ERROR_OK; |
| 266 | +} |
| 267 | + |
| 268 | +} // namespace ndsrvp |
| 269 | + |
| 270 | +} // namespace cv |
0 commit comments