Update to 2.0.0 tree from current Fremantle build
[opencv] / src / cv / cvderiv.cpp
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 //                        Intel License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2000, Intel Corporation, all rights reserved.
14 // Third party copyrights are property of their respective owners.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 //   * Redistribution's of source code must retain the above copyright notice,
20 //     this list of conditions and the following disclaimer.
21 //
22 //   * Redistribution's in binary form must reproduce the above copyright notice,
23 //     this list of conditions and the following disclaimer in the documentation
24 //     and/or other materials provided with the distribution.
25 //
26 //   * The name of Intel Corporation may not be used to endorse or promote products
27 //     derived from this software without specific prior written permission.
28 //
29 // This software is provided by the copyright holders and contributors "as is" and
30 // any express or implied warranties, including, but not limited to, the implied
31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
32 // In no event shall the Intel Corporation or contributors be liable for any direct,
33 // indirect, incidental, special, exemplary, or consequential damages
34 // (including, but not limited to, procurement of substitute goods or services;
35 // loss of use, data, or profits; or business interruption) however caused
36 // and on any theory of liability, whether in contract, strict liability,
37 // or tort (including negligence or otherwise) arising in any way out of
38 // the use of this software, even if advised of the possibility of such damage.
39 //
40 //M*/
41
42 #include "_cv.h"
43
44 /****************************************************************************************/
45
46 /* lightweight convolution with 3x3 kernel */
47 void icvSepConvSmall3_32f( float* src, int src_step, float* dst, int dst_step,
48             CvSize src_size, const float* kx, const float* ky, float* buffer )
49 {
50     int  dst_width, buffer_step = 0;
51     int  x, y;
52
53     assert( src && dst && src_size.width > 2 && src_size.height > 2 &&
54             (src_step & 3) == 0 && (dst_step & 3) == 0 &&
55             (kx || ky) && (buffer || !kx || !ky));
56
57     src_step /= sizeof(src[0]);
58     dst_step /= sizeof(dst[0]);
59
60     dst_width = src_size.width - 2;
61
62     if( !kx )
63     {
64         /* set vars, so that vertical convolution
65            will write results into destination ROI and
66            horizontal convolution won't run */
67         src_size.width = dst_width;
68         buffer_step = dst_step;
69         buffer = dst;
70         dst_width = 0;
71     }
72
73     assert( src_step >= src_size.width && dst_step >= dst_width );
74
75     src_size.height -= 3;
76     if( !ky )
77     {
78         /* set vars, so that vertical convolution won't run and
79            horizontal convolution will write results into destination ROI */
80         src_size.height += 3;
81         buffer_step = src_step;
82         buffer = src;
83         src_size.width = 0;
84     }
85
86     for( y = 0; y <= src_size.height; y++, src += src_step,
87                                            dst += dst_step,
88                                            buffer += buffer_step )
89     {
90         float* src2 = src + src_step;
91         float* src3 = src + src_step*2;
92         for( x = 0; x < src_size.width; x++ )
93         {
94             buffer[x] = (float)(ky[0]*src[x] + ky[1]*src2[x] + ky[2]*src3[x]);
95         }
96
97         for( x = 0; x < dst_width; x++ )
98         {
99             dst[x] = (float)(kx[0]*buffer[x] + kx[1]*buffer[x+1] + kx[2]*buffer[x+2]);
100         }
101     }
102 }
103
104
105 /****************************************************************************************\
106                              Sobel & Scharr Derivative Filters
107 \****************************************************************************************/
108
109 namespace cv
110 {
111
112 static void getScharrKernels( Mat& kx, Mat& ky, int dx, int dy, bool normalize, int ktype )
113 {
114     const int ksize = 3;
115
116     CV_Assert( ktype == CV_32F || ktype == CV_64F );
117
118     if( kx.cols != ksize || kx.rows != 1 || kx.type() != ktype )
119         kx.create( ksize, 1, ktype );
120     if( ky.cols != ksize || ky.rows != 1 || ky.type() != ktype )
121         ky.create( ksize, 1, ktype );
122
123     CV_Assert( dx >= 0 && dy >= 0 && dx+dy == 1 );
124
125     for( int k = 0; k < 2; k++ )
126     {
127         Mat* kernel = k == 0 ? &kx : &ky;
128         int order = k == 0 ? dx : dy;
129         int kerI[3];
130
131         if( order == 0 )
132             kerI[0] = 3, kerI[1] = 10, kerI[2] = 3;
133         else if( order == 1 )
134             kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
135
136         Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
137         double scale = !normalize || order == 1 ? 1. : 1./32;
138         temp.convertTo(*kernel, ktype, scale);
139     }
140 }
141
142
143 static void getSobelKernels( Mat& kx, Mat& ky, int dx, int dy, int _ksize, bool normalize, int ktype )
144 {
145     int i, j, ksizeX = _ksize, ksizeY = _ksize;
146     if( ksizeX == 1 && dx > 0 )
147         ksizeX = 3;
148     if( ksizeY == 1 && dy > 0 )
149         ksizeY = 3;
150
151     CV_Assert( ktype == CV_32F || ktype == CV_64F );
152
153     if( kx.cols != ksizeX || kx.rows != 1 || kx.type() != ktype )
154         kx.create( ksizeX, 1, ktype );
155     if( ky.cols != ksizeY || ky.rows != 1 || ky.type() != ktype )
156         ky.create( ksizeY, 1, ktype );
157
158     if( _ksize % 2 == 0 || _ksize > 31 )
159         CV_Error( CV_StsOutOfRange, "The kernel size must be odd and not larger than 31" );
160     vector<int> kerI(std::max(ksizeX, ksizeY) + 1);
161
162     CV_Assert( dx >= 0 && dy >= 0 && dx+dy > 0 );
163
164     for( int k = 0; k < 2; k++ )
165     {
166         Mat* kernel = k == 0 ? &kx : &ky;
167         int order = k == 0 ? dx : dy;
168         int ksize = k == 0 ? ksizeX : ksizeY;
169
170         CV_Assert( ksize > order );
171
172         if( ksize == 1 )
173             kerI[0] = 1;
174         else if( ksize == 3 )
175         {
176             if( order == 0 )
177                 kerI[0] = 1, kerI[1] = 2, kerI[2] = 1;
178             else if( order == 1 )
179                 kerI[0] = -1, kerI[1] = 0, kerI[2] = 1;
180             else
181                 kerI[0] = 1, kerI[1] = -2, kerI[2] = 1;
182         }
183         else
184         {
185             int oldval, newval;
186             kerI[0] = 1;
187             for( i = 0; i < ksize; i++ )
188                 kerI[i+1] = 0;
189
190             for( i = 0; i < ksize - order - 1; i++ )
191             {
192                 oldval = kerI[0];
193                 for( j = 1; j <= ksize; j++ )
194                 {
195                     newval = kerI[j]+kerI[j-1];
196                     kerI[j-1] = oldval;
197                     oldval = newval;
198                 }
199             }
200
201             for( i = 0; i < order; i++ )
202             {
203                 oldval = -kerI[0];
204                 for( j = 1; j <= ksize; j++ )
205                 {
206                     newval = kerI[j-1] - kerI[j];
207                     kerI[j-1] = oldval;
208                     oldval = newval;
209                 }
210             }
211         }
212
213         Mat temp(kernel->rows, kernel->cols, CV_32S, &kerI[0]);
214         double scale = !normalize ? 1. : 1./(1 << (ksize-order-1));
215         temp.convertTo(*kernel, ktype, scale);
216     }
217 }
218
219
220 void getDerivKernels( Mat& kx, Mat& ky, int dx, int dy,
221                       int ksize, bool normalize, int ktype )
222 {
223     if( ksize <= 0 )
224         getScharrKernels( kx, ky, dx, dy, normalize, ktype );
225     else
226         getSobelKernels( kx, ky, dx, dy, ksize, normalize, ktype );
227 }
228
229
230 Ptr<FilterEngine> createDerivFilter(int srcType, int dstType,
231                                     int dx, int dy, int ksize, int borderType )
232 {
233     Mat kx, ky;
234     getDerivKernels( kx, ky, dx, dy, ksize, false, CV_32F );
235     return createSeparableLinearFilter(srcType, dstType,
236         kx, ky, Point(-1,-1), 0, borderType );
237 }
238
239
240 void Sobel( const Mat& src, Mat& dst, int ddepth, int dx, int dy,
241             int ksize, double scale, double delta, int borderType )
242 {
243     int ktype = std::max(CV_32F, std::max(ddepth, src.depth()));
244
245     Mat kx, ky;
246     getDerivKernels( kx, ky, dx, dy, ksize, false, ktype );
247     if( scale != 1 )
248     {
249         // usually the smoothing part is the slowest to compute,
250         // so try to scale it instead of the faster differenciating part
251         if( dx == 0 )
252             kx *= scale;
253         else
254             ky *= scale;
255     }
256     sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType );
257 }
258
259
260 void Scharr( const Mat& src, Mat& dst, int ddepth, int dx, int dy,
261              double scale, double delta, int borderType )
262 {
263     int ktype = std::max(CV_32F, std::max(ddepth, src.depth()));
264
265     Mat kx, ky;
266     getScharrKernels( kx, ky, dx, dy, false, ktype );
267     if( scale != 1 )
268     {
269         // usually the smoothing part is the slowest to compute,
270         // so try to scale it instead of the faster differenciating part
271         if( dx == 0 )
272             kx *= scale;
273         else
274             ky *= scale;
275     }
276     sepFilter2D( src, dst, ddepth, kx, ky, Point(-1,-1), delta, borderType );
277 }
278
279
280 void Laplacian( const Mat& src, Mat& dst, int ddepth, int ksize,
281                 double scale, double delta, int borderType )
282 {
283     if( ksize == 1 || ksize == 3 )
284     {
285         float K[2][9] =
286         {{0, 1, 0, 1, -4, 1, 0, 1, 0},
287          {2, 0, 2, 0, -8, 0, 2, 0, 2}};
288         Mat kernel(3, 3, CV_32F, K[ksize == 3]);
289         if( scale != 1 )
290             kernel *= scale;
291         filter2D( src, dst, ddepth, kernel, Point(-1,-1), delta, borderType );
292     }
293     else
294     {
295         const size_t STRIPE_SIZE = 1 << 14;
296
297         int depth = src.depth();
298         int ktype = std::max(CV_32F, std::max(ddepth, depth));
299         int wdepth = depth == CV_8U && ksize <= 5 ? CV_16S : depth <= CV_32F ? CV_32F : CV_64F;
300         int wtype = CV_MAKETYPE(wdepth, src.channels());
301         Mat kd, ks;
302         getSobelKernels( kd, ks, 2, 0, ksize, false, ktype );
303         if( ddepth < 0 )
304             ddepth = src.depth();
305         int dtype = CV_MAKETYPE(ddepth, src.channels());
306         dst.create( src.size(), dtype );
307
308         int dy0 = std::min(std::max((int)(STRIPE_SIZE/(getElemSize(src.type())*src.cols)), 1), src.rows);
309         Ptr<FilterEngine> fx = createSeparableLinearFilter(src.type(),
310             wtype, kd, ks, Point(-1,-1), 0, borderType, borderType, Scalar() ); 
311         Ptr<FilterEngine> fy = createSeparableLinearFilter(src.type(),
312             wtype, ks, kd, Point(-1,-1), 0, borderType, borderType, Scalar() );
313
314         int y = fx->start(src), dsty = 0, dy = 0;
315         fy->start(src);
316         const uchar* sptr = src.data + y*src.step;
317
318         Mat d2x( dy0 + kd.rows - 1, src.cols, wtype );
319         Mat d2y( dy0 + kd.rows - 1, src.cols, wtype );
320
321         for( ; dsty < src.rows; sptr += dy0*src.step, dsty += dy )
322         {
323             fx->proceed( sptr, (int)src.step, dy0, d2x.data, (int)d2x.step );
324             dy = fy->proceed( sptr, (int)src.step, dy0, d2y.data, (int)d2y.step );
325             if( dy > 0 )
326             {
327                 Mat dstripe = dst.rowRange(dsty, dsty + dy);
328                 d2x.rows = d2y.rows = dy; // modify the headers, which should work
329                 d2x += d2y;
330                 d2x.convertTo( dstripe, dtype, scale, delta );
331             }
332         }
333     }
334 }
335
336 }
337
338 /////////////////////////////////////////////////////////////////////////////////////////
339
340 CV_IMPL void
341 cvSobel( const void* srcarr, void* dstarr, int dx, int dy, int aperture_size )
342 {
343     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
344
345     CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() &&
346         ((src.depth() == CV_8U && (dst.depth() == CV_16S || dst.depth() == CV_32F)) ||
347         (src.depth() == CV_32F && dst.depth() == CV_32F)));
348
349     cv::Sobel( src, dst, dst.depth(), dx, dy, aperture_size, 1, 0, cv::BORDER_REPLICATE );
350     if( CV_IS_IMAGE(srcarr) && ((IplImage*)srcarr)->origin && dy % 2 != 0 )
351         dst *= -1;
352 }
353
354
355 CV_IMPL void
356 cvLaplace( const void* srcarr, void* dstarr, int aperture_size )
357 {
358     cv::Mat src = cv::cvarrToMat(srcarr), dst = cv::cvarrToMat(dstarr);
359
360     CV_Assert( src.size() == dst.size() && src.channels() == dst.channels() &&
361         ((src.depth() == CV_8U && (dst.depth() == CV_16S || dst.depth() == CV_32F)) ||
362         (src.depth() == CV_32F && dst.depth() == CV_32F)));
363
364     cv::Laplacian( src, dst, dst.depth(), aperture_size, 1, 0, cv::BORDER_REPLICATE );
365 }
366
367 /* End of file. */