imagecore 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (71) hide show
  1. data/.gitignore +24 -0
  2. data/Gemfile +4 -0
  3. data/Rakefile +2 -0
  4. data/ext/imagecore/analyze_image.cxx +58 -0
  5. data/ext/imagecore/analyze_image.h +6 -0
  6. data/ext/imagecore/extconf.rb +9 -0
  7. data/ext/imagecore/imagecore.cxx +34 -0
  8. data/ext/opencv/core/___.c +3 -0
  9. data/ext/opencv/core/alloc.cpp +697 -0
  10. data/ext/opencv/core/array.cpp +3206 -0
  11. data/ext/opencv/core/datastructs.cpp +4064 -0
  12. data/ext/opencv/core/extconf.rb +22 -0
  13. data/ext/opencv/core/matrix.cpp +3777 -0
  14. data/ext/opencv/core/precomp.hpp +216 -0
  15. data/ext/opencv/core/system.cpp +832 -0
  16. data/ext/opencv/core/tables.cpp +3512 -0
  17. data/ext/opencv/highgui/___.c +3 -0
  18. data/ext/opencv/highgui/bitstrm.cpp +582 -0
  19. data/ext/opencv/highgui/bitstrm.hpp +182 -0
  20. data/ext/opencv/highgui/extconf.rb +28 -0
  21. data/ext/opencv/highgui/grfmt_base.cpp +128 -0
  22. data/ext/opencv/highgui/grfmt_base.hpp +113 -0
  23. data/ext/opencv/highgui/grfmt_bmp.cpp +564 -0
  24. data/ext/opencv/highgui/grfmt_bmp.hpp +99 -0
  25. data/ext/opencv/highgui/grfmt_exr.hpp +113 -0
  26. data/ext/opencv/highgui/grfmt_imageio.hpp +56 -0
  27. data/ext/opencv/highgui/grfmt_jpeg.cpp +622 -0
  28. data/ext/opencv/highgui/grfmt_jpeg.hpp +90 -0
  29. data/ext/opencv/highgui/grfmt_jpeg2000.cpp +529 -0
  30. data/ext/opencv/highgui/grfmt_jpeg2000.hpp +95 -0
  31. data/ext/opencv/highgui/grfmt_png.cpp +406 -0
  32. data/ext/opencv/highgui/grfmt_png.hpp +101 -0
  33. data/ext/opencv/highgui/grfmt_pxm.cpp +513 -0
  34. data/ext/opencv/highgui/grfmt_pxm.hpp +92 -0
  35. data/ext/opencv/highgui/grfmt_sunras.cpp +425 -0
  36. data/ext/opencv/highgui/grfmt_sunras.hpp +105 -0
  37. data/ext/opencv/highgui/grfmt_tiff.cpp +718 -0
  38. data/ext/opencv/highgui/grfmt_tiff.hpp +136 -0
  39. data/ext/opencv/highgui/grfmts.hpp +56 -0
  40. data/ext/opencv/highgui/loadsave.cpp +535 -0
  41. data/ext/opencv/highgui/precomp.hpp +223 -0
  42. data/ext/opencv/highgui/utils.cpp +689 -0
  43. data/ext/opencv/highgui/utils.hpp +128 -0
  44. data/ext/opencv/imgproc/___.c +3 -0
  45. data/ext/opencv/imgproc/_geom.h +72 -0
  46. data/ext/opencv/imgproc/color.cpp +3179 -0
  47. data/ext/opencv/imgproc/contours.cpp +1780 -0
  48. data/ext/opencv/imgproc/extconf.rb +11 -0
  49. data/ext/opencv/imgproc/filter.cpp +3063 -0
  50. data/ext/opencv/imgproc/precomp.hpp +159 -0
  51. data/ext/opencv/imgproc/shapedescr.cpp +1306 -0
  52. data/ext/opencv/imgproc/smooth.cpp +1566 -0
  53. data/ext/opencv/imgproc/tables.cpp +214 -0
  54. data/ext/opencv/imgproc/thresh.cpp +636 -0
  55. data/ext/opencv/imgproc/utils.cpp +242 -0
  56. data/ext/opencv/include/opencv2/core/core.hpp +4344 -0
  57. data/ext/opencv/include/opencv2/core/core_c.h +1885 -0
  58. data/ext/opencv/include/opencv2/core/internal.hpp +710 -0
  59. data/ext/opencv/include/opencv2/core/mat.hpp +2557 -0
  60. data/ext/opencv/include/opencv2/core/operations.hpp +3623 -0
  61. data/ext/opencv/include/opencv2/core/types_c.h +1875 -0
  62. data/ext/opencv/include/opencv2/core/version.hpp +58 -0
  63. data/ext/opencv/include/opencv2/highgui/highgui.hpp +198 -0
  64. data/ext/opencv/include/opencv2/highgui/highgui_c.h +506 -0
  65. data/ext/opencv/include/opencv2/imgproc/imgproc.hpp +1139 -0
  66. data/ext/opencv/include/opencv2/imgproc/imgproc_c.h +783 -0
  67. data/ext/opencv/include/opencv2/imgproc/types_c.h +538 -0
  68. data/imagecore.gemspec +20 -0
  69. data/lib/imagecore.rb +16 -0
  70. data/lib/imagecore/version.rb +3 -0
  71. 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. */