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.
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. */