1 /*M///////////////////////////////////////////////////////////////////////////////////////
3 // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
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.
11 // For Open Source Computer Vision Library
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.
18 // Peng Xiao, pengxiao@multicorewareinc.com
20 // Redistribution and use in source and binary forms, with or without modification,
21 // are permitted provided that the following conditions are met:
23 // * Redistribution's of source code must retain the above copyright notice,
24 // this list of conditions and the following disclaimer.
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.
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.
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.
46 #include "precomp.hpp"
47 #include "opencl_kernels.hpp"
50 using namespace cv::ocl;
52 cv::ocl::CannyBuf::CannyBuf(const oclMat &dx_, const oclMat &dy_) : dx(dx_), dy(dy_), counter(NULL)
54 CV_Assert(dx_.type() == CV_32SC1 && dy_.type() == CV_32SC1 && dx_.size() == dy_.size());
56 create(dx_.size(), -1);
59 void cv::ocl::CannyBuf::create(const Size &image_size, int apperture_size)
61 ensureSizeIsEnough(image_size, CV_32SC1, dx);
62 ensureSizeIsEnough(image_size, CV_32SC1, dy);
64 if(apperture_size == 3)
66 ensureSizeIsEnough(image_size, CV_32SC1, dx_buf);
67 ensureSizeIsEnough(image_size, CV_32SC1, dy_buf);
69 else if(apperture_size > 0)
74 filterDX = createDerivFilter_GPU(CV_8U, CV_32S, 1, 0, apperture_size, BORDER_REPLICATE);
78 filterDY = createDerivFilter_GPU(CV_8U, CV_32S, 0, 1, apperture_size, BORDER_REPLICATE);
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);
84 ensureSizeIsEnough(1, image_size.width * image_size.height, CV_16UC2, trackBuf1);
85 ensureSizeIsEnough(1, image_size.width * image_size.height, CV_16UC2, trackBuf2);
87 int counter_i [1] = { 0 };
93 counter = clCreateBuffer( *((cl_context*)getClContextPtr()), CL_MEM_COPY_HOST_PTR, sizeof(int), counter_i, &err );
97 void cv::ocl::CannyBuf::release()
120 void calcSobelRowPass_gpu(const oclMat &src, oclMat &dx_buf, oclMat &dy_buf, int rows, int cols);
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);
125 void calcMap_gpu(oclMat &dx, oclMat &dy, oclMat &mag, oclMat &map, int rows, int cols, float low_thresh, float high_thresh);
127 void edgesHysteresisLocal_gpu(oclMat &map, oclMat &st1, void *counter, int rows, int cols);
129 void edgesHysteresisGlobal_gpu(oclMat &map, oclMat &st1, oclMat &st2, void *counter, int rows, int cols);
131 void getEdges_gpu(oclMat &map, oclMat &dst, int rows, int cols);
138 void CannyCaller(CannyBuf &buf, oclMat &dst, float low_thresh, float high_thresh)
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);
143 edgesHysteresisLocal_gpu(buf.mapBuf, buf.trackBuf1, buf.counter, dst.rows, dst.cols);
145 edgesHysteresisGlobal_gpu(buf.mapBuf, buf.trackBuf1, buf.trackBuf2, buf.counter, dst.rows, dst.cols);
147 getEdges_gpu(buf.mapBuf, dst, dst.rows, dst.cols);
151 void cv::ocl::Canny(const oclMat &src, oclMat &dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient)
153 CannyBuf buf(src.size(), apperture_size);
154 Canny(src, buf, dst, low_thresh, high_thresh, apperture_size, L2gradient);
157 void cv::ocl::Canny(const oclMat &src, CannyBuf &buf, oclMat &dst, double low_thresh, double high_thresh, int apperture_size, bool L2gradient)
159 using namespace ::cv::ocl::canny;
161 CV_Assert(src.type() == CV_8UC1);
163 if( low_thresh > high_thresh )
164 std::swap( low_thresh, high_thresh );
166 dst.create(src.size(), CV_8U);
167 dst.setTo(Scalar::all(0));
169 buf.create(src.size(), apperture_size);
170 buf.magBuf.setTo(Scalar::all(0));
172 if (apperture_size == 3)
174 calcSobelRowPass_gpu(src, buf.dx_buf, buf.dy_buf, src.rows, src.cols);
176 calcMagnitude_gpu(buf.dx_buf, buf.dy_buf, buf.dx, buf.dy, buf.magBuf, src.rows, src.cols, L2gradient);
180 buf.filterDX->apply(src, buf.dx);
181 buf.filterDY->apply(src, buf.dy);
183 calcMagnitude_gpu(buf.dx, buf.dy, buf.magBuf, src.rows, src.cols, L2gradient);
185 CannyCaller(buf, dst, static_cast<float>(low_thresh), static_cast<float>(high_thresh));
187 void cv::ocl::Canny(const oclMat &dx, const oclMat &dy, oclMat &dst, double low_thresh, double high_thresh, bool L2gradient)
189 CannyBuf buf(dx, dy);
190 Canny(dx, dy, buf, dst, low_thresh, high_thresh, L2gradient);
193 void cv::ocl::Canny(const oclMat &dx, const oclMat &dy, CannyBuf &buf, oclMat &dst, double low_thresh, double high_thresh, bool L2gradient)
195 using namespace ::cv::ocl::canny;
197 CV_Assert(dx.type() == CV_32SC1 && dy.type() == CV_32SC1 && dx.size() == dy.size());
199 if( low_thresh > high_thresh )
200 std::swap( low_thresh, high_thresh);
202 dst.create(dx.size(), CV_8U);
203 dst.setTo(Scalar::all(0));
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);
211 CannyCaller(buf, dst, static_cast<float>(low_thresh), static_cast<float>(high_thresh));
214 void canny::calcSobelRowPass_gpu(const oclMat &src, oclMat &dx_buf, oclMat &dy_buf, int rows, int cols)
216 Context *clCxt = src.clCxt;
217 String kernelName = "calcSobelRowPass";
218 std::vector< std::pair<size_t, const void *> > args;
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));
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);
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)
239 Context *clCxt = dx_buf.clCxt;
240 String kernelName = "calcMagnitude_buf";
241 std::vector< std::pair<size_t, const void *> > args;
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));
261 size_t globalThreads[3] = {cols, rows, 1};
262 size_t localThreads[3] = {16, 16, 1};
264 const char * build_options = L2Grad ? "-D L2GRAD":"";
265 openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1, build_options);
267 void canny::calcMagnitude_gpu(const oclMat &dx, const oclMat &dy, oclMat &mag, int rows, int cols, bool L2Grad)
269 Context *clCxt = dx.clCxt;
270 String kernelName = "calcMagnitude";
271 std::vector< std::pair<size_t, const void *> > args;
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));
285 size_t globalThreads[3] = {cols, rows, 1};
286 size_t localThreads[3] = {16, 16, 1};
288 const char * build_options = L2Grad ? "-D L2GRAD":"";
289 openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1, build_options);
292 void canny::calcMap_gpu(oclMat &dx, oclMat &dy, oclMat &mag, oclMat &map, int rows, int cols, float low_thresh, float high_thresh)
294 Context *clCxt = dx.clCxt;
296 std::vector< std::pair<size_t, const void *> > args;
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));
316 size_t globalThreads[3] = {cols, rows, 1};
317 String kernelName = "calcMap";
318 size_t localThreads[3] = {16, 16, 1};
320 openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
323 void canny::edgesHysteresisLocal_gpu(oclMat &map, oclMat &st1, void *counter, int rows, int cols)
325 Context *clCxt = map.clCxt;
326 String kernelName = "edgesHysteresisLocal";
327 std::vector< std::pair<size_t, const void *> > args;
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));
337 size_t globalThreads[3] = {cols, rows, 1};
338 size_t localThreads[3] = {16, 16, 1};
340 openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);
343 void canny::edgesHysteresisGlobal_gpu(oclMat &map, oclMat &st1, oclMat &st2, void *counter, int rows, int cols)
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};
352 int count_i[1] = {0};
355 openCLSafeCall(clEnqueueWriteBuffer(*(cl_command_queue*)getClCommandQueuePtr(), (cl_mem)counter, 1, 0, sizeof(int), &count_i, 0, NULL, NULL));
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));
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));
375 void canny::getEdges_gpu(oclMat &map, oclMat &dst, int rows, int cols)
377 Context *clCxt = map.clCxt;
378 String kernelName = "getEdges";
379 std::vector< std::pair<size_t, const void *> > args;
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));
390 size_t globalThreads[3] = {cols, rows, 1};
391 size_t localThreads[3] = {16, 16, 1};
393 openCLExecuteKernel(clCxt, &imgproc_canny, kernelName, globalThreads, localThreads, args, -1, -1);