Skip to content

Commit bf7ab8e

Browse files
committed
feat: medianBlur & bilateralFilter
1 parent dd08328 commit bf7ab8e

File tree

4 files changed

+590
-2
lines changed

4 files changed

+590
-2
lines changed

3rdparty/ndsrvp/include/imgproc.hpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,24 @@ int filterFree(cvhalFilter2D *context);
101101
#undef cv_hal_filterFree
102102
#define cv_hal_filterFree (cv::ndsrvp::filterFree)
103103

104+
// ################ medianBlur ################
105+
106+
int medianBlur(const uchar* src_data, size_t src_step,
107+
uchar* dst_data, size_t dst_step,
108+
int width, int height, int depth, int cn, int ksize);
109+
110+
#undef cv_hal_medianBlur
111+
#define cv_hal_medianBlur (cv::ndsrvp::medianBlur)
112+
113+
// ################ bilateralFilter ################
114+
115+
int bilateralFilter(const uchar* src_data, size_t src_step,
116+
uchar* dst_data, size_t dst_step, int width, int height, int depth,
117+
int cn, int d, double sigma_color, double sigma_space, int border_type);
118+
119+
#undef cv_hal_bilateralFilter
120+
#define cv_hal_bilateralFilter (cv::ndsrvp::bilateralFilter)
121+
104122
} // namespace ndsrvp
105123

106124
} // namespace cv
Lines changed: 270 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,270 @@
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

3rdparty/ndsrvp/src/filter.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ int filter(cvhalFilter2D *context,
132132
// ROI fully used in the computation
133133
int cal_width = width + ctx->kernel_width - 1;
134134
int cal_height = height + ctx->kernel_height - 1;
135-
int cal_x = offset_x - ctx->anchor_x;
136-
int cal_y = offset_y - ctx->anchor_y;
135+
int cal_x = offset_x - ctx->anchor_x; // negative if left border exceeded
136+
int cal_y = offset_y - ctx->anchor_y; // negative if top border exceeded
137137

138138
// calculate source border
139139
ctx->padding.resize(cal_width * cal_height * cnes);

0 commit comments

Comments
 (0)