imagecore 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +24 -0
- data/Gemfile +4 -0
- data/Rakefile +2 -0
- data/ext/imagecore/analyze_image.cxx +58 -0
- data/ext/imagecore/analyze_image.h +6 -0
- data/ext/imagecore/extconf.rb +9 -0
- data/ext/imagecore/imagecore.cxx +34 -0
- data/ext/opencv/core/___.c +3 -0
- data/ext/opencv/core/alloc.cpp +697 -0
- data/ext/opencv/core/array.cpp +3206 -0
- data/ext/opencv/core/datastructs.cpp +4064 -0
- data/ext/opencv/core/extconf.rb +22 -0
- data/ext/opencv/core/matrix.cpp +3777 -0
- data/ext/opencv/core/precomp.hpp +216 -0
- data/ext/opencv/core/system.cpp +832 -0
- data/ext/opencv/core/tables.cpp +3512 -0
- data/ext/opencv/highgui/___.c +3 -0
- data/ext/opencv/highgui/bitstrm.cpp +582 -0
- data/ext/opencv/highgui/bitstrm.hpp +182 -0
- data/ext/opencv/highgui/extconf.rb +28 -0
- data/ext/opencv/highgui/grfmt_base.cpp +128 -0
- data/ext/opencv/highgui/grfmt_base.hpp +113 -0
- data/ext/opencv/highgui/grfmt_bmp.cpp +564 -0
- data/ext/opencv/highgui/grfmt_bmp.hpp +99 -0
- data/ext/opencv/highgui/grfmt_exr.hpp +113 -0
- data/ext/opencv/highgui/grfmt_imageio.hpp +56 -0
- data/ext/opencv/highgui/grfmt_jpeg.cpp +622 -0
- data/ext/opencv/highgui/grfmt_jpeg.hpp +90 -0
- data/ext/opencv/highgui/grfmt_jpeg2000.cpp +529 -0
- data/ext/opencv/highgui/grfmt_jpeg2000.hpp +95 -0
- data/ext/opencv/highgui/grfmt_png.cpp +406 -0
- data/ext/opencv/highgui/grfmt_png.hpp +101 -0
- data/ext/opencv/highgui/grfmt_pxm.cpp +513 -0
- data/ext/opencv/highgui/grfmt_pxm.hpp +92 -0
- data/ext/opencv/highgui/grfmt_sunras.cpp +425 -0
- data/ext/opencv/highgui/grfmt_sunras.hpp +105 -0
- data/ext/opencv/highgui/grfmt_tiff.cpp +718 -0
- data/ext/opencv/highgui/grfmt_tiff.hpp +136 -0
- data/ext/opencv/highgui/grfmts.hpp +56 -0
- data/ext/opencv/highgui/loadsave.cpp +535 -0
- data/ext/opencv/highgui/precomp.hpp +223 -0
- data/ext/opencv/highgui/utils.cpp +689 -0
- data/ext/opencv/highgui/utils.hpp +128 -0
- data/ext/opencv/imgproc/___.c +3 -0
- data/ext/opencv/imgproc/_geom.h +72 -0
- data/ext/opencv/imgproc/color.cpp +3179 -0
- data/ext/opencv/imgproc/contours.cpp +1780 -0
- data/ext/opencv/imgproc/extconf.rb +11 -0
- data/ext/opencv/imgproc/filter.cpp +3063 -0
- data/ext/opencv/imgproc/precomp.hpp +159 -0
- data/ext/opencv/imgproc/shapedescr.cpp +1306 -0
- data/ext/opencv/imgproc/smooth.cpp +1566 -0
- data/ext/opencv/imgproc/tables.cpp +214 -0
- data/ext/opencv/imgproc/thresh.cpp +636 -0
- data/ext/opencv/imgproc/utils.cpp +242 -0
- data/ext/opencv/include/opencv2/core/core.hpp +4344 -0
- data/ext/opencv/include/opencv2/core/core_c.h +1885 -0
- data/ext/opencv/include/opencv2/core/internal.hpp +710 -0
- data/ext/opencv/include/opencv2/core/mat.hpp +2557 -0
- data/ext/opencv/include/opencv2/core/operations.hpp +3623 -0
- data/ext/opencv/include/opencv2/core/types_c.h +1875 -0
- data/ext/opencv/include/opencv2/core/version.hpp +58 -0
- data/ext/opencv/include/opencv2/highgui/highgui.hpp +198 -0
- data/ext/opencv/include/opencv2/highgui/highgui_c.h +506 -0
- data/ext/opencv/include/opencv2/imgproc/imgproc.hpp +1139 -0
- data/ext/opencv/include/opencv2/imgproc/imgproc_c.h +783 -0
- data/ext/opencv/include/opencv2/imgproc/types_c.h +538 -0
- data/imagecore.gemspec +20 -0
- data/lib/imagecore.rb +16 -0
- data/lib/imagecore/version.rb +3 -0
- metadata +119 -0
@@ -0,0 +1,1566 @@
|
|
1
|
+
/*M///////////////////////////////////////////////////////////////////////////////////////
|
2
|
+
//
|
3
|
+
// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
|
4
|
+
//
|
5
|
+
// By downloading, copying, installing or using the software you agree to this license.
|
6
|
+
// If you do not agree to this license, do not download, install,
|
7
|
+
// copy or use the software.
|
8
|
+
//
|
9
|
+
//
|
10
|
+
// License Agreement
|
11
|
+
// For Open Source Computer Vision Library
|
12
|
+
//
|
13
|
+
// Copyright (C) 2000-2008, Intel Corporation, all rights reserved.
|
14
|
+
// Copyright (C) 2009, Willow Garage Inc., all rights reserved.
|
15
|
+
// Third party copyrights are property of their respective owners.
|
16
|
+
//
|
17
|
+
// Redistribution and use in source and binary forms, with or without modification,
|
18
|
+
// are permitted provided that the following conditions are met:
|
19
|
+
//
|
20
|
+
// * Redistribution's of source code must retain the above copyright notice,
|
21
|
+
// this list of conditions and the following disclaimer.
|
22
|
+
//
|
23
|
+
// * Redistribution's in binary form must reproduce the above copyright notice,
|
24
|
+
// this list of conditions and the following disclaimer in the documentation
|
25
|
+
// and/or other materials provided with the distribution.
|
26
|
+
//
|
27
|
+
// * The name of the copyright holders may not be used to endorse or promote products
|
28
|
+
// derived from this software without specific prior written permission.
|
29
|
+
//
|
30
|
+
// This software is provided by the copyright holders and contributors "as is" and
|
31
|
+
// any express or implied warranties, including, but not limited to, the implied
|
32
|
+
// warranties of merchantability and fitness for a particular purpose are disclaimed.
|
33
|
+
// In no event shall the Intel Corporation or contributors be liable for any direct,
|
34
|
+
// indirect, incidental, special, exemplary, or consequential damages
|
35
|
+
// (including, but not limited to, procurement of substitute goods or services;
|
36
|
+
// loss of use, data, or profits; or business interruption) however caused
|
37
|
+
// and on any theory of liability, whether in contract, strict liability,
|
38
|
+
// or tort (including negligence or otherwise) arising in any way out of
|
39
|
+
// the use of this software, even if advised of the possibility of such damage.
|
40
|
+
//
|
41
|
+
//M*/
|
42
|
+
|
43
|
+
#include "precomp.hpp"
|
44
|
+
|
45
|
+
/*
|
46
|
+
* This file includes the code, contributed by Simon Perreault
|
47
|
+
* (the function icvMedianBlur_8u_O1)
|
48
|
+
*
|
49
|
+
* Constant-time median filtering -- http://nomis80.org/ctmf.html
|
50
|
+
* Copyright (C) 2006 Simon Perreault
|
51
|
+
*
|
52
|
+
* Contact:
|
53
|
+
* Laboratoire de vision et systemes numeriques
|
54
|
+
* Pavillon Adrien-Pouliot
|
55
|
+
* Universite Laval
|
56
|
+
* Sainte-Foy, Quebec, Canada
|
57
|
+
* G1K 7P4
|
58
|
+
*
|
59
|
+
* perreaul@gel.ulaval.ca
|
60
|
+
*/
|
61
|
+
|
62
|
+
namespace cv
|
63
|
+
{
|
64
|
+
|
65
|
+
/****************************************************************************************\
|
66
|
+
Box Filter
|
67
|
+
\****************************************************************************************/
|
68
|
+
|
69
|
+
template<typename T, typename ST> struct RowSum : public BaseRowFilter
|
70
|
+
{
|
71
|
+
RowSum( int _ksize, int _anchor )
|
72
|
+
{
|
73
|
+
ksize = _ksize;
|
74
|
+
anchor = _anchor;
|
75
|
+
}
|
76
|
+
|
77
|
+
void operator()(const uchar* src, uchar* dst, int width, int cn)
|
78
|
+
{
|
79
|
+
const T* S = (const T*)src;
|
80
|
+
ST* D = (ST*)dst;
|
81
|
+
int i = 0, k, ksz_cn = ksize*cn;
|
82
|
+
|
83
|
+
width = (width - 1)*cn;
|
84
|
+
for( k = 0; k < cn; k++, S++, D++ )
|
85
|
+
{
|
86
|
+
ST s = 0;
|
87
|
+
for( i = 0; i < ksz_cn; i += cn )
|
88
|
+
s += S[i];
|
89
|
+
D[0] = s;
|
90
|
+
for( i = 0; i < width; i += cn )
|
91
|
+
{
|
92
|
+
s += S[i + ksz_cn] - S[i];
|
93
|
+
D[i+cn] = s;
|
94
|
+
}
|
95
|
+
}
|
96
|
+
}
|
97
|
+
};
|
98
|
+
|
99
|
+
|
100
|
+
template<typename ST, typename T> struct ColumnSum : public BaseColumnFilter
|
101
|
+
{
|
102
|
+
ColumnSum( int _ksize, int _anchor, double _scale )
|
103
|
+
{
|
104
|
+
ksize = _ksize;
|
105
|
+
anchor = _anchor;
|
106
|
+
scale = _scale;
|
107
|
+
sumCount = 0;
|
108
|
+
}
|
109
|
+
|
110
|
+
void reset() { sumCount = 0; }
|
111
|
+
|
112
|
+
void operator()(const uchar** src, uchar* dst, int dststep, int count, int width)
|
113
|
+
{
|
114
|
+
int i;
|
115
|
+
ST* SUM;
|
116
|
+
bool haveScale = scale != 1;
|
117
|
+
double _scale = scale;
|
118
|
+
|
119
|
+
if( width != (int)sum.size() )
|
120
|
+
{
|
121
|
+
sum.resize(width);
|
122
|
+
sumCount = 0;
|
123
|
+
}
|
124
|
+
|
125
|
+
SUM = &sum[0];
|
126
|
+
if( sumCount == 0 )
|
127
|
+
{
|
128
|
+
for( i = 0; i < width; i++ )
|
129
|
+
SUM[i] = 0;
|
130
|
+
for( ; sumCount < ksize - 1; sumCount++, src++ )
|
131
|
+
{
|
132
|
+
const ST* Sp = (const ST*)src[0];
|
133
|
+
for( i = 0; i <= width - 2; i += 2 )
|
134
|
+
{
|
135
|
+
ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
|
136
|
+
SUM[i] = s0; SUM[i+1] = s1;
|
137
|
+
}
|
138
|
+
|
139
|
+
for( ; i < width; i++ )
|
140
|
+
SUM[i] += Sp[i];
|
141
|
+
}
|
142
|
+
}
|
143
|
+
else
|
144
|
+
{
|
145
|
+
CV_Assert( sumCount == ksize-1 );
|
146
|
+
src += ksize-1;
|
147
|
+
}
|
148
|
+
|
149
|
+
for( ; count--; src++ )
|
150
|
+
{
|
151
|
+
const ST* Sp = (const ST*)src[0];
|
152
|
+
const ST* Sm = (const ST*)src[1-ksize];
|
153
|
+
T* D = (T*)dst;
|
154
|
+
if( haveScale )
|
155
|
+
{
|
156
|
+
for( i = 0; i <= width - 2; i += 2 )
|
157
|
+
{
|
158
|
+
ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
|
159
|
+
D[i] = saturate_cast<T>(s0*_scale);
|
160
|
+
D[i+1] = saturate_cast<T>(s1*_scale);
|
161
|
+
s0 -= Sm[i]; s1 -= Sm[i+1];
|
162
|
+
SUM[i] = s0; SUM[i+1] = s1;
|
163
|
+
}
|
164
|
+
|
165
|
+
for( ; i < width; i++ )
|
166
|
+
{
|
167
|
+
ST s0 = SUM[i] + Sp[i];
|
168
|
+
D[i] = saturate_cast<T>(s0*_scale);
|
169
|
+
SUM[i] = s0 - Sm[i];
|
170
|
+
}
|
171
|
+
}
|
172
|
+
else
|
173
|
+
{
|
174
|
+
for( i = 0; i <= width - 2; i += 2 )
|
175
|
+
{
|
176
|
+
ST s0 = SUM[i] + Sp[i], s1 = SUM[i+1] + Sp[i+1];
|
177
|
+
D[i] = saturate_cast<T>(s0);
|
178
|
+
D[i+1] = saturate_cast<T>(s1);
|
179
|
+
s0 -= Sm[i]; s1 -= Sm[i+1];
|
180
|
+
SUM[i] = s0; SUM[i+1] = s1;
|
181
|
+
}
|
182
|
+
|
183
|
+
for( ; i < width; i++ )
|
184
|
+
{
|
185
|
+
ST s0 = SUM[i] + Sp[i];
|
186
|
+
D[i] = saturate_cast<T>(s0);
|
187
|
+
SUM[i] = s0 - Sm[i];
|
188
|
+
}
|
189
|
+
}
|
190
|
+
dst += dststep;
|
191
|
+
}
|
192
|
+
}
|
193
|
+
|
194
|
+
double scale;
|
195
|
+
int sumCount;
|
196
|
+
vector<ST> sum;
|
197
|
+
};
|
198
|
+
|
199
|
+
|
200
|
+
}
|
201
|
+
|
202
|
+
cv::Ptr<cv::BaseRowFilter> cv::getRowSumFilter(int srcType, int sumType, int ksize, int anchor)
|
203
|
+
{
|
204
|
+
int sdepth = CV_MAT_DEPTH(srcType), ddepth = CV_MAT_DEPTH(sumType);
|
205
|
+
CV_Assert( CV_MAT_CN(sumType) == CV_MAT_CN(srcType) );
|
206
|
+
|
207
|
+
if( anchor < 0 )
|
208
|
+
anchor = ksize/2;
|
209
|
+
|
210
|
+
if( sdepth == CV_8U && ddepth == CV_32S )
|
211
|
+
return Ptr<BaseRowFilter>(new RowSum<uchar, int>(ksize, anchor));
|
212
|
+
if( sdepth == CV_8U && ddepth == CV_64F )
|
213
|
+
return Ptr<BaseRowFilter>(new RowSum<uchar, double>(ksize, anchor));
|
214
|
+
if( sdepth == CV_16U && ddepth == CV_32S )
|
215
|
+
return Ptr<BaseRowFilter>(new RowSum<ushort, int>(ksize, anchor));
|
216
|
+
if( sdepth == CV_16U && ddepth == CV_64F )
|
217
|
+
return Ptr<BaseRowFilter>(new RowSum<ushort, double>(ksize, anchor));
|
218
|
+
if( sdepth == CV_16S && ddepth == CV_32S )
|
219
|
+
return Ptr<BaseRowFilter>(new RowSum<short, int>(ksize, anchor));
|
220
|
+
if( sdepth == CV_32S && ddepth == CV_32S )
|
221
|
+
return Ptr<BaseRowFilter>(new RowSum<int, int>(ksize, anchor));
|
222
|
+
if( sdepth == CV_16S && ddepth == CV_64F )
|
223
|
+
return Ptr<BaseRowFilter>(new RowSum<short, double>(ksize, anchor));
|
224
|
+
if( sdepth == CV_32F && ddepth == CV_64F )
|
225
|
+
return Ptr<BaseRowFilter>(new RowSum<float, double>(ksize, anchor));
|
226
|
+
if( sdepth == CV_64F && ddepth == CV_64F )
|
227
|
+
return Ptr<BaseRowFilter>(new RowSum<double, double>(ksize, anchor));
|
228
|
+
|
229
|
+
CV_Error_( CV_StsNotImplemented,
|
230
|
+
("Unsupported combination of source format (=%d), and buffer format (=%d)",
|
231
|
+
srcType, sumType));
|
232
|
+
|
233
|
+
return Ptr<BaseRowFilter>(0);
|
234
|
+
}
|
235
|
+
|
236
|
+
|
237
|
+
cv::Ptr<cv::BaseColumnFilter> cv::getColumnSumFilter(int sumType, int dstType, int ksize,
|
238
|
+
int anchor, double scale)
|
239
|
+
{
|
240
|
+
int sdepth = CV_MAT_DEPTH(sumType), ddepth = CV_MAT_DEPTH(dstType);
|
241
|
+
CV_Assert( CV_MAT_CN(sumType) == CV_MAT_CN(dstType) );
|
242
|
+
|
243
|
+
if( anchor < 0 )
|
244
|
+
anchor = ksize/2;
|
245
|
+
|
246
|
+
if( ddepth == CV_8U && sdepth == CV_32S )
|
247
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, uchar>(ksize, anchor, scale));
|
248
|
+
if( ddepth == CV_8U && sdepth == CV_64F )
|
249
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<double, uchar>(ksize, anchor, scale));
|
250
|
+
if( ddepth == CV_16U && sdepth == CV_32S )
|
251
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, ushort>(ksize, anchor, scale));
|
252
|
+
if( ddepth == CV_16U && sdepth == CV_64F )
|
253
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<double, ushort>(ksize, anchor, scale));
|
254
|
+
if( ddepth == CV_16S && sdepth == CV_32S )
|
255
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, short>(ksize, anchor, scale));
|
256
|
+
if( ddepth == CV_16S && sdepth == CV_64F )
|
257
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<double, short>(ksize, anchor, scale));
|
258
|
+
if( ddepth == CV_32S && sdepth == CV_32S )
|
259
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, int>(ksize, anchor, scale));
|
260
|
+
if( ddepth == CV_32F && sdepth == CV_32S )
|
261
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, float>(ksize, anchor, scale));
|
262
|
+
if( ddepth == CV_32F && sdepth == CV_64F )
|
263
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<double, float>(ksize, anchor, scale));
|
264
|
+
if( ddepth == CV_64F && sdepth == CV_32S )
|
265
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<int, double>(ksize, anchor, scale));
|
266
|
+
if( ddepth == CV_64F && sdepth == CV_64F )
|
267
|
+
return Ptr<BaseColumnFilter>(new ColumnSum<double, double>(ksize, anchor, scale));
|
268
|
+
|
269
|
+
CV_Error_( CV_StsNotImplemented,
|
270
|
+
("Unsupported combination of sum format (=%d), and destination format (=%d)",
|
271
|
+
sumType, dstType));
|
272
|
+
|
273
|
+
return Ptr<BaseColumnFilter>(0);
|
274
|
+
}
|
275
|
+
|
276
|
+
|
277
|
+
cv::Ptr<cv::FilterEngine> cv::createBoxFilter( int srcType, int dstType, Size ksize,
|
278
|
+
Point anchor, bool normalize, int borderType )
|
279
|
+
{
|
280
|
+
int sdepth = CV_MAT_DEPTH(srcType);
|
281
|
+
int cn = CV_MAT_CN(srcType), sumType = CV_64F;
|
282
|
+
if( sdepth < CV_32S && (!normalize ||
|
283
|
+
ksize.width*ksize.height <= (sdepth == CV_8U ? (1<<23) :
|
284
|
+
sdepth == CV_16U ? (1 << 15) : (1 << 16))) )
|
285
|
+
sumType = CV_32S;
|
286
|
+
sumType = CV_MAKETYPE( sumType, cn );
|
287
|
+
|
288
|
+
Ptr<BaseRowFilter> rowFilter = getRowSumFilter(srcType, sumType, ksize.width, anchor.x );
|
289
|
+
Ptr<BaseColumnFilter> columnFilter = getColumnSumFilter(sumType,
|
290
|
+
dstType, ksize.height, anchor.y, normalize ? 1./(ksize.width*ksize.height) : 1);
|
291
|
+
|
292
|
+
return Ptr<FilterEngine>(new FilterEngine(Ptr<BaseFilter>(0), rowFilter, columnFilter,
|
293
|
+
srcType, dstType, sumType, borderType ));
|
294
|
+
}
|
295
|
+
|
296
|
+
|
297
|
+
void cv::boxFilter( InputArray _src, OutputArray _dst, int ddepth,
|
298
|
+
Size ksize, Point anchor,
|
299
|
+
bool normalize, int borderType )
|
300
|
+
{
|
301
|
+
Mat src = _src.getMat();
|
302
|
+
int sdepth = src.depth(), cn = src.channels();
|
303
|
+
if( ddepth < 0 )
|
304
|
+
ddepth = sdepth;
|
305
|
+
_dst.create( src.size(), CV_MAKETYPE(ddepth, cn) );
|
306
|
+
Mat dst = _dst.getMat();
|
307
|
+
if( borderType != BORDER_CONSTANT && normalize )
|
308
|
+
{
|
309
|
+
if( src.rows == 1 )
|
310
|
+
ksize.height = 1;
|
311
|
+
if( src.cols == 1 )
|
312
|
+
ksize.width = 1;
|
313
|
+
}
|
314
|
+
Ptr<FilterEngine> f = createBoxFilter( src.type(), dst.type(),
|
315
|
+
ksize, anchor, normalize, borderType );
|
316
|
+
f->apply( src, dst );
|
317
|
+
}
|
318
|
+
|
319
|
+
void cv::blur( InputArray src, OutputArray dst,
|
320
|
+
Size ksize, Point anchor, int borderType )
|
321
|
+
{
|
322
|
+
boxFilter( src, dst, -1, ksize, anchor, true, borderType );
|
323
|
+
}
|
324
|
+
|
325
|
+
/****************************************************************************************\
|
326
|
+
Gaussian Blur
|
327
|
+
\****************************************************************************************/
|
328
|
+
|
329
|
+
cv::Mat cv::getGaussianKernel( int n, double sigma, int ktype )
|
330
|
+
{
|
331
|
+
const int SMALL_GAUSSIAN_SIZE = 7;
|
332
|
+
static const float small_gaussian_tab[][SMALL_GAUSSIAN_SIZE] =
|
333
|
+
{
|
334
|
+
{1.f},
|
335
|
+
{0.25f, 0.5f, 0.25f},
|
336
|
+
{0.0625f, 0.25f, 0.375f, 0.25f, 0.0625f},
|
337
|
+
{0.03125f, 0.109375f, 0.21875f, 0.28125f, 0.21875f, 0.109375f, 0.03125f}
|
338
|
+
};
|
339
|
+
|
340
|
+
const float* fixed_kernel = n % 2 == 1 && n <= SMALL_GAUSSIAN_SIZE && sigma <= 0 ?
|
341
|
+
small_gaussian_tab[n>>1] : 0;
|
342
|
+
|
343
|
+
CV_Assert( ktype == CV_32F || ktype == CV_64F );
|
344
|
+
Mat kernel(n, 1, ktype);
|
345
|
+
float* cf = (float*)kernel.data;
|
346
|
+
double* cd = (double*)kernel.data;
|
347
|
+
|
348
|
+
double sigmaX = sigma > 0 ? sigma : ((n-1)*0.5 - 1)*0.3 + 0.8;
|
349
|
+
double scale2X = -0.5/(sigmaX*sigmaX);
|
350
|
+
double sum = 0;
|
351
|
+
|
352
|
+
int i;
|
353
|
+
for( i = 0; i < n; i++ )
|
354
|
+
{
|
355
|
+
double x = i - (n-1)*0.5;
|
356
|
+
double t = fixed_kernel ? (double)fixed_kernel[i] : std::exp(scale2X*x*x);
|
357
|
+
if( ktype == CV_32F )
|
358
|
+
{
|
359
|
+
cf[i] = (float)t;
|
360
|
+
sum += cf[i];
|
361
|
+
}
|
362
|
+
else
|
363
|
+
{
|
364
|
+
cd[i] = t;
|
365
|
+
sum += cd[i];
|
366
|
+
}
|
367
|
+
}
|
368
|
+
|
369
|
+
sum = 1./sum;
|
370
|
+
for( i = 0; i < n; i++ )
|
371
|
+
{
|
372
|
+
if( ktype == CV_32F )
|
373
|
+
cf[i] = (float)(cf[i]*sum);
|
374
|
+
else
|
375
|
+
cd[i] *= sum;
|
376
|
+
}
|
377
|
+
|
378
|
+
return kernel;
|
379
|
+
}
|
380
|
+
|
381
|
+
|
382
|
+
cv::Ptr<cv::FilterEngine> cv::createGaussianFilter( int type, Size ksize,
|
383
|
+
double sigma1, double sigma2,
|
384
|
+
int borderType )
|
385
|
+
{
|
386
|
+
int depth = CV_MAT_DEPTH(type);
|
387
|
+
if( sigma2 <= 0 )
|
388
|
+
sigma2 = sigma1;
|
389
|
+
|
390
|
+
// automatic detection of kernel size from sigma
|
391
|
+
if( ksize.width <= 0 && sigma1 > 0 )
|
392
|
+
ksize.width = cvRound(sigma1*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
|
393
|
+
if( ksize.height <= 0 && sigma2 > 0 )
|
394
|
+
ksize.height = cvRound(sigma2*(depth == CV_8U ? 3 : 4)*2 + 1)|1;
|
395
|
+
|
396
|
+
CV_Assert( ksize.width > 0 && ksize.width % 2 == 1 &&
|
397
|
+
ksize.height > 0 && ksize.height % 2 == 1 );
|
398
|
+
|
399
|
+
sigma1 = std::max( sigma1, 0. );
|
400
|
+
sigma2 = std::max( sigma2, 0. );
|
401
|
+
|
402
|
+
Mat kx = getGaussianKernel( ksize.width, sigma1, std::max(depth, CV_32F) );
|
403
|
+
Mat ky;
|
404
|
+
if( ksize.height == ksize.width && std::abs(sigma1 - sigma2) < DBL_EPSILON )
|
405
|
+
ky = kx;
|
406
|
+
else
|
407
|
+
ky = getGaussianKernel( ksize.height, sigma2, std::max(depth, CV_32F) );
|
408
|
+
|
409
|
+
return createSeparableLinearFilter( type, type, kx, ky, Point(-1,-1), 0, borderType );
|
410
|
+
}
|
411
|
+
|
412
|
+
|
413
|
+
void cv::GaussianBlur( InputArray _src, OutputArray _dst, Size ksize,
|
414
|
+
double sigma1, double sigma2,
|
415
|
+
int borderType )
|
416
|
+
{
|
417
|
+
Mat src = _src.getMat();
|
418
|
+
_dst.create( src.size(), src.type() );
|
419
|
+
Mat dst = _dst.getMat();
|
420
|
+
|
421
|
+
if( ksize.width == 1 && ksize.height == 1 )
|
422
|
+
{
|
423
|
+
src.copyTo(dst);
|
424
|
+
return;
|
425
|
+
}
|
426
|
+
|
427
|
+
if( borderType != BORDER_CONSTANT )
|
428
|
+
{
|
429
|
+
if( src.rows == 1 )
|
430
|
+
ksize.height = 1;
|
431
|
+
if( src.cols == 1 )
|
432
|
+
ksize.width = 1;
|
433
|
+
}
|
434
|
+
Ptr<FilterEngine> f = createGaussianFilter( src.type(), ksize, sigma1, sigma2, borderType );
|
435
|
+
f->apply( src, dst );
|
436
|
+
}
|
437
|
+
|
438
|
+
|
439
|
+
/****************************************************************************************\
|
440
|
+
Median Filter
|
441
|
+
\****************************************************************************************/
|
442
|
+
|
443
|
+
namespace cv
|
444
|
+
{
|
445
|
+
|
446
|
+
#if _MSC_VER >= 1200
|
447
|
+
#pragma warning( disable: 4244 )
|
448
|
+
#endif
|
449
|
+
|
450
|
+
typedef ushort HT;
|
451
|
+
|
452
|
+
/**
|
453
|
+
* This structure represents a two-tier histogram. The first tier (known as the
|
454
|
+
* "coarse" level) is 4 bit wide and the second tier (known as the "fine" level)
|
455
|
+
* is 8 bit wide. Pixels inserted in the fine level also get inserted into the
|
456
|
+
* coarse bucket designated by the 4 MSBs of the fine bucket value.
|
457
|
+
*
|
458
|
+
* The structure is aligned on 16 bits, which is a prerequisite for SIMD
|
459
|
+
* instructions. Each bucket is 16 bit wide, which means that extra care must be
|
460
|
+
* taken to prevent overflow.
|
461
|
+
*/
|
462
|
+
typedef struct
|
463
|
+
{
|
464
|
+
HT coarse[16];
|
465
|
+
HT fine[16][16];
|
466
|
+
} Histogram;
|
467
|
+
|
468
|
+
|
469
|
+
#if CV_SSE2
|
470
|
+
#define MEDIAN_HAVE_SIMD 1
|
471
|
+
|
472
|
+
static inline void histogram_add_simd( const HT x[16], HT y[16] )
|
473
|
+
{
|
474
|
+
const __m128i* rx = (const __m128i*)x;
|
475
|
+
__m128i* ry = (__m128i*)y;
|
476
|
+
__m128i r0 = _mm_add_epi16(_mm_load_si128(ry+0),_mm_load_si128(rx+0));
|
477
|
+
__m128i r1 = _mm_add_epi16(_mm_load_si128(ry+1),_mm_load_si128(rx+1));
|
478
|
+
_mm_store_si128(ry+0, r0);
|
479
|
+
_mm_store_si128(ry+1, r1);
|
480
|
+
}
|
481
|
+
|
482
|
+
static inline void histogram_sub_simd( const HT x[16], HT y[16] )
|
483
|
+
{
|
484
|
+
const __m128i* rx = (const __m128i*)x;
|
485
|
+
__m128i* ry = (__m128i*)y;
|
486
|
+
__m128i r0 = _mm_sub_epi16(_mm_load_si128(ry+0),_mm_load_si128(rx+0));
|
487
|
+
__m128i r1 = _mm_sub_epi16(_mm_load_si128(ry+1),_mm_load_si128(rx+1));
|
488
|
+
_mm_store_si128(ry+0, r0);
|
489
|
+
_mm_store_si128(ry+1, r1);
|
490
|
+
}
|
491
|
+
|
492
|
+
#else
|
493
|
+
#define MEDIAN_HAVE_SIMD 0
|
494
|
+
#endif
|
495
|
+
|
496
|
+
|
497
|
+
static inline void histogram_add( const HT x[16], HT y[16] )
|
498
|
+
{
|
499
|
+
int i;
|
500
|
+
for( i = 0; i < 16; ++i )
|
501
|
+
y[i] = (HT)(y[i] + x[i]);
|
502
|
+
}
|
503
|
+
|
504
|
+
static inline void histogram_sub( const HT x[16], HT y[16] )
|
505
|
+
{
|
506
|
+
int i;
|
507
|
+
for( i = 0; i < 16; ++i )
|
508
|
+
y[i] = (HT)(y[i] - x[i]);
|
509
|
+
}
|
510
|
+
|
511
|
+
static inline void histogram_muladd( int a, const HT x[16],
|
512
|
+
HT y[16] )
|
513
|
+
{
|
514
|
+
for( int i = 0; i < 16; ++i )
|
515
|
+
y[i] = (HT)(y[i] + a * x[i]);
|
516
|
+
}
|
517
|
+
|
518
|
+
static void
|
519
|
+
medianBlur_8u_O1( const Mat& _src, Mat& _dst, int ksize )
|
520
|
+
{
|
521
|
+
/**
|
522
|
+
* HOP is short for Histogram OPeration. This macro makes an operation \a op on
|
523
|
+
* histogram \a h for pixel value \a x. It takes care of handling both levels.
|
524
|
+
*/
|
525
|
+
#define HOP(h,x,op) \
|
526
|
+
h.coarse[x>>4] op, \
|
527
|
+
*((HT*)h.fine + x) op
|
528
|
+
|
529
|
+
#define COP(c,j,x,op) \
|
530
|
+
h_coarse[ 16*(n*c+j) + (x>>4) ] op, \
|
531
|
+
h_fine[ 16 * (n*(16*c+(x>>4)) + j) + (x & 0xF) ] op
|
532
|
+
|
533
|
+
int cn = _dst.channels(), m = _dst.rows, r = (ksize-1)/2;
|
534
|
+
size_t sstep = _src.step, dstep = _dst.step;
|
535
|
+
Histogram CV_DECL_ALIGNED(16) H[4];
|
536
|
+
HT CV_DECL_ALIGNED(16) luc[4][16];
|
537
|
+
|
538
|
+
int STRIPE_SIZE = std::min( _dst.cols, 512/cn );
|
539
|
+
|
540
|
+
vector<HT> _h_coarse(1 * 16 * (STRIPE_SIZE + 2*r) * cn + 16);
|
541
|
+
vector<HT> _h_fine(16 * 16 * (STRIPE_SIZE + 2*r) * cn + 16);
|
542
|
+
HT* h_coarse = alignPtr(&_h_coarse[0], 16);
|
543
|
+
HT* h_fine = alignPtr(&_h_fine[0], 16);
|
544
|
+
#if MEDIAN_HAVE_SIMD
|
545
|
+
volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
|
546
|
+
#endif
|
547
|
+
|
548
|
+
for( int x = 0; x < _dst.cols; x += STRIPE_SIZE )
|
549
|
+
{
|
550
|
+
int i, j, k, c, n = std::min(_dst.cols - x, STRIPE_SIZE) + r*2;
|
551
|
+
const uchar* src = _src.data + x*cn;
|
552
|
+
uchar* dst = _dst.data + (x - r)*cn;
|
553
|
+
|
554
|
+
memset( h_coarse, 0, 16*n*cn*sizeof(h_coarse[0]) );
|
555
|
+
memset( h_fine, 0, 16*16*n*cn*sizeof(h_fine[0]) );
|
556
|
+
|
557
|
+
// First row initialization
|
558
|
+
for( c = 0; c < cn; c++ )
|
559
|
+
{
|
560
|
+
for( j = 0; j < n; j++ )
|
561
|
+
COP( c, j, src[cn*j+c], += r+2 );
|
562
|
+
|
563
|
+
for( i = 1; i < r; i++ )
|
564
|
+
{
|
565
|
+
const uchar* p = src + sstep*std::min(i, m-1);
|
566
|
+
for ( j = 0; j < n; j++ )
|
567
|
+
COP( c, j, p[cn*j+c], ++ );
|
568
|
+
}
|
569
|
+
}
|
570
|
+
|
571
|
+
for( i = 0; i < m; i++ )
|
572
|
+
{
|
573
|
+
const uchar* p0 = src + sstep * std::max( 0, i-r-1 );
|
574
|
+
const uchar* p1 = src + sstep * std::min( m-1, i+r );
|
575
|
+
|
576
|
+
memset( H, 0, cn*sizeof(H[0]) );
|
577
|
+
memset( luc, 0, cn*sizeof(luc[0]) );
|
578
|
+
for( c = 0; c < cn; c++ )
|
579
|
+
{
|
580
|
+
// Update column histograms for the entire row.
|
581
|
+
for( j = 0; j < n; j++ )
|
582
|
+
{
|
583
|
+
COP( c, j, p0[j*cn + c], -- );
|
584
|
+
COP( c, j, p1[j*cn + c], ++ );
|
585
|
+
}
|
586
|
+
|
587
|
+
// First column initialization
|
588
|
+
for( k = 0; k < 16; ++k )
|
589
|
+
histogram_muladd( 2*r+1, &h_fine[16*n*(16*c+k)], &H[c].fine[k][0] );
|
590
|
+
|
591
|
+
#if MEDIAN_HAVE_SIMD
|
592
|
+
if( useSIMD )
|
593
|
+
{
|
594
|
+
for( j = 0; j < 2*r; ++j )
|
595
|
+
histogram_add_simd( &h_coarse[16*(n*c+j)], H[c].coarse );
|
596
|
+
|
597
|
+
for( j = r; j < n-r; j++ )
|
598
|
+
{
|
599
|
+
int t = 2*r*r + 2*r, b, sum = 0;
|
600
|
+
HT* segment;
|
601
|
+
|
602
|
+
histogram_add_simd( &h_coarse[16*(n*c + std::min(j+r,n-1))], H[c].coarse );
|
603
|
+
|
604
|
+
// Find median at coarse level
|
605
|
+
for ( k = 0; k < 16 ; ++k )
|
606
|
+
{
|
607
|
+
sum += H[c].coarse[k];
|
608
|
+
if ( sum > t )
|
609
|
+
{
|
610
|
+
sum -= H[c].coarse[k];
|
611
|
+
break;
|
612
|
+
}
|
613
|
+
}
|
614
|
+
assert( k < 16 );
|
615
|
+
|
616
|
+
/* Update corresponding histogram segment */
|
617
|
+
if ( luc[c][k] <= j-r )
|
618
|
+
{
|
619
|
+
memset( &H[c].fine[k], 0, 16 * sizeof(HT) );
|
620
|
+
for ( luc[c][k] = j-r; luc[c][k] < MIN(j+r+1,n); ++luc[c][k] )
|
621
|
+
histogram_add_simd( &h_fine[16*(n*(16*c+k)+luc[c][k])], H[c].fine[k] );
|
622
|
+
|
623
|
+
if ( luc[c][k] < j+r+1 )
|
624
|
+
{
|
625
|
+
histogram_muladd( j+r+1 - n, &h_fine[16*(n*(16*c+k)+(n-1))], &H[c].fine[k][0] );
|
626
|
+
luc[c][k] = (HT)(j+r+1);
|
627
|
+
}
|
628
|
+
}
|
629
|
+
else
|
630
|
+
{
|
631
|
+
for ( ; luc[c][k] < j+r+1; ++luc[c][k] )
|
632
|
+
{
|
633
|
+
histogram_sub_simd( &h_fine[16*(n*(16*c+k)+MAX(luc[c][k]-2*r-1,0))], H[c].fine[k] );
|
634
|
+
histogram_add_simd( &h_fine[16*(n*(16*c+k)+MIN(luc[c][k],n-1))], H[c].fine[k] );
|
635
|
+
}
|
636
|
+
}
|
637
|
+
|
638
|
+
histogram_sub_simd( &h_coarse[16*(n*c+MAX(j-r,0))], H[c].coarse );
|
639
|
+
|
640
|
+
/* Find median in segment */
|
641
|
+
segment = H[c].fine[k];
|
642
|
+
for ( b = 0; b < 16 ; b++ )
|
643
|
+
{
|
644
|
+
sum += segment[b];
|
645
|
+
if ( sum > t )
|
646
|
+
{
|
647
|
+
dst[dstep*i+cn*j+c] = (uchar)(16*k + b);
|
648
|
+
break;
|
649
|
+
}
|
650
|
+
}
|
651
|
+
assert( b < 16 );
|
652
|
+
}
|
653
|
+
}
|
654
|
+
else
|
655
|
+
#endif
|
656
|
+
{
|
657
|
+
for( j = 0; j < 2*r; ++j )
|
658
|
+
histogram_add( &h_coarse[16*(n*c+j)], H[c].coarse );
|
659
|
+
|
660
|
+
for( j = r; j < n-r; j++ )
|
661
|
+
{
|
662
|
+
int t = 2*r*r + 2*r, b, sum = 0;
|
663
|
+
HT* segment;
|
664
|
+
|
665
|
+
histogram_add( &h_coarse[16*(n*c + std::min(j+r,n-1))], H[c].coarse );
|
666
|
+
|
667
|
+
// Find median at coarse level
|
668
|
+
for ( k = 0; k < 16 ; ++k )
|
669
|
+
{
|
670
|
+
sum += H[c].coarse[k];
|
671
|
+
if ( sum > t )
|
672
|
+
{
|
673
|
+
sum -= H[c].coarse[k];
|
674
|
+
break;
|
675
|
+
}
|
676
|
+
}
|
677
|
+
assert( k < 16 );
|
678
|
+
|
679
|
+
/* Update corresponding histogram segment */
|
680
|
+
if ( luc[c][k] <= j-r )
|
681
|
+
{
|
682
|
+
memset( &H[c].fine[k], 0, 16 * sizeof(HT) );
|
683
|
+
for ( luc[c][k] = j-r; luc[c][k] < MIN(j+r+1,n); ++luc[c][k] )
|
684
|
+
histogram_add( &h_fine[16*(n*(16*c+k)+luc[c][k])], H[c].fine[k] );
|
685
|
+
|
686
|
+
if ( luc[c][k] < j+r+1 )
|
687
|
+
{
|
688
|
+
histogram_muladd( j+r+1 - n, &h_fine[16*(n*(16*c+k)+(n-1))], &H[c].fine[k][0] );
|
689
|
+
luc[c][k] = (HT)(j+r+1);
|
690
|
+
}
|
691
|
+
}
|
692
|
+
else
|
693
|
+
{
|
694
|
+
for ( ; luc[c][k] < j+r+1; ++luc[c][k] )
|
695
|
+
{
|
696
|
+
histogram_sub( &h_fine[16*(n*(16*c+k)+MAX(luc[c][k]-2*r-1,0))], H[c].fine[k] );
|
697
|
+
histogram_add( &h_fine[16*(n*(16*c+k)+MIN(luc[c][k],n-1))], H[c].fine[k] );
|
698
|
+
}
|
699
|
+
}
|
700
|
+
|
701
|
+
histogram_sub( &h_coarse[16*(n*c+MAX(j-r,0))], H[c].coarse );
|
702
|
+
|
703
|
+
/* Find median in segment */
|
704
|
+
segment = H[c].fine[k];
|
705
|
+
for ( b = 0; b < 16 ; b++ )
|
706
|
+
{
|
707
|
+
sum += segment[b];
|
708
|
+
if ( sum > t )
|
709
|
+
{
|
710
|
+
dst[dstep*i+cn*j+c] = (uchar)(16*k + b);
|
711
|
+
break;
|
712
|
+
}
|
713
|
+
}
|
714
|
+
assert( b < 16 );
|
715
|
+
}
|
716
|
+
}
|
717
|
+
}
|
718
|
+
}
|
719
|
+
}
|
720
|
+
|
721
|
+
#undef HOP
|
722
|
+
#undef COP
|
723
|
+
}
|
724
|
+
|
725
|
+
|
726
|
+
#if _MSC_VER >= 1200
|
727
|
+
#pragma warning( default: 4244 )
|
728
|
+
#endif
|
729
|
+
|
730
|
+
static void
|
731
|
+
medianBlur_8u_Om( const Mat& _src, Mat& _dst, int m )
|
732
|
+
{
|
733
|
+
#define N 16
|
734
|
+
int zone0[4][N];
|
735
|
+
int zone1[4][N*N];
|
736
|
+
int x, y;
|
737
|
+
int n2 = m*m/2;
|
738
|
+
Size size = _dst.size();
|
739
|
+
const uchar* src = _src.data;
|
740
|
+
uchar* dst = _dst.data;
|
741
|
+
int src_step = (int)_src.step, dst_step = (int)_dst.step;
|
742
|
+
int cn = _src.channels();
|
743
|
+
const uchar* src_max = src + size.height*src_step;
|
744
|
+
|
745
|
+
#define UPDATE_ACC01( pix, cn, op ) \
|
746
|
+
{ \
|
747
|
+
int p = (pix); \
|
748
|
+
zone1[cn][p] op; \
|
749
|
+
zone0[cn][p >> 4] op; \
|
750
|
+
}
|
751
|
+
|
752
|
+
//CV_Assert( size.height >= nx && size.width >= nx );
|
753
|
+
for( x = 0; x < size.width; x++, src += cn, dst += cn )
|
754
|
+
{
|
755
|
+
uchar* dst_cur = dst;
|
756
|
+
const uchar* src_top = src;
|
757
|
+
const uchar* src_bottom = src;
|
758
|
+
int k, c;
|
759
|
+
int src_step1 = src_step, dst_step1 = dst_step;
|
760
|
+
|
761
|
+
if( x % 2 != 0 )
|
762
|
+
{
|
763
|
+
src_bottom = src_top += src_step*(size.height-1);
|
764
|
+
dst_cur += dst_step*(size.height-1);
|
765
|
+
src_step1 = -src_step1;
|
766
|
+
dst_step1 = -dst_step1;
|
767
|
+
}
|
768
|
+
|
769
|
+
// init accumulator
|
770
|
+
memset( zone0, 0, sizeof(zone0[0])*cn );
|
771
|
+
memset( zone1, 0, sizeof(zone1[0])*cn );
|
772
|
+
|
773
|
+
for( y = 0; y <= m/2; y++ )
|
774
|
+
{
|
775
|
+
for( c = 0; c < cn; c++ )
|
776
|
+
{
|
777
|
+
if( y > 0 )
|
778
|
+
{
|
779
|
+
for( k = 0; k < m*cn; k += cn )
|
780
|
+
UPDATE_ACC01( src_bottom[k+c], c, ++ );
|
781
|
+
}
|
782
|
+
else
|
783
|
+
{
|
784
|
+
for( k = 0; k < m*cn; k += cn )
|
785
|
+
UPDATE_ACC01( src_bottom[k+c], c, += m/2+1 );
|
786
|
+
}
|
787
|
+
}
|
788
|
+
|
789
|
+
if( (src_step1 > 0 && y < size.height-1) ||
|
790
|
+
(src_step1 < 0 && size.height-y-1 > 0) )
|
791
|
+
src_bottom += src_step1;
|
792
|
+
}
|
793
|
+
|
794
|
+
for( y = 0; y < size.height; y++, dst_cur += dst_step1 )
|
795
|
+
{
|
796
|
+
// find median
|
797
|
+
for( c = 0; c < cn; c++ )
|
798
|
+
{
|
799
|
+
int s = 0;
|
800
|
+
for( k = 0; ; k++ )
|
801
|
+
{
|
802
|
+
int t = s + zone0[c][k];
|
803
|
+
if( t > n2 ) break;
|
804
|
+
s = t;
|
805
|
+
}
|
806
|
+
|
807
|
+
for( k *= N; ;k++ )
|
808
|
+
{
|
809
|
+
s += zone1[c][k];
|
810
|
+
if( s > n2 ) break;
|
811
|
+
}
|
812
|
+
|
813
|
+
dst_cur[c] = (uchar)k;
|
814
|
+
}
|
815
|
+
|
816
|
+
if( y+1 == size.height )
|
817
|
+
break;
|
818
|
+
|
819
|
+
if( cn == 1 )
|
820
|
+
{
|
821
|
+
for( k = 0; k < m; k++ )
|
822
|
+
{
|
823
|
+
int p = src_top[k];
|
824
|
+
int q = src_bottom[k];
|
825
|
+
zone1[0][p]--;
|
826
|
+
zone0[0][p>>4]--;
|
827
|
+
zone1[0][q]++;
|
828
|
+
zone0[0][q>>4]++;
|
829
|
+
}
|
830
|
+
}
|
831
|
+
else if( cn == 3 )
|
832
|
+
{
|
833
|
+
for( k = 0; k < m*3; k += 3 )
|
834
|
+
{
|
835
|
+
UPDATE_ACC01( src_top[k], 0, -- );
|
836
|
+
UPDATE_ACC01( src_top[k+1], 1, -- );
|
837
|
+
UPDATE_ACC01( src_top[k+2], 2, -- );
|
838
|
+
|
839
|
+
UPDATE_ACC01( src_bottom[k], 0, ++ );
|
840
|
+
UPDATE_ACC01( src_bottom[k+1], 1, ++ );
|
841
|
+
UPDATE_ACC01( src_bottom[k+2], 2, ++ );
|
842
|
+
}
|
843
|
+
}
|
844
|
+
else
|
845
|
+
{
|
846
|
+
assert( cn == 4 );
|
847
|
+
for( k = 0; k < m*4; k += 4 )
|
848
|
+
{
|
849
|
+
UPDATE_ACC01( src_top[k], 0, -- );
|
850
|
+
UPDATE_ACC01( src_top[k+1], 1, -- );
|
851
|
+
UPDATE_ACC01( src_top[k+2], 2, -- );
|
852
|
+
UPDATE_ACC01( src_top[k+3], 3, -- );
|
853
|
+
|
854
|
+
UPDATE_ACC01( src_bottom[k], 0, ++ );
|
855
|
+
UPDATE_ACC01( src_bottom[k+1], 1, ++ );
|
856
|
+
UPDATE_ACC01( src_bottom[k+2], 2, ++ );
|
857
|
+
UPDATE_ACC01( src_bottom[k+3], 3, ++ );
|
858
|
+
}
|
859
|
+
}
|
860
|
+
|
861
|
+
if( (src_step1 > 0 && src_bottom + src_step1 < src_max) ||
|
862
|
+
(src_step1 < 0 && src_bottom + src_step1 >= src) )
|
863
|
+
src_bottom += src_step1;
|
864
|
+
|
865
|
+
if( y >= m/2 )
|
866
|
+
src_top += src_step1;
|
867
|
+
}
|
868
|
+
}
|
869
|
+
#undef N
|
870
|
+
#undef UPDATE_ACC
|
871
|
+
}
|
872
|
+
|
873
|
+
|
874
|
+
struct MinMax8u
|
875
|
+
{
|
876
|
+
typedef uchar value_type;
|
877
|
+
typedef int arg_type;
|
878
|
+
enum { SIZE = 1 };
|
879
|
+
arg_type load(const uchar* ptr) { return *ptr; }
|
880
|
+
void store(uchar* ptr, arg_type val) { *ptr = (uchar)val; }
|
881
|
+
void operator()(arg_type& a, arg_type& b) const
|
882
|
+
{
|
883
|
+
int t = CV_FAST_CAST_8U(a - b);
|
884
|
+
b += t; a -= t;
|
885
|
+
}
|
886
|
+
};
|
887
|
+
|
888
|
+
struct MinMax16u
|
889
|
+
{
|
890
|
+
typedef ushort value_type;
|
891
|
+
typedef int arg_type;
|
892
|
+
enum { SIZE = 1 };
|
893
|
+
arg_type load(const ushort* ptr) { return *ptr; }
|
894
|
+
void store(ushort* ptr, arg_type val) { *ptr = (ushort)val; }
|
895
|
+
void operator()(arg_type& a, arg_type& b) const
|
896
|
+
{
|
897
|
+
arg_type t = a;
|
898
|
+
a = std::min(a, b);
|
899
|
+
b = std::max(b, t);
|
900
|
+
}
|
901
|
+
};
|
902
|
+
|
903
|
+
struct MinMax16s
|
904
|
+
{
|
905
|
+
typedef short value_type;
|
906
|
+
typedef int arg_type;
|
907
|
+
enum { SIZE = 1 };
|
908
|
+
arg_type load(const short* ptr) { return *ptr; }
|
909
|
+
void store(short* ptr, arg_type val) { *ptr = (short)val; }
|
910
|
+
void operator()(arg_type& a, arg_type& b) const
|
911
|
+
{
|
912
|
+
arg_type t = a;
|
913
|
+
a = std::min(a, b);
|
914
|
+
b = std::max(b, t);
|
915
|
+
}
|
916
|
+
};
|
917
|
+
|
918
|
+
struct MinMax32f
|
919
|
+
{
|
920
|
+
typedef float value_type;
|
921
|
+
typedef float arg_type;
|
922
|
+
enum { SIZE = 1 };
|
923
|
+
arg_type load(const float* ptr) { return *ptr; }
|
924
|
+
void store(float* ptr, arg_type val) { *ptr = val; }
|
925
|
+
void operator()(arg_type& a, arg_type& b) const
|
926
|
+
{
|
927
|
+
arg_type t = a;
|
928
|
+
a = std::min(a, b);
|
929
|
+
b = std::max(b, t);
|
930
|
+
}
|
931
|
+
};
|
932
|
+
|
933
|
+
#if CV_SSE2
|
934
|
+
|
935
|
+
struct MinMaxVec8u
|
936
|
+
{
|
937
|
+
typedef uchar value_type;
|
938
|
+
typedef __m128i arg_type;
|
939
|
+
enum { SIZE = 16 };
|
940
|
+
arg_type load(const uchar* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
|
941
|
+
void store(uchar* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); }
|
942
|
+
void operator()(arg_type& a, arg_type& b) const
|
943
|
+
{
|
944
|
+
arg_type t = a;
|
945
|
+
a = _mm_min_epu8(a, b);
|
946
|
+
b = _mm_max_epu8(b, t);
|
947
|
+
}
|
948
|
+
};
|
949
|
+
|
950
|
+
|
951
|
+
struct MinMaxVec16u
|
952
|
+
{
|
953
|
+
typedef ushort value_type;
|
954
|
+
typedef __m128i arg_type;
|
955
|
+
enum { SIZE = 8 };
|
956
|
+
arg_type load(const ushort* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
|
957
|
+
void store(ushort* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); }
|
958
|
+
void operator()(arg_type& a, arg_type& b) const
|
959
|
+
{
|
960
|
+
arg_type t = _mm_subs_epu16(a, b);
|
961
|
+
a = _mm_subs_epu16(a, t);
|
962
|
+
b = _mm_adds_epu16(b, t);
|
963
|
+
}
|
964
|
+
};
|
965
|
+
|
966
|
+
|
967
|
+
struct MinMaxVec16s
|
968
|
+
{
|
969
|
+
typedef short value_type;
|
970
|
+
typedef __m128i arg_type;
|
971
|
+
enum { SIZE = 8 };
|
972
|
+
arg_type load(const short* ptr) { return _mm_loadu_si128((const __m128i*)ptr); }
|
973
|
+
void store(short* ptr, arg_type val) { _mm_storeu_si128((__m128i*)ptr, val); }
|
974
|
+
void operator()(arg_type& a, arg_type& b) const
|
975
|
+
{
|
976
|
+
arg_type t = a;
|
977
|
+
a = _mm_min_epi16(a, b);
|
978
|
+
b = _mm_max_epi16(b, t);
|
979
|
+
}
|
980
|
+
};
|
981
|
+
|
982
|
+
|
983
|
+
struct MinMaxVec32f
|
984
|
+
{
|
985
|
+
typedef float value_type;
|
986
|
+
typedef __m128 arg_type;
|
987
|
+
enum { SIZE = 4 };
|
988
|
+
arg_type load(const float* ptr) { return _mm_loadu_ps(ptr); }
|
989
|
+
void store(float* ptr, arg_type val) { _mm_storeu_ps(ptr, val); }
|
990
|
+
void operator()(arg_type& a, arg_type& b) const
|
991
|
+
{
|
992
|
+
arg_type t = a;
|
993
|
+
a = _mm_min_ps(a, b);
|
994
|
+
b = _mm_max_ps(b, t);
|
995
|
+
}
|
996
|
+
};
|
997
|
+
|
998
|
+
|
999
|
+
#else
|
1000
|
+
|
1001
|
+
typedef MinMax8u MinMaxVec8u;
|
1002
|
+
typedef MinMax16u MinMaxVec16u;
|
1003
|
+
typedef MinMax16s MinMaxVec16s;
|
1004
|
+
typedef MinMax32f MinMaxVec32f;
|
1005
|
+
|
1006
|
+
#endif
|
1007
|
+
|
1008
|
+
template<class Op, class VecOp>
|
1009
|
+
static void
|
1010
|
+
medianBlur_SortNet( const Mat& _src, Mat& _dst, int m )
|
1011
|
+
{
|
1012
|
+
typedef typename Op::value_type T;
|
1013
|
+
typedef typename Op::arg_type WT;
|
1014
|
+
typedef typename VecOp::arg_type VT;
|
1015
|
+
|
1016
|
+
const T* src = (const T*)_src.data;
|
1017
|
+
T* dst = (T*)_dst.data;
|
1018
|
+
int sstep = (int)(_src.step/sizeof(T));
|
1019
|
+
int dstep = (int)(_dst.step/sizeof(T));
|
1020
|
+
Size size = _dst.size();
|
1021
|
+
int i, j, k, cn = _src.channels();
|
1022
|
+
Op op;
|
1023
|
+
VecOp vop;
|
1024
|
+
volatile bool useSIMD = checkHardwareSupport(CV_CPU_SSE2);
|
1025
|
+
|
1026
|
+
if( m == 3 )
|
1027
|
+
{
|
1028
|
+
if( size.width == 1 || size.height == 1 )
|
1029
|
+
{
|
1030
|
+
int len = size.width + size.height - 1;
|
1031
|
+
int sdelta = size.height == 1 ? cn : sstep;
|
1032
|
+
int sdelta0 = size.height == 1 ? 0 : sstep - cn;
|
1033
|
+
int ddelta = size.height == 1 ? cn : dstep;
|
1034
|
+
|
1035
|
+
for( i = 0; i < len; i++, src += sdelta0, dst += ddelta )
|
1036
|
+
for( j = 0; j < cn; j++, src++ )
|
1037
|
+
{
|
1038
|
+
WT p0 = src[i > 0 ? -sdelta : 0];
|
1039
|
+
WT p1 = src[0];
|
1040
|
+
WT p2 = src[i < len - 1 ? sdelta : 0];
|
1041
|
+
|
1042
|
+
op(p0, p1); op(p1, p2); op(p0, p1);
|
1043
|
+
dst[j] = (T)p1;
|
1044
|
+
}
|
1045
|
+
return;
|
1046
|
+
}
|
1047
|
+
|
1048
|
+
size.width *= cn;
|
1049
|
+
for( i = 0; i < size.height; i++, dst += dstep )
|
1050
|
+
{
|
1051
|
+
const T* row0 = src + std::max(i - 1, 0)*sstep;
|
1052
|
+
const T* row1 = src + i*sstep;
|
1053
|
+
const T* row2 = src + std::min(i + 1, size.height-1)*sstep;
|
1054
|
+
int limit = useSIMD ? cn : size.width;
|
1055
|
+
|
1056
|
+
for(j = 0;; )
|
1057
|
+
{
|
1058
|
+
for( ; j < limit; j++ )
|
1059
|
+
{
|
1060
|
+
int j0 = j >= cn ? j - cn : j;
|
1061
|
+
int j2 = j < size.width - cn ? j + cn : j;
|
1062
|
+
WT p0 = row0[j0], p1 = row0[j], p2 = row0[j2];
|
1063
|
+
WT p3 = row1[j0], p4 = row1[j], p5 = row1[j2];
|
1064
|
+
WT p6 = row2[j0], p7 = row2[j], p8 = row2[j2];
|
1065
|
+
|
1066
|
+
op(p1, p2); op(p4, p5); op(p7, p8); op(p0, p1);
|
1067
|
+
op(p3, p4); op(p6, p7); op(p1, p2); op(p4, p5);
|
1068
|
+
op(p7, p8); op(p0, p3); op(p5, p8); op(p4, p7);
|
1069
|
+
op(p3, p6); op(p1, p4); op(p2, p5); op(p4, p7);
|
1070
|
+
op(p4, p2); op(p6, p4); op(p4, p2);
|
1071
|
+
dst[j] = (T)p4;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
if( limit == size.width )
|
1075
|
+
break;
|
1076
|
+
|
1077
|
+
for( ; j <= size.width - VecOp::SIZE - cn; j += VecOp::SIZE )
|
1078
|
+
{
|
1079
|
+
VT p0 = vop.load(row0+j-cn), p1 = vop.load(row0+j), p2 = vop.load(row0+j+cn);
|
1080
|
+
VT p3 = vop.load(row1+j-cn), p4 = vop.load(row1+j), p5 = vop.load(row1+j+cn);
|
1081
|
+
VT p6 = vop.load(row2+j-cn), p7 = vop.load(row2+j), p8 = vop.load(row2+j+cn);
|
1082
|
+
|
1083
|
+
vop(p1, p2); vop(p4, p5); vop(p7, p8); vop(p0, p1);
|
1084
|
+
vop(p3, p4); vop(p6, p7); vop(p1, p2); vop(p4, p5);
|
1085
|
+
vop(p7, p8); vop(p0, p3); vop(p5, p8); vop(p4, p7);
|
1086
|
+
vop(p3, p6); vop(p1, p4); vop(p2, p5); vop(p4, p7);
|
1087
|
+
vop(p4, p2); vop(p6, p4); vop(p4, p2);
|
1088
|
+
vop.store(dst+j, p4);
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
limit = size.width;
|
1092
|
+
}
|
1093
|
+
}
|
1094
|
+
}
|
1095
|
+
else if( m == 5 )
|
1096
|
+
{
|
1097
|
+
if( size.width == 1 || size.height == 1 )
|
1098
|
+
{
|
1099
|
+
int len = size.width + size.height - 1;
|
1100
|
+
int sdelta = size.height == 1 ? cn : sstep;
|
1101
|
+
int sdelta0 = size.height == 1 ? 0 : sstep - cn;
|
1102
|
+
int ddelta = size.height == 1 ? cn : dstep;
|
1103
|
+
|
1104
|
+
for( i = 0; i < len; i++, src += sdelta0, dst += ddelta )
|
1105
|
+
for( j = 0; j < cn; j++, src++ )
|
1106
|
+
{
|
1107
|
+
int i1 = i > 0 ? -sdelta : 0;
|
1108
|
+
int i0 = i > 1 ? -sdelta*2 : i1;
|
1109
|
+
int i3 = i < len-1 ? sdelta : 0;
|
1110
|
+
int i4 = i < len-2 ? sdelta*2 : i3;
|
1111
|
+
WT p0 = src[i0], p1 = src[i1], p2 = src[0], p3 = src[i3], p4 = src[i4];
|
1112
|
+
|
1113
|
+
op(p0, p1); op(p3, p4); op(p2, p3); op(p3, p4); op(p0, p2);
|
1114
|
+
op(p2, p4); op(p1, p3); op(p1, p2);
|
1115
|
+
dst[j] = (T)p2;
|
1116
|
+
}
|
1117
|
+
return;
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
size.width *= cn;
|
1121
|
+
for( i = 0; i < size.height; i++, dst += dstep )
|
1122
|
+
{
|
1123
|
+
const T* row[5];
|
1124
|
+
row[0] = src + std::max(i - 2, 0)*sstep;
|
1125
|
+
row[1] = src + std::max(i - 1, 0)*sstep;
|
1126
|
+
row[2] = src + i*sstep;
|
1127
|
+
row[3] = src + std::min(i + 1, size.height-1)*sstep;
|
1128
|
+
row[4] = src + std::min(i + 2, size.height-1)*sstep;
|
1129
|
+
int limit = useSIMD ? cn*2 : size.width;
|
1130
|
+
|
1131
|
+
for(j = 0;; )
|
1132
|
+
{
|
1133
|
+
for( ; j < limit; j++ )
|
1134
|
+
{
|
1135
|
+
WT p[25];
|
1136
|
+
int j1 = j >= cn ? j - cn : j;
|
1137
|
+
int j0 = j >= cn*2 ? j - cn*2 : j1;
|
1138
|
+
int j3 = j < size.width - cn ? j + cn : j;
|
1139
|
+
int j4 = j < size.width - cn*2 ? j + cn*2 : j3;
|
1140
|
+
for( k = 0; k < 5; k++ )
|
1141
|
+
{
|
1142
|
+
const T* rowk = row[k];
|
1143
|
+
p[k*5] = rowk[j0]; p[k*5+1] = rowk[j1];
|
1144
|
+
p[k*5+2] = rowk[j]; p[k*5+3] = rowk[j3];
|
1145
|
+
p[k*5+4] = rowk[j4];
|
1146
|
+
}
|
1147
|
+
|
1148
|
+
op(p[1], p[2]); op(p[0], p[1]); op(p[1], p[2]); op(p[4], p[5]); op(p[3], p[4]);
|
1149
|
+
op(p[4], p[5]); op(p[0], p[3]); op(p[2], p[5]); op(p[2], p[3]); op(p[1], p[4]);
|
1150
|
+
op(p[1], p[2]); op(p[3], p[4]); op(p[7], p[8]); op(p[6], p[7]); op(p[7], p[8]);
|
1151
|
+
op(p[10], p[11]); op(p[9], p[10]); op(p[10], p[11]); op(p[6], p[9]); op(p[8], p[11]);
|
1152
|
+
op(p[8], p[9]); op(p[7], p[10]); op(p[7], p[8]); op(p[9], p[10]); op(p[0], p[6]);
|
1153
|
+
op(p[4], p[10]); op(p[4], p[6]); op(p[2], p[8]); op(p[2], p[4]); op(p[6], p[8]);
|
1154
|
+
op(p[1], p[7]); op(p[5], p[11]); op(p[5], p[7]); op(p[3], p[9]); op(p[3], p[5]);
|
1155
|
+
op(p[7], p[9]); op(p[1], p[2]); op(p[3], p[4]); op(p[5], p[6]); op(p[7], p[8]);
|
1156
|
+
op(p[9], p[10]); op(p[13], p[14]); op(p[12], p[13]); op(p[13], p[14]); op(p[16], p[17]);
|
1157
|
+
op(p[15], p[16]); op(p[16], p[17]); op(p[12], p[15]); op(p[14], p[17]); op(p[14], p[15]);
|
1158
|
+
op(p[13], p[16]); op(p[13], p[14]); op(p[15], p[16]); op(p[19], p[20]); op(p[18], p[19]);
|
1159
|
+
op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[21], p[23]); op(p[22], p[24]);
|
1160
|
+
op(p[22], p[23]); op(p[18], p[21]); op(p[20], p[23]); op(p[20], p[21]); op(p[19], p[22]);
|
1161
|
+
op(p[22], p[24]); op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[12], p[18]);
|
1162
|
+
op(p[16], p[22]); op(p[16], p[18]); op(p[14], p[20]); op(p[20], p[24]); op(p[14], p[16]);
|
1163
|
+
op(p[18], p[20]); op(p[22], p[24]); op(p[13], p[19]); op(p[17], p[23]); op(p[17], p[19]);
|
1164
|
+
op(p[15], p[21]); op(p[15], p[17]); op(p[19], p[21]); op(p[13], p[14]); op(p[15], p[16]);
|
1165
|
+
op(p[17], p[18]); op(p[19], p[20]); op(p[21], p[22]); op(p[23], p[24]); op(p[0], p[12]);
|
1166
|
+
op(p[8], p[20]); op(p[8], p[12]); op(p[4], p[16]); op(p[16], p[24]); op(p[12], p[16]);
|
1167
|
+
op(p[2], p[14]); op(p[10], p[22]); op(p[10], p[14]); op(p[6], p[18]); op(p[6], p[10]);
|
1168
|
+
op(p[10], p[12]); op(p[1], p[13]); op(p[9], p[21]); op(p[9], p[13]); op(p[5], p[17]);
|
1169
|
+
op(p[13], p[17]); op(p[3], p[15]); op(p[11], p[23]); op(p[11], p[15]); op(p[7], p[19]);
|
1170
|
+
op(p[7], p[11]); op(p[11], p[13]); op(p[11], p[12]);
|
1171
|
+
dst[j] = (T)p[12];
|
1172
|
+
}
|
1173
|
+
|
1174
|
+
if( limit == size.width )
|
1175
|
+
break;
|
1176
|
+
|
1177
|
+
for( ; j <= size.width - VecOp::SIZE - cn*2; j += VecOp::SIZE )
|
1178
|
+
{
|
1179
|
+
VT p[25];
|
1180
|
+
for( k = 0; k < 5; k++ )
|
1181
|
+
{
|
1182
|
+
const T* rowk = row[k];
|
1183
|
+
p[k*5] = vop.load(rowk+j-cn*2); p[k*5+1] = vop.load(rowk+j-cn);
|
1184
|
+
p[k*5+2] = vop.load(rowk+j); p[k*5+3] = vop.load(rowk+j+cn);
|
1185
|
+
p[k*5+4] = vop.load(rowk+j+cn*2);
|
1186
|
+
}
|
1187
|
+
|
1188
|
+
vop(p[1], p[2]); vop(p[0], p[1]); vop(p[1], p[2]); vop(p[4], p[5]); vop(p[3], p[4]);
|
1189
|
+
vop(p[4], p[5]); vop(p[0], p[3]); vop(p[2], p[5]); vop(p[2], p[3]); vop(p[1], p[4]);
|
1190
|
+
vop(p[1], p[2]); vop(p[3], p[4]); vop(p[7], p[8]); vop(p[6], p[7]); vop(p[7], p[8]);
|
1191
|
+
vop(p[10], p[11]); vop(p[9], p[10]); vop(p[10], p[11]); vop(p[6], p[9]); vop(p[8], p[11]);
|
1192
|
+
vop(p[8], p[9]); vop(p[7], p[10]); vop(p[7], p[8]); vop(p[9], p[10]); vop(p[0], p[6]);
|
1193
|
+
vop(p[4], p[10]); vop(p[4], p[6]); vop(p[2], p[8]); vop(p[2], p[4]); vop(p[6], p[8]);
|
1194
|
+
vop(p[1], p[7]); vop(p[5], p[11]); vop(p[5], p[7]); vop(p[3], p[9]); vop(p[3], p[5]);
|
1195
|
+
vop(p[7], p[9]); vop(p[1], p[2]); vop(p[3], p[4]); vop(p[5], p[6]); vop(p[7], p[8]);
|
1196
|
+
vop(p[9], p[10]); vop(p[13], p[14]); vop(p[12], p[13]); vop(p[13], p[14]); vop(p[16], p[17]);
|
1197
|
+
vop(p[15], p[16]); vop(p[16], p[17]); vop(p[12], p[15]); vop(p[14], p[17]); vop(p[14], p[15]);
|
1198
|
+
vop(p[13], p[16]); vop(p[13], p[14]); vop(p[15], p[16]); vop(p[19], p[20]); vop(p[18], p[19]);
|
1199
|
+
vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[21], p[23]); vop(p[22], p[24]);
|
1200
|
+
vop(p[22], p[23]); vop(p[18], p[21]); vop(p[20], p[23]); vop(p[20], p[21]); vop(p[19], p[22]);
|
1201
|
+
vop(p[22], p[24]); vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[12], p[18]);
|
1202
|
+
vop(p[16], p[22]); vop(p[16], p[18]); vop(p[14], p[20]); vop(p[20], p[24]); vop(p[14], p[16]);
|
1203
|
+
vop(p[18], p[20]); vop(p[22], p[24]); vop(p[13], p[19]); vop(p[17], p[23]); vop(p[17], p[19]);
|
1204
|
+
vop(p[15], p[21]); vop(p[15], p[17]); vop(p[19], p[21]); vop(p[13], p[14]); vop(p[15], p[16]);
|
1205
|
+
vop(p[17], p[18]); vop(p[19], p[20]); vop(p[21], p[22]); vop(p[23], p[24]); vop(p[0], p[12]);
|
1206
|
+
vop(p[8], p[20]); vop(p[8], p[12]); vop(p[4], p[16]); vop(p[16], p[24]); vop(p[12], p[16]);
|
1207
|
+
vop(p[2], p[14]); vop(p[10], p[22]); vop(p[10], p[14]); vop(p[6], p[18]); vop(p[6], p[10]);
|
1208
|
+
vop(p[10], p[12]); vop(p[1], p[13]); vop(p[9], p[21]); vop(p[9], p[13]); vop(p[5], p[17]);
|
1209
|
+
vop(p[13], p[17]); vop(p[3], p[15]); vop(p[11], p[23]); vop(p[11], p[15]); vop(p[7], p[19]);
|
1210
|
+
vop(p[7], p[11]); vop(p[11], p[13]); vop(p[11], p[12]);
|
1211
|
+
vop.store(dst+j, p[12]);
|
1212
|
+
}
|
1213
|
+
|
1214
|
+
limit = size.width;
|
1215
|
+
}
|
1216
|
+
}
|
1217
|
+
}
|
1218
|
+
}
|
1219
|
+
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
void cv::medianBlur( InputArray _src0, OutputArray _dst, int ksize )
|
1223
|
+
{
|
1224
|
+
Mat src0 = _src0.getMat();
|
1225
|
+
_dst.create( src0.size(), src0.type() );
|
1226
|
+
Mat dst = _dst.getMat();
|
1227
|
+
|
1228
|
+
if( ksize <= 1 )
|
1229
|
+
{
|
1230
|
+
src0.copyTo(dst);
|
1231
|
+
return;
|
1232
|
+
}
|
1233
|
+
|
1234
|
+
CV_Assert( ksize % 2 == 1 );
|
1235
|
+
|
1236
|
+
Size size = src0.size();
|
1237
|
+
int cn = src0.channels();
|
1238
|
+
bool useSortNet = ksize == 3 || (ksize == 5
|
1239
|
+
#if !CV_SSE2
|
1240
|
+
&& src0.depth() > CV_8U
|
1241
|
+
#endif
|
1242
|
+
);
|
1243
|
+
|
1244
|
+
Mat src;
|
1245
|
+
if( useSortNet )
|
1246
|
+
{
|
1247
|
+
if( dst.data != src0.data )
|
1248
|
+
src = src0;
|
1249
|
+
else
|
1250
|
+
src0.copyTo(src);
|
1251
|
+
}
|
1252
|
+
else
|
1253
|
+
cv::copyMakeBorder( src0, src, 0, 0, ksize/2, ksize/2, BORDER_REPLICATE );
|
1254
|
+
|
1255
|
+
if( useSortNet )
|
1256
|
+
{
|
1257
|
+
if( src.depth() == CV_8U )
|
1258
|
+
medianBlur_SortNet<MinMax8u, MinMaxVec8u>( src, dst, ksize );
|
1259
|
+
else if( src.depth() == CV_16U )
|
1260
|
+
medianBlur_SortNet<MinMax16u, MinMaxVec16u>( src, dst, ksize );
|
1261
|
+
else if( src.depth() == CV_16S )
|
1262
|
+
medianBlur_SortNet<MinMax16s, MinMaxVec16s>( src, dst, ksize );
|
1263
|
+
else if( src.depth() == CV_32F )
|
1264
|
+
medianBlur_SortNet<MinMax32f, MinMaxVec32f>( src, dst, ksize );
|
1265
|
+
else
|
1266
|
+
CV_Error(CV_StsUnsupportedFormat, "");
|
1267
|
+
return;
|
1268
|
+
}
|
1269
|
+
|
1270
|
+
CV_Assert( src.depth() == CV_8U && (cn == 1 || cn == 3 || cn == 4) );
|
1271
|
+
|
1272
|
+
double img_size_mp = (double)(size.width*size.height)/(1 << 20);
|
1273
|
+
if( ksize <= 3 + (img_size_mp < 1 ? 12 : img_size_mp < 4 ? 6 : 2)*(MEDIAN_HAVE_SIMD && checkHardwareSupport(CV_CPU_SSE2) ? 1 : 3))
|
1274
|
+
medianBlur_8u_Om( src, dst, ksize );
|
1275
|
+
else
|
1276
|
+
medianBlur_8u_O1( src, dst, ksize );
|
1277
|
+
}
|
1278
|
+
|
1279
|
+
/****************************************************************************************\
|
1280
|
+
Bilateral Filtering
|
1281
|
+
\****************************************************************************************/
|
1282
|
+
|
1283
|
+
namespace cv
|
1284
|
+
{
|
1285
|
+
|
1286
|
+
static void
|
1287
|
+
bilateralFilter_8u( const Mat& src, Mat& dst, int d,
|
1288
|
+
double sigma_color, double sigma_space,
|
1289
|
+
int borderType )
|
1290
|
+
{
|
1291
|
+
int cn = src.channels();
|
1292
|
+
int i, j, k, maxk, radius;
|
1293
|
+
Size size = src.size();
|
1294
|
+
|
1295
|
+
CV_Assert( (src.type() == CV_8UC1 || src.type() == CV_8UC3) &&
|
1296
|
+
src.type() == dst.type() && src.size() == dst.size() &&
|
1297
|
+
src.data != dst.data );
|
1298
|
+
|
1299
|
+
if( sigma_color <= 0 )
|
1300
|
+
sigma_color = 1;
|
1301
|
+
if( sigma_space <= 0 )
|
1302
|
+
sigma_space = 1;
|
1303
|
+
|
1304
|
+
double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
|
1305
|
+
double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
|
1306
|
+
|
1307
|
+
if( d <= 0 )
|
1308
|
+
radius = cvRound(sigma_space*1.5);
|
1309
|
+
else
|
1310
|
+
radius = d/2;
|
1311
|
+
radius = MAX(radius, 1);
|
1312
|
+
d = radius*2 + 1;
|
1313
|
+
|
1314
|
+
Mat temp;
|
1315
|
+
copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );
|
1316
|
+
|
1317
|
+
vector<float> _color_weight(cn*256);
|
1318
|
+
vector<float> _space_weight(d*d);
|
1319
|
+
vector<int> _space_ofs(d*d);
|
1320
|
+
float* color_weight = &_color_weight[0];
|
1321
|
+
float* space_weight = &_space_weight[0];
|
1322
|
+
int* space_ofs = &_space_ofs[0];
|
1323
|
+
|
1324
|
+
// initialize color-related bilateral filter coefficients
|
1325
|
+
for( i = 0; i < 256*cn; i++ )
|
1326
|
+
color_weight[i] = (float)std::exp(i*i*gauss_color_coeff);
|
1327
|
+
|
1328
|
+
// initialize space-related bilateral filter coefficients
|
1329
|
+
for( i = -radius, maxk = 0; i <= radius; i++ )
|
1330
|
+
for( j = -radius; j <= radius; j++ )
|
1331
|
+
{
|
1332
|
+
double r = std::sqrt((double)i*i + (double)j*j);
|
1333
|
+
if( r > radius )
|
1334
|
+
continue;
|
1335
|
+
space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff);
|
1336
|
+
space_ofs[maxk++] = (int)(i*temp.step + j*cn);
|
1337
|
+
}
|
1338
|
+
|
1339
|
+
for( i = 0; i < size.height; i++ )
|
1340
|
+
{
|
1341
|
+
const uchar* sptr = temp.data + (i+radius)*temp.step + radius*cn;
|
1342
|
+
uchar* dptr = dst.data + i*dst.step;
|
1343
|
+
|
1344
|
+
if( cn == 1 )
|
1345
|
+
{
|
1346
|
+
for( j = 0; j < size.width; j++ )
|
1347
|
+
{
|
1348
|
+
float sum = 0, wsum = 0;
|
1349
|
+
int val0 = sptr[j];
|
1350
|
+
for( k = 0; k < maxk; k++ )
|
1351
|
+
{
|
1352
|
+
int val = sptr[j + space_ofs[k]];
|
1353
|
+
float w = space_weight[k]*color_weight[std::abs(val - val0)];
|
1354
|
+
sum += val*w;
|
1355
|
+
wsum += w;
|
1356
|
+
}
|
1357
|
+
// overflow is not possible here => there is no need to use CV_CAST_8U
|
1358
|
+
dptr[j] = (uchar)cvRound(sum/wsum);
|
1359
|
+
}
|
1360
|
+
}
|
1361
|
+
else
|
1362
|
+
{
|
1363
|
+
assert( cn == 3 );
|
1364
|
+
for( j = 0; j < size.width*3; j += 3 )
|
1365
|
+
{
|
1366
|
+
float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
|
1367
|
+
int b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
|
1368
|
+
for( k = 0; k < maxk; k++ )
|
1369
|
+
{
|
1370
|
+
const uchar* sptr_k = sptr + j + space_ofs[k];
|
1371
|
+
int b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
|
1372
|
+
float w = space_weight[k]*color_weight[std::abs(b - b0) +
|
1373
|
+
std::abs(g - g0) + std::abs(r - r0)];
|
1374
|
+
sum_b += b*w; sum_g += g*w; sum_r += r*w;
|
1375
|
+
wsum += w;
|
1376
|
+
}
|
1377
|
+
wsum = 1.f/wsum;
|
1378
|
+
b0 = cvRound(sum_b*wsum);
|
1379
|
+
g0 = cvRound(sum_g*wsum);
|
1380
|
+
r0 = cvRound(sum_r*wsum);
|
1381
|
+
dptr[j] = (uchar)b0; dptr[j+1] = (uchar)g0; dptr[j+2] = (uchar)r0;
|
1382
|
+
}
|
1383
|
+
}
|
1384
|
+
}
|
1385
|
+
}
|
1386
|
+
|
1387
|
+
|
1388
|
+
static void
|
1389
|
+
bilateralFilter_32f( const Mat& src, Mat& dst, int d,
|
1390
|
+
double sigma_color, double sigma_space,
|
1391
|
+
int borderType )
|
1392
|
+
{
|
1393
|
+
int cn = src.channels();
|
1394
|
+
int i, j, k, maxk, radius;
|
1395
|
+
double minValSrc=-1, maxValSrc=1;
|
1396
|
+
const int kExpNumBinsPerChannel = 1 << 12;
|
1397
|
+
int kExpNumBins = 0;
|
1398
|
+
float lastExpVal = 1.f;
|
1399
|
+
float len, scale_index;
|
1400
|
+
Size size = src.size();
|
1401
|
+
|
1402
|
+
CV_Assert( (src.type() == CV_32FC1 || src.type() == CV_32FC3) &&
|
1403
|
+
src.type() == dst.type() && src.size() == dst.size() &&
|
1404
|
+
src.data != dst.data );
|
1405
|
+
|
1406
|
+
if( sigma_color <= 0 )
|
1407
|
+
sigma_color = 1;
|
1408
|
+
if( sigma_space <= 0 )
|
1409
|
+
sigma_space = 1;
|
1410
|
+
|
1411
|
+
double gauss_color_coeff = -0.5/(sigma_color*sigma_color);
|
1412
|
+
double gauss_space_coeff = -0.5/(sigma_space*sigma_space);
|
1413
|
+
|
1414
|
+
if( d <= 0 )
|
1415
|
+
radius = cvRound(sigma_space*1.5);
|
1416
|
+
else
|
1417
|
+
radius = d/2;
|
1418
|
+
radius = MAX(radius, 1);
|
1419
|
+
d = radius*2 + 1;
|
1420
|
+
// compute the min/max range for the input image (even if multichannel)
|
1421
|
+
|
1422
|
+
minMaxLoc( src.reshape(1), &minValSrc, &maxValSrc );
|
1423
|
+
|
1424
|
+
// temporary copy of the image with borders for easy processing
|
1425
|
+
Mat temp;
|
1426
|
+
copyMakeBorder( src, temp, radius, radius, radius, radius, borderType );
|
1427
|
+
|
1428
|
+
// allocate lookup tables
|
1429
|
+
vector<float> _space_weight(d*d);
|
1430
|
+
vector<int> _space_ofs(d*d);
|
1431
|
+
float* space_weight = &_space_weight[0];
|
1432
|
+
int* space_ofs = &_space_ofs[0];
|
1433
|
+
|
1434
|
+
// assign a length which is slightly more than needed
|
1435
|
+
len = (float)(maxValSrc - minValSrc) * cn;
|
1436
|
+
kExpNumBins = kExpNumBinsPerChannel * cn;
|
1437
|
+
vector<float> _expLUT(kExpNumBins+2);
|
1438
|
+
float* expLUT = &_expLUT[0];
|
1439
|
+
|
1440
|
+
scale_index = kExpNumBins/len;
|
1441
|
+
|
1442
|
+
// initialize the exp LUT
|
1443
|
+
for( i = 0; i < kExpNumBins+2; i++ )
|
1444
|
+
{
|
1445
|
+
if( lastExpVal > 0.f )
|
1446
|
+
{
|
1447
|
+
double val = i / scale_index;
|
1448
|
+
expLUT[i] = (float)std::exp(val * val * gauss_color_coeff);
|
1449
|
+
lastExpVal = expLUT[i];
|
1450
|
+
}
|
1451
|
+
else
|
1452
|
+
expLUT[i] = 0.f;
|
1453
|
+
}
|
1454
|
+
|
1455
|
+
// initialize space-related bilateral filter coefficients
|
1456
|
+
for( i = -radius, maxk = 0; i <= radius; i++ )
|
1457
|
+
for( j = -radius; j <= radius; j++ )
|
1458
|
+
{
|
1459
|
+
double r = std::sqrt((double)i*i + (double)j*j);
|
1460
|
+
if( r > radius )
|
1461
|
+
continue;
|
1462
|
+
space_weight[maxk] = (float)std::exp(r*r*gauss_space_coeff);
|
1463
|
+
space_ofs[maxk++] = (int)(i*(temp.step/sizeof(float)) + j*cn);
|
1464
|
+
}
|
1465
|
+
|
1466
|
+
for( i = 0; i < size.height; i++ )
|
1467
|
+
{
|
1468
|
+
const float* sptr = (const float*)(temp.data + (i+radius)*temp.step) + radius*cn;
|
1469
|
+
float* dptr = (float*)(dst.data + i*dst.step);
|
1470
|
+
|
1471
|
+
if( cn == 1 )
|
1472
|
+
{
|
1473
|
+
for( j = 0; j < size.width; j++ )
|
1474
|
+
{
|
1475
|
+
float sum = 0, wsum = 0;
|
1476
|
+
float val0 = sptr[j];
|
1477
|
+
for( k = 0; k < maxk; k++ )
|
1478
|
+
{
|
1479
|
+
float val = sptr[j + space_ofs[k]];
|
1480
|
+
float alpha = (float)(std::abs(val - val0)*scale_index);
|
1481
|
+
int idx = cvFloor(alpha);
|
1482
|
+
alpha -= idx;
|
1483
|
+
float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
|
1484
|
+
sum += val*w;
|
1485
|
+
wsum += w;
|
1486
|
+
}
|
1487
|
+
dptr[j] = (float)(sum/wsum);
|
1488
|
+
}
|
1489
|
+
}
|
1490
|
+
else
|
1491
|
+
{
|
1492
|
+
assert( cn == 3 );
|
1493
|
+
for( j = 0; j < size.width*3; j += 3 )
|
1494
|
+
{
|
1495
|
+
float sum_b = 0, sum_g = 0, sum_r = 0, wsum = 0;
|
1496
|
+
float b0 = sptr[j], g0 = sptr[j+1], r0 = sptr[j+2];
|
1497
|
+
for( k = 0; k < maxk; k++ )
|
1498
|
+
{
|
1499
|
+
const float* sptr_k = sptr + j + space_ofs[k];
|
1500
|
+
float b = sptr_k[0], g = sptr_k[1], r = sptr_k[2];
|
1501
|
+
float alpha = (float)((std::abs(b - b0) +
|
1502
|
+
std::abs(g - g0) + std::abs(r - r0))*scale_index);
|
1503
|
+
int idx = cvFloor(alpha);
|
1504
|
+
alpha -= idx;
|
1505
|
+
float w = space_weight[k]*(expLUT[idx] + alpha*(expLUT[idx+1] - expLUT[idx]));
|
1506
|
+
sum_b += b*w; sum_g += g*w; sum_r += r*w;
|
1507
|
+
wsum += w;
|
1508
|
+
}
|
1509
|
+
wsum = 1.f/wsum;
|
1510
|
+
b0 = sum_b*wsum;
|
1511
|
+
g0 = sum_g*wsum;
|
1512
|
+
r0 = sum_r*wsum;
|
1513
|
+
dptr[j] = b0; dptr[j+1] = g0; dptr[j+2] = r0;
|
1514
|
+
}
|
1515
|
+
}
|
1516
|
+
}
|
1517
|
+
}
|
1518
|
+
|
1519
|
+
}
|
1520
|
+
|
1521
|
+
void cv::bilateralFilter( InputArray _src, OutputArray _dst, int d,
|
1522
|
+
double sigmaColor, double sigmaSpace,
|
1523
|
+
int borderType )
|
1524
|
+
{
|
1525
|
+
Mat src = _src.getMat();
|
1526
|
+
_dst.create( src.size(), src.type() );
|
1527
|
+
Mat dst = _dst.getMat();
|
1528
|
+
|
1529
|
+
if( src.depth() == CV_8U )
|
1530
|
+
bilateralFilter_8u( src, dst, d, sigmaColor, sigmaSpace, borderType );
|
1531
|
+
else if( src.depth() == CV_32F )
|
1532
|
+
bilateralFilter_32f( src, dst, d, sigmaColor, sigmaSpace, borderType );
|
1533
|
+
else
|
1534
|
+
CV_Error( CV_StsUnsupportedFormat,
|
1535
|
+
"Bilateral filtering is only implemented for 8u and 32f images" );
|
1536
|
+
}
|
1537
|
+
|
1538
|
+
//////////////////////////////////////////////////////////////////////////////////////////
|
1539
|
+
|
1540
|
+
CV_IMPL void
|
1541
|
+
cvSmooth( const void* srcarr, void* dstarr, int smooth_type,
|
1542
|
+
int param1, int param2, double param3, double param4 )
|
1543
|
+
{
|
1544
|
+
cv::Mat src = cv::cvarrToMat(srcarr), dst0 = cv::cvarrToMat(dstarr), dst = dst0;
|
1545
|
+
|
1546
|
+
CV_Assert( dst.size() == src.size() &&
|
1547
|
+
(smooth_type == CV_BLUR_NO_SCALE || dst.type() == src.type()) );
|
1548
|
+
|
1549
|
+
if( param2 <= 0 )
|
1550
|
+
param2 = param1;
|
1551
|
+
|
1552
|
+
if( smooth_type == CV_BLUR || smooth_type == CV_BLUR_NO_SCALE )
|
1553
|
+
cv::boxFilter( src, dst, dst.depth(), cv::Size(param1, param2), cv::Point(-1,-1),
|
1554
|
+
smooth_type == CV_BLUR, cv::BORDER_REPLICATE );
|
1555
|
+
else if( smooth_type == CV_GAUSSIAN )
|
1556
|
+
cv::GaussianBlur( src, dst, cv::Size(param1, param2), param3, param4, cv::BORDER_REPLICATE );
|
1557
|
+
else if( smooth_type == CV_MEDIAN )
|
1558
|
+
cv::medianBlur( src, dst, param1 );
|
1559
|
+
else
|
1560
|
+
cv::bilateralFilter( src, dst, param1, param3, param4, cv::BORDER_REPLICATE );
|
1561
|
+
|
1562
|
+
if( dst.data != dst0.data )
|
1563
|
+
CV_Error( CV_StsUnmatchedFormats, "The destination image does not have the proper type" );
|
1564
|
+
}
|
1565
|
+
|
1566
|
+
/* End of file. */
|