Merge pull request #1663 from vpisarev:ocl_experiments3
[profile/ivi/opencv.git] / modules / ocl / src / canny.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 //                           License Agreement
11 //                For Open Source Computer Vision Library
12 //
13 // Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
14 // Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
15 // Third party copyrights are property of their respective owners.
16 //
17 // @Authors
18 //    Peng Xiao, pengxiao@multicorewareinc.com
19 //
20 // Redistribution and use in source and binary forms, with or without modification,
21 // are permitted provided that the following conditions are met:
22 //
23 //   * Redistribution's of source code must retain the above copyright notice,
24 //     this list of conditions and the following disclaimer.
25 //
26 //   * Redistribution's in binary form must reproduce the above copyright notice,
27 //     this list of conditions and the following disclaimer in the documentation
28 //     and/or other oclMaterials provided with the distribution.
29 //
30 //   * The name of the copyright holders may not be used to endorse or promote products
31 //     derived from this software without specific prior written permission.
32 //
33 // This software is provided by the copyright holders and contributors as is and
34 // any express or implied warranties, including, but not limited to, the implied
35 // warranties of merchantability and fitness for a particular purpose are disclaimed.
36 // In no event shall the Intel Corporation or contributors be liable for any direct,
37 // indirect, incidental, special, exemplary, or consequential damages
38 // (including, but not limited to, procurement of substitute goods or services;
39 // loss of use, data, or profits; or business interruption) however caused
40 // and on any theory of liability, whether in contract, strict liability,
41 // or tort (including negligence or otherwise) arising in any way out of
42 // the use of this software, even if advised of the possibility of such damage.
43 //
44 //M*/
45
46 #include "precomp.hpp"
47 #include "opencl_kernels.hpp"
48
49 using namespace cv;
50 using namespace cv::ocl;
51
52 cv::ocl::CannyBuf::CannyBuf(const oclMat &dx_, const oclMat &dy_) : dx(dx_), dy(dy_), counter(NULL)
53 {
54     CV_Assert(dx_.type() == CV_32SC1 && dy_.type() == CV_32SC1 && dx_.size() == dy_.size());
55
56     create(dx_.size(), -1);
57 }
58
59 void cv::ocl::CannyBuf::create(const Size &image_size, int apperture_size)
60 {
61     ensureSizeIsEnough(image_size, CV_32SC1, dx);
62     ensureSizeIsEnough(image_size, CV_32SC1, dy);
63
64     if(apperture_size == 3)
65     {
66         ensureSizeIsEnough(image_size, CV_32SC1, dx_buf);
67         ensureSizeIsEnough(image_size, CV_32SC1, dy_buf);
68     }
69     else if(apperture_size > 0)
70     {
71         Mat kx, ky;
72         if (!filterDX)
73         {
74             filterDX = createDerivFilter_GPU(CV_8U, CV_32S, 1, 0, apperture_size, BORDER_REPLICATE);
75         }
76         if (!filterDY)
77         {
78             filterDY = createDerivFilter_GPU(CV_8U, CV_32S, 0, 1, apperture_size, BORDER_REPLICATE);
79         }
80     }
81     ensureSizeIsEnough(image_size.height + 2, image_size.width + 2, CV_32FC1, magBuf);
82     ensureSizeIsEnough(image_size.height + 2, image_size.width + 2, CV_32FC1, mapBuf);
83
84     ensureSizeIsEnough(1, image_size.width * image_size.height, CV_16UC2, trackBuf1);
85     ensureSizeIsEnough(1, image_size.width * image_size.height, CV_16UC2, trackBuf2);
86
87     int counter_i [1] = { 0 };
88     int err = 0;
89     if(counter)
90     {
91         openCLFree(counter);
92     }
93     counter = clCreateBuffer( *((cl_context*)getClContextPtr()), CL_MEM_COPY_HOST_PTR, sizeof(int), counter_i, &err );
94     openCLSafeCall(err);
95 }
96
97 void cv::ocl::CannyBuf::release()
98 {
99     dx.release();
100     dy.release();
101     dx_buf.release();
102     dy_buf.release();
103     magBuf.release();
104     mapBuf.release();
105     trackBuf1.release();
106     trackBuf2.release();
107     if(counter)
108     {
109         openCLFree(counter);
110         counter = NULL;
111     }
112 }
113
114 namespace cv
115 {
116     namespace ocl
117     {
118         namespace canny
119         {
120             void calcSobelRowPass_gpu(const oclMat &src, oclMat &dx_buf, oclMat &dy_buf, int rows, int cols);
121
122             void calcMagnitude_gpu(const oclMat &dx_buf, const oclMat &dy_buf, oclMat &dx, oclMat &dy, oclMat &mag, int rows, int cols, bool L2Grad);
123             void calcMagnitude_gpu(const oclMat &dx, const oclMat &dy, oclMat &mag, int rows, int cols, bool L2Grad);
124
125             void calcMap_gpu(oclMat &dx, oclMat &dy, oclMat &mag, oclMat &map, int rows, int cols, float low_thresh, float high_thresh);
126
127             void edgesHysteresisLocal_gpu(oclMat &map, oclMat &st1, void *counter, int rows, int cols);
128
129             void edgesHysteresisGlobal_gpu(oclMat &map, oclMat &st1, oclMat &st2, void *counter, int rows, int cols);
130
131             void getEdges_gpu(oclMat &map, oclMat &dst, int rows, int cols);
132         }
133     }
134 }// cv::ocl
135
136 namespace
137 {
138     void CannyCaller(CannyBuf &buf, oclMat &dst, float low_thresh, float high_thresh)
139     {
140         using namespace ::cv::ocl::canny;
141         calcMap_gpu(buf.dx, buf.dy, buf.magBuf, buf.mapBuf, dst.rows, dst.cols, low_thresh, high_thresh);
142
143         edgesHysteresisLocal_gpu(buf.mapBuf, buf.trackBuf1, buf.counter, dst.rows, dst.cols);
144
145         edgesHysteresisGlobal_gpu(buf.mapBuf, buf.trackBuf1, buf.trackBuf2, buf.counter, dst.rows, dst.cols);
146
147         getEdges_gpu(buf.mapBuf, dst, dst.rows, dst.cols);
148     }
149 }
150
151 void cv::ocl::Canny(const oclMat &src, oclMat &dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient)
152 {
153     CannyBuf buf(src.size(), apperture_size);
154     Canny(src, buf, dst, low_thresh, high_thresh, apperture_size, L2gradient);
155 }
156
157 void cv::ocl::Canny(const oclMat &src, CannyBuf &buf, oclMat &dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient)
158 {
159     using namespace ::cv::ocl::canny;
160
161     CV_Assert(src.type() == CV_8UC1);
162
163     if( low_thresh > high_thresh )
164         std::swap( low_thresh, high_thresh );
165
166     dst.create(src.size(), CV_8U);
167     dst.setTo(Scalar::all(0));
168
169     buf.create(src.size(), apperture_size);
170     buf.magBuf.setTo(Scalar::all(0));
171
172     if (apperture_size == 3)
173     {
174         calcSobelRowPass_gpu(src, buf.dx_buf, buf.dy_buf, src.rows, src.cols);
175
176         calcMagnitude_gpu(buf.dx_buf, buf.dy_buf, buf.dx, buf.dy, buf.magBuf, src.rows, src.cols, L2gradient);
177     }
178     else
179     {
180         buf.filterDX->apply(src, buf.dx);
181         buf.filterDY->apply(src, buf.dy);
182
183         calcMagnitude_gpu(buf.dx, buf.dy, buf.magBuf, src.rows, src.cols, L2gradient);
184     }
185     CannyCaller(buf, dst, static_cast<float>(low_thresh), static_cast<float>(high_thresh));
186 }
187 void cv::ocl::Canny(const oclMat &dx, const oclMat &dy, oclMat &dst, double low_thresh, double high_thresh, bool L2gradient)
188 {
189     CannyBuf buf(dx, dy);
190     Canny(dx, dy, buf, dst, low_thresh, high_thresh, L2gradient);
191 }
192
193 void cv::ocl::Canny(const oclMat &dx, const oclMat &dy, CannyBuf &buf, oclMat &dst, double low_thresh, double high_thresh, bool L2gradient)
194 {
195     using namespace ::cv::ocl::canny;
196
197     CV_Assert(dx.type() == CV_32SC1 && dy.type() == CV_32SC1 && dx.size() == dy.size());
198
199     if( low_thresh > high_thresh )
200         std::swap( low_thresh, high_thresh);
201
202     dst.create(dx.size(), CV_8U);
203     dst.setTo(Scalar::all(0));
204
205     buf.dx = dx;
206     buf.dy = dy;
207     buf.create(dx.size(), -1);
208     buf.magBuf.setTo(Scalar::all(0));
209     calcMagnitude_gpu(buf.dx, buf.dy, buf.magBuf, dx.rows, dx.cols, L2gradient);
210
211     CannyCaller(buf, dst, static_cast<float>(low_thresh), static_cast<float>(high_thresh));
212 }
213
214 void canny::calcSobelRowPass_gpu(const oclMat &src, oclMat &dx_buf, oclMat &dy_buf, int rows, int cols)
215 {
216     Context *clCxt = src.clCxt;
217     String kernelName = "calcSobelRowPass";
218     std::vector< std::pair<size_t, const void *> > args;
219
220     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&src.data));
221     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dx_buf.data));
222     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dy_buf.data));
223     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
224     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
225     args.push_back( std::make_pair( sizeof(cl_int), (void *)&src.step));
226     args.push_back( std::make_pair( sizeof(cl_int), (void *)&src.offset));
227     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx_buf.step));
228     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx_buf.offset));
229     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy_buf.step));
230     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy_buf.offset));
231
232     size_t globalThreads[3] = {cols, rows, 1};
233     size_t localThreads[3]  = {16, 16, 1};
234     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
235 }
236
237 void canny::calcMagnitude_gpu(const oclMat &dx_buf, const oclMat &dy_buf, oclMat &dx, oclMat &dy, oclMat &mag, int rows, int cols, bool L2Grad)
238 {
239     Context *clCxt = dx_buf.clCxt;
240     String kernelName = "calcMagnitude_buf";
241     std::vector< std::pair<size_t, const void *> > args;
242
243     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dx_buf.data));
244     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dy_buf.data));
245     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dx.data));
246     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dy.data));
247     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&mag.data));
248     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
249     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
250     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx_buf.step));
251     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx_buf.offset));
252     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy_buf.step));
253     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy_buf.offset));
254     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.step));
255     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.offset));
256     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.step));
257     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.offset));
258     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.step));
259     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.offset));
260
261     size_t globalThreads[3] = {cols, rows, 1};
262     size_t localThreads[3]  = {16, 16, 1};
263
264     const char * build_options = L2Grad ? "-D L2GRAD":"";
265     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1, build_options);
266 }
267 void canny::calcMagnitude_gpu(const oclMat &dx, const oclMat &dy, oclMat &mag, int rows, int cols, bool L2Grad)
268 {
269     Context *clCxt = dx.clCxt;
270     String kernelName = "calcMagnitude";
271     std::vector< std::pair<size_t, const void *> > args;
272
273     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dx.data));
274     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dy.data));
275     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&mag.data));
276     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
277     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
278     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.step));
279     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.offset));
280     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.step));
281     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.offset));
282     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.step));
283     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.offset));
284
285     size_t globalThreads[3] = {cols, rows, 1};
286     size_t localThreads[3]  = {16, 16, 1};
287
288     const char * build_options = L2Grad ? "-D L2GRAD":"";
289     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1, build_options);
290 }
291
292 void canny::calcMap_gpu(oclMat &dx, oclMat &dy, oclMat &mag, oclMat &map, int rows, int cols, float low_thresh, float high_thresh)
293 {
294     Context *clCxt = dx.clCxt;
295
296     std::vector< std::pair<size_t, const void *> > args;
297
298     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dx.data));
299     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dy.data));
300     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&mag.data));
301     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&map.data));
302     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
303     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
304     args.push_back( std::make_pair( sizeof(cl_float), (void *)&low_thresh));
305     args.push_back( std::make_pair( sizeof(cl_float), (void *)&high_thresh));
306     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.step));
307     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dx.offset));
308     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.step));
309     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dy.offset));
310     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.step));
311     args.push_back( std::make_pair( sizeof(cl_int), (void *)&mag.offset));
312     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.step));
313     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.offset));
314
315
316     size_t globalThreads[3] = {cols, rows, 1};
317     String kernelName = "calcMap";
318     size_t localThreads[3]  = {16, 16, 1};
319
320     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
321 }
322
323 void canny::edgesHysteresisLocal_gpu(oclMat &map, oclMat &st1, void *counter, int rows, int cols)
324 {
325     Context *clCxt = map.clCxt;
326     String kernelName = "edgesHysteresisLocal";
327     std::vector< std::pair<size_t, const void *> > args;
328
329     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&map.data));
330     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&st1.data));
331     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&counter));
332     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
333     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
334     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.step));
335     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.offset));
336
337     size_t globalThreads[3] = {cols, rows, 1};
338     size_t localThreads[3]  = {16, 16, 1};
339
340     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
341 }
342
343 void canny::edgesHysteresisGlobal_gpu(oclMat &map, oclMat &st1, oclMat &st2, void *counter, int rows, int cols)
344 {
345     unsigned int count;
346     openCLSafeCall(clEnqueueReadBuffer(*(cl_command_queue*)getClCommandQueuePtr(), (cl_mem)counter, 1, 0, sizeof(float), &count, 0, NULL, NULL));
347     Context *clCxt = map.clCxt;
348     String kernelName = "edgesHysteresisGlobal";
349     std::vector< std::pair<size_t, const void *> > args;
350     size_t localThreads[3]  = {128, 1, 1};
351
352     int count_i[1] = {0};
353     while(count > 0)
354     {
355         openCLSafeCall(clEnqueueWriteBuffer(*(cl_command_queue*)getClCommandQueuePtr(), (cl_mem)counter, 1, 0, sizeof(int), &count_i, 0, NULL, NULL));
356
357         args.clear();
358         size_t globalThreads[3] = {std::min(count, 65535u) * 128, divUp(count, 65535), 1};
359         args.push_back( std::make_pair( sizeof(cl_mem), (void *)&map.data));
360         args.push_back( std::make_pair( sizeof(cl_mem), (void *)&st1.data));
361         args.push_back( std::make_pair( sizeof(cl_mem), (void *)&st2.data));
362         args.push_back( std::make_pair( sizeof(cl_mem), (void *)&counter));
363         args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
364         args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
365         args.push_back( std::make_pair( sizeof(cl_int), (void *)&count));
366         args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.step));
367         args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.offset));
368
369         openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
370         openCLSafeCall(clEnqueueReadBuffer(*(cl_command_queue*)getClCommandQueuePtr(), (cl_mem)counter, 1, 0, sizeof(int), &count, 0, NULL, NULL));
371         std::swap(st1, st2);
372     }
373 }
374
375 void canny::getEdges_gpu(oclMat &map, oclMat &dst, int rows, int cols)
376 {
377     Context *clCxt = map.clCxt;
378     String kernelName = "getEdges";
379     std::vector< std::pair<size_t, const void *> > args;
380
381     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&map.data));
382     args.push_back( std::make_pair( sizeof(cl_mem), (void *)&dst.data));
383     args.push_back( std::make_pair( sizeof(cl_int), (void *)&rows));
384     args.push_back( std::make_pair( sizeof(cl_int), (void *)&cols));
385     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.step));
386     args.push_back( std::make_pair( sizeof(cl_int), (void *)&map.offset));
387     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dst.step));
388     args.push_back( std::make_pair( sizeof(cl_int), (void *)&dst.offset));
389
390     size_t globalThreads[3] = {cols, rows, 1};
391     size_t localThreads[3]  = {16, 16, 1};
392
393     openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
394 }