test_warp.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  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, Institute Of Software Chinese Academy Of Science, all rights reserved.
  14. // Copyright (C) 2010-2012, Advanced Micro Devices, Inc., all rights reserved.
  15. // Copyright (C) 2010-2012, Multicoreware, Inc., all rights reserved.
  16. // Third party copyrights are property of their respective owners.
  17. //
  18. // @Authors
  19. // Niko Li, newlife20080214@gmail.com
  20. // Jia Haipeng, jiahaipeng95@gmail.com
  21. // Shengen Yan, yanshengen@gmail.com
  22. // Jiang Liyuan, lyuan001.good@163.com
  23. // Rock Li, Rock.Li@amd.com
  24. // Wu Zailong, bullet@yeah.net
  25. // Xu Pang, pangxu010@163.com
  26. // Sen Liu, swjtuls1987@126.com
  27. //
  28. // Redistribution and use in source and binary forms, with or without modification,
  29. // are permitted provided that the following conditions are met:
  30. //
  31. // * Redistribution's of source code must retain the above copyright notice,
  32. // this list of conditions and the following disclaimer.
  33. //
  34. // * Redistribution's in binary form must reproduce the above copyright notice,
  35. // this list of conditions and the following disclaimer in the documentation
  36. // and/or other materials provided with the distribution.
  37. //
  38. // * The name of the copyright holders may not be used to endorse or promote products
  39. // derived from this software without specific prior written permission.
  40. //
  41. // This software is provided by the copyright holders and contributors "as is" and
  42. // any express or implied warranties, including, but not limited to, the implied
  43. // warranties of merchantability and fitness for a particular purpose are disclaimed.
  44. // In no event shall the Intel Corporation or contributors be liable for any direct,
  45. // indirect, incidental, special, exemplary, or consequential damages
  46. // (including, but not limited to, procurement of substitute goods or services;
  47. // loss of use, data, or profits; or business interruption) however caused
  48. // and on any theory of liability, whether in contract, strict liability,
  49. // or tort (including negligence or otherwise) arising in any way out of
  50. // the use of this software, even if advised of the possibility of such damage.
  51. //
  52. //M*/
  53. #include "../test_precomp.hpp"
  54. #include "opencv2/ts/ocl_test.hpp"
  55. #ifdef HAVE_OPENCL
  56. namespace opencv_test {
  57. namespace ocl {
  58. enum
  59. {
  60. noType = -1
  61. };
  62. /////////////////////////////////////////////////////////////////////////////////////////////////
  63. // warpAffine & warpPerspective
  64. PARAM_TEST_CASE(WarpTestBase, MatType, Interpolation, bool, bool)
  65. {
  66. int type, interpolation;
  67. Size dsize;
  68. bool useRoi, mapInverse;
  69. int depth;
  70. TEST_DECLARE_INPUT_PARAMETER(src);
  71. TEST_DECLARE_OUTPUT_PARAMETER(dst);
  72. virtual void SetUp()
  73. {
  74. type = GET_PARAM(0);
  75. interpolation = GET_PARAM(1);
  76. mapInverse = GET_PARAM(2);
  77. useRoi = GET_PARAM(3);
  78. depth = CV_MAT_DEPTH(type);
  79. if (mapInverse)
  80. interpolation |= WARP_INVERSE_MAP;
  81. }
  82. void random_roi()
  83. {
  84. dsize = randomSize(1, MAX_VALUE);
  85. Size roiSize = randomSize(1, MAX_VALUE);
  86. Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  87. randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
  88. Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  89. randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
  90. UMAT_UPLOAD_INPUT_PARAMETER(src);
  91. UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
  92. }
  93. void Near(double threshold = 0.0)
  94. {
  95. if (depth < CV_32F)
  96. EXPECT_MAT_N_DIFF(dst_roi, udst_roi, cvRound(dst_roi.total()*threshold));
  97. else
  98. OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
  99. }
  100. };
  101. PARAM_TEST_CASE(WarpTest_cols4_Base, MatType, Interpolation, bool, bool)
  102. {
  103. int type, interpolation;
  104. Size dsize;
  105. bool useRoi, mapInverse;
  106. int depth;
  107. TEST_DECLARE_INPUT_PARAMETER(src);
  108. TEST_DECLARE_OUTPUT_PARAMETER(dst);
  109. virtual void SetUp()
  110. {
  111. type = GET_PARAM(0);
  112. interpolation = GET_PARAM(1);
  113. mapInverse = GET_PARAM(2);
  114. useRoi = GET_PARAM(3);
  115. depth = CV_MAT_DEPTH(type);
  116. if (mapInverse)
  117. interpolation |= WARP_INVERSE_MAP;
  118. }
  119. void random_roi()
  120. {
  121. dsize = randomSize(1, MAX_VALUE);
  122. dsize.width = ((dsize.width >> 2) + 1) * 4;
  123. Size roiSize = randomSize(1, MAX_VALUE);
  124. Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  125. randomSubMat(src, src_roi, roiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
  126. Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  127. randomSubMat(dst, dst_roi, dsize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
  128. UMAT_UPLOAD_INPUT_PARAMETER(src);
  129. UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
  130. }
  131. void Near(double threshold = 0.0)
  132. {
  133. if (depth < CV_32F)
  134. EXPECT_MAT_N_DIFF(dst_roi, udst_roi, cvRound(dst_roi.total()*threshold));
  135. else
  136. OCL_EXPECT_MATS_NEAR_RELATIVE(dst, threshold);
  137. }
  138. };
  139. /////warpAffine
  140. typedef WarpTestBase WarpAffine;
  141. /////warpAffine
  142. typedef WarpTestBase WarpAffine;
  143. OCL_TEST_P(WarpAffine, Mat)
  144. {
  145. for (int j = 0; j < test_loop_times; j++)
  146. {
  147. double eps = depth < CV_32F ? 0.04 : 0.06;
  148. random_roi();
  149. Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
  150. rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
  151. OCL_OFF(cv::warpAffine(src_roi, dst_roi, M, dsize, interpolation));
  152. OCL_ON(cv::warpAffine(usrc_roi, udst_roi, M, dsize, interpolation));
  153. Near(eps);
  154. }
  155. }
  156. typedef WarpTest_cols4_Base WarpAffine_cols4;
  157. OCL_TEST_P(WarpAffine_cols4, Mat)
  158. {
  159. for (int j = 0; j < test_loop_times; j++)
  160. {
  161. double eps = depth < CV_32F ? 0.04 : 0.06;
  162. random_roi();
  163. Mat M = getRotationMatrix2D(Point2f(src_roi.cols / 2.0f, src_roi.rows / 2.0f),
  164. rng.uniform(-180.f, 180.f), rng.uniform(0.4f, 2.0f));
  165. OCL_OFF(cv::warpAffine(src_roi, dst_roi, M, dsize, interpolation));
  166. OCL_ON(cv::warpAffine(usrc_roi, udst_roi, M, dsize, interpolation));
  167. Near(eps);
  168. }
  169. }
  170. //// warpPerspective
  171. typedef WarpTestBase WarpPerspective;
  172. OCL_TEST_P(WarpPerspective, Mat)
  173. {
  174. for (int j = 0; j < test_loop_times; j++)
  175. {
  176. double eps = depth < CV_32F ? 0.03 : 0.06;
  177. random_roi();
  178. float cols = static_cast<float>(src_roi.cols), rows = static_cast<float>(src_roi.rows);
  179. float cols2 = cols / 2.0f, rows2 = rows / 2.0f;
  180. Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
  181. Point2f dp[] = { Point2f(rng.uniform(0.0f, cols2), rng.uniform(0.0f, rows2)),
  182. Point2f(rng.uniform(cols2, cols), rng.uniform(0.0f, rows2)),
  183. Point2f(rng.uniform(0.0f, cols2), rng.uniform(rows2, rows)),
  184. Point2f(rng.uniform(cols2, cols), rng.uniform(rows2, rows)) };
  185. Mat M = getPerspectiveTransform(sp, dp);
  186. OCL_OFF(cv::warpPerspective(src_roi, dst_roi, M, dsize, interpolation));
  187. OCL_ON(cv::warpPerspective(usrc_roi, udst_roi, M, dsize, interpolation));
  188. Near(eps);
  189. }
  190. }
  191. typedef WarpTest_cols4_Base WarpPerspective_cols4;
  192. OCL_TEST_P(WarpPerspective_cols4, Mat)
  193. {
  194. for (int j = 0; j < test_loop_times; j++)
  195. {
  196. double eps = depth < CV_32F ? 0.03 : 0.06;
  197. random_roi();
  198. float cols = static_cast<float>(src_roi.cols), rows = static_cast<float>(src_roi.rows);
  199. float cols2 = cols / 2.0f, rows2 = rows / 2.0f;
  200. Point2f sp[] = { Point2f(0.0f, 0.0f), Point2f(cols, 0.0f), Point2f(0.0f, rows), Point2f(cols, rows) };
  201. Point2f dp[] = { Point2f(rng.uniform(0.0f, cols2), rng.uniform(0.0f, rows2)),
  202. Point2f(rng.uniform(cols2, cols), rng.uniform(0.0f, rows2)),
  203. Point2f(rng.uniform(0.0f, cols2), rng.uniform(rows2, rows)),
  204. Point2f(rng.uniform(cols2, cols), rng.uniform(rows2, rows)) };
  205. Mat M = getPerspectiveTransform(sp, dp);
  206. OCL_OFF(cv::warpPerspective(src_roi, dst_roi, M, dsize, interpolation));
  207. OCL_ON(cv::warpPerspective(usrc_roi, udst_roi, M, dsize, interpolation));
  208. Near(eps);
  209. }
  210. }
  211. /////////////////////////////////////////////////////////////////////////////////////////////////
  212. //// resize
  213. PARAM_TEST_CASE(Resize, MatType, double, double, Interpolation, bool, int)
  214. {
  215. int type, interpolation;
  216. int widthMultiple;
  217. double fx, fy;
  218. bool useRoi;
  219. TEST_DECLARE_INPUT_PARAMETER(src);
  220. TEST_DECLARE_OUTPUT_PARAMETER(dst);
  221. virtual void SetUp()
  222. {
  223. type = GET_PARAM(0);
  224. fx = GET_PARAM(1);
  225. fy = GET_PARAM(2);
  226. interpolation = GET_PARAM(3);
  227. useRoi = GET_PARAM(4);
  228. widthMultiple = GET_PARAM(5);
  229. }
  230. void random_roi()
  231. {
  232. CV_Assert(fx > 0 && fy > 0);
  233. Size srcRoiSize = randomSize(10, MAX_VALUE), dstRoiSize;
  234. // Make sure the width is a multiple of the requested value, and no more
  235. srcRoiSize.width += widthMultiple - 1 - (srcRoiSize.width - 1) % widthMultiple;
  236. dstRoiSize.width = cvRound(srcRoiSize.width * fx);
  237. dstRoiSize.height = cvRound(srcRoiSize.height * fy);
  238. if (dstRoiSize.empty())
  239. {
  240. random_roi();
  241. return;
  242. }
  243. Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  244. randomSubMat(src, src_roi, srcRoiSize, srcBorder, type, -MAX_VALUE, MAX_VALUE);
  245. Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  246. randomSubMat(dst, dst_roi, dstRoiSize, dstBorder, type, -MAX_VALUE, MAX_VALUE);
  247. UMAT_UPLOAD_INPUT_PARAMETER(src);
  248. UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
  249. }
  250. };
  251. #if defined(__aarch64__) || defined(__arm__)
  252. const int integerEps = 3;
  253. #else
  254. const int integerEps = 1;
  255. #endif
  256. OCL_TEST_P(Resize, Mat)
  257. {
  258. for (int j = 0; j < test_loop_times; j++)
  259. {
  260. int depth = CV_MAT_DEPTH(type);
  261. double eps = depth <= CV_32S ? integerEps : 5e-2;
  262. random_roi();
  263. OCL_OFF(cv::resize(src_roi, dst_roi, Size(), fx, fy, interpolation));
  264. OCL_ON(cv::resize(usrc_roi, udst_roi, Size(), fx, fy, interpolation));
  265. OCL_EXPECT_MAT_N_DIFF(dst, eps);
  266. }
  267. }
  268. OCL_TEST(Resize, overflow_21198)
  269. {
  270. Mat src(Size(600, 600), CV_16UC3, Scalar::all(32768));
  271. UMat src_u;
  272. src.copyTo(src_u);
  273. Mat dst;
  274. cv::resize(src, dst, Size(1024, 1024), 0, 0, INTER_LINEAR);
  275. UMat dst_u;
  276. cv::resize(src_u, dst_u, Size(1024, 1024), 0, 0, INTER_LINEAR);
  277. EXPECT_LE(cv::norm(dst_u, dst, NORM_INF), 1.0f);
  278. }
  279. /////////////////////////////////////////////////////////////////////////////////////////////////
  280. // remap
  281. PARAM_TEST_CASE(Remap, MatDepth, Channels, std::pair<MatType, MatType>, BorderType, bool)
  282. {
  283. int srcType, map1Type, map2Type;
  284. int borderType;
  285. bool useRoi;
  286. Scalar val;
  287. TEST_DECLARE_INPUT_PARAMETER(src);
  288. TEST_DECLARE_INPUT_PARAMETER(map1);
  289. TEST_DECLARE_INPUT_PARAMETER(map2);
  290. TEST_DECLARE_OUTPUT_PARAMETER(dst);
  291. virtual void SetUp()
  292. {
  293. srcType = CV_MAKE_TYPE(GET_PARAM(0), GET_PARAM(1));
  294. map1Type = GET_PARAM(2).first;
  295. map2Type = GET_PARAM(2).second;
  296. borderType = GET_PARAM(3);
  297. useRoi = GET_PARAM(4);
  298. }
  299. void random_roi()
  300. {
  301. val = randomScalar(-MAX_VALUE, MAX_VALUE);
  302. Size srcROISize = randomSize(1, MAX_VALUE);
  303. Size dstROISize = randomSize(1, MAX_VALUE);
  304. Border srcBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  305. randomSubMat(src, src_roi, srcROISize, srcBorder, srcType, 5, 256);
  306. Border dstBorder = randomBorder(0, useRoi ? MAX_VALUE : 0);
  307. randomSubMat(dst, dst_roi, dstROISize, dstBorder, srcType, -MAX_VALUE, MAX_VALUE);
  308. int mapMaxValue = MAX_VALUE << 2;
  309. Border map1Border = randomBorder(0, useRoi ? MAX_VALUE : 0);
  310. randomSubMat(map1, map1_roi, dstROISize, map1Border, map1Type, -mapMaxValue, mapMaxValue);
  311. Border map2Border = randomBorder(0, useRoi ? MAX_VALUE + 1 : 0);
  312. if (map2Type != noType)
  313. {
  314. int mapMinValue = -mapMaxValue;
  315. if (map2Type == CV_16UC1 || map2Type == CV_16SC1)
  316. mapMinValue = 0, mapMaxValue = INTER_TAB_SIZE2;
  317. randomSubMat(map2, map2_roi, dstROISize, map2Border, map2Type, mapMinValue, mapMaxValue);
  318. }
  319. UMAT_UPLOAD_INPUT_PARAMETER(src);
  320. UMAT_UPLOAD_INPUT_PARAMETER(map1);
  321. UMAT_UPLOAD_OUTPUT_PARAMETER(dst);
  322. if (noType != map2Type)
  323. UMAT_UPLOAD_INPUT_PARAMETER(map2);
  324. }
  325. };
  326. typedef Remap Remap_INTER_NEAREST;
  327. OCL_TEST_P(Remap_INTER_NEAREST, Mat)
  328. {
  329. for (int j = 0; j < test_loop_times; j++)
  330. {
  331. random_roi();
  332. OCL_OFF(cv::remap(src_roi, dst_roi, map1_roi, map2_roi, INTER_NEAREST, borderType, val));
  333. OCL_ON(cv::remap(usrc_roi, udst_roi, umap1_roi, umap2_roi, INTER_NEAREST, borderType, val));
  334. OCL_EXPECT_MAT_N_DIFF(dst, 1.0);
  335. }
  336. }
  337. typedef Remap Remap_INTER_LINEAR;
  338. OCL_TEST_P(Remap_INTER_LINEAR, Mat)
  339. {
  340. for (int j = 0; j < test_loop_times; j++)
  341. {
  342. random_roi();
  343. double eps = 2.0;
  344. #ifdef __ANDROID__
  345. // TODO investigate accuracy
  346. if (cv::ocl::Device::getDefault().isNVidia())
  347. eps = 8.0;
  348. #elif defined(__arm__)
  349. eps = 8.0;
  350. #endif
  351. OCL_OFF(cv::remap(src_roi, dst_roi, map1_roi, map2_roi, INTER_LINEAR, borderType, val));
  352. OCL_ON(cv::remap(usrc_roi, udst_roi, umap1_roi, umap2_roi, INTER_LINEAR, borderType, val));
  353. OCL_EXPECT_MAT_N_DIFF(dst, eps);
  354. }
  355. }
  356. /////////////////////////////////////////////////////////////////////////////////////
  357. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine, Combine(
  358. Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
  359. Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
  360. Bool(),
  361. Bool()));
  362. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpAffine_cols4, Combine(
  363. Values((MatType)CV_8UC1),
  364. Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
  365. Bool(),
  366. Bool()));
  367. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective, Combine(
  368. Values(CV_8UC1, CV_8UC3, CV_8UC4, CV_32FC1, CV_32FC3, CV_32FC4),
  369. Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
  370. Bool(),
  371. Bool()));
  372. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, WarpPerspective_cols4, Combine(
  373. Values((MatType)CV_8UC1),
  374. Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR, (Interpolation)INTER_CUBIC),
  375. Bool(),
  376. Bool()));
  377. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Resize, Combine(
  378. Values(CV_8UC1, CV_8UC4, CV_16UC2, CV_32FC1, CV_32FC4),
  379. Values(0.5, 1.5, 2.0, 0.2),
  380. Values(0.5, 1.5, 2.0, 0.2),
  381. Values((Interpolation)INTER_NEAREST, (Interpolation)INTER_LINEAR),
  382. Bool(),
  383. Values(1, 16)));
  384. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarpLinearExact, Resize, Combine(
  385. Values(CV_8UC1, CV_8UC4, CV_16UC2),
  386. Values(0.5, 1.5, 2.0, 0.2),
  387. Values(0.5, 1.5, 2.0, 0.2),
  388. Values((Interpolation)INTER_LINEAR_EXACT),
  389. Bool(),
  390. Values(1, 16)));
  391. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarpResizeArea, Resize, Combine(
  392. Values((MatType)CV_8UC1, CV_8UC4, CV_32FC1, CV_32FC4),
  393. Values(0.7, 0.4, 0.5),
  394. Values(0.3, 0.6, 0.5),
  395. Values((Interpolation)INTER_AREA),
  396. Bool(),
  397. Values(1, 16)));
  398. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Remap_INTER_LINEAR, Combine(
  399. Values(CV_8U, CV_16U, CV_32F),
  400. Values(1, 3, 4),
  401. Values(std::pair<MatType, MatType>((MatType)CV_32FC1, (MatType)CV_32FC1),
  402. std::pair<MatType, MatType>((MatType)CV_16SC2, (MatType)CV_16UC1),
  403. std::pair<MatType, MatType>((MatType)CV_32FC2, noType)),
  404. Values((BorderType)BORDER_CONSTANT,
  405. (BorderType)BORDER_REPLICATE,
  406. (BorderType)BORDER_WRAP,
  407. (BorderType)BORDER_REFLECT,
  408. (BorderType)BORDER_REFLECT_101),
  409. Bool()));
  410. OCL_INSTANTIATE_TEST_CASE_P(ImgprocWarp, Remap_INTER_NEAREST, Combine(
  411. Values(CV_8U, CV_16U, CV_32F),
  412. Values(1, 3, 4),
  413. Values(std::pair<MatType, MatType>((MatType)CV_32FC1, (MatType)CV_32FC1),
  414. std::pair<MatType, MatType>((MatType)CV_32FC2, noType),
  415. std::pair<MatType, MatType>((MatType)CV_16SC2, (MatType)CV_16UC1),
  416. std::pair<MatType, MatType>((MatType)CV_16SC2, noType)),
  417. Values((BorderType)BORDER_CONSTANT,
  418. (BorderType)BORDER_REPLICATE,
  419. (BorderType)BORDER_WRAP,
  420. (BorderType)BORDER_REFLECT,
  421. (BorderType)BORDER_REFLECT_101),
  422. Bool()));
  423. } } // namespace opencv_test::ocl
  424. #endif // HAVE_OPENCL