test_gapi_sample_pipelines.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681
  1. #!/usr/bin/env python
  2. import numpy as np
  3. import cv2 as cv
  4. import os
  5. import sys
  6. import unittest
  7. from tests_common import NewOpenCVTests
  8. try:
  9. if sys.version_info[:2] < (3, 0):
  10. raise unittest.SkipTest('Python 2.x is not supported')
  11. # Plaidml is an optional backend
  12. pkgs = [
  13. ('ocl' , cv.gapi.core.ocl.kernels()),
  14. ('cpu' , cv.gapi.core.cpu.kernels()),
  15. ('fluid' , cv.gapi.core.fluid.kernels())
  16. # ('plaidml', cv.gapi.core.plaidml.kernels())
  17. ]
  18. @cv.gapi.op('custom.add', in_types=[cv.GMat, cv.GMat, int], out_types=[cv.GMat])
  19. class GAdd:
  20. """Calculates sum of two matrices."""
  21. @staticmethod
  22. def outMeta(desc1, desc2, depth):
  23. return desc1
  24. @cv.gapi.kernel(GAdd)
  25. class GAddImpl:
  26. """Implementation for GAdd operation."""
  27. @staticmethod
  28. def run(img1, img2, dtype):
  29. return cv.add(img1, img2)
  30. @cv.gapi.op('custom.split3', in_types=[cv.GMat], out_types=[cv.GMat, cv.GMat, cv.GMat])
  31. class GSplit3:
  32. """Divides a 3-channel matrix into 3 single-channel matrices."""
  33. @staticmethod
  34. def outMeta(desc):
  35. out_desc = desc.withType(desc.depth, 1)
  36. return out_desc, out_desc, out_desc
  37. @cv.gapi.kernel(GSplit3)
  38. class GSplit3Impl:
  39. """Implementation for GSplit3 operation."""
  40. @staticmethod
  41. def run(img):
  42. # NB: cv.split return list but g-api requires tuple in multiple output case
  43. return tuple(cv.split(img))
  44. @cv.gapi.op('custom.mean', in_types=[cv.GMat], out_types=[cv.GScalar])
  45. class GMean:
  46. """Calculates the mean value M of matrix elements."""
  47. @staticmethod
  48. def outMeta(desc):
  49. return cv.empty_scalar_desc()
  50. @cv.gapi.kernel(GMean)
  51. class GMeanImpl:
  52. """Implementation for GMean operation."""
  53. @staticmethod
  54. def run(img):
  55. # NB: cv.split return list but g-api requires tuple in multiple output case
  56. return cv.mean(img)
  57. @cv.gapi.op('custom.addC', in_types=[cv.GMat, cv.GScalar, int], out_types=[cv.GMat])
  58. class GAddC:
  59. """Adds a given scalar value to each element of given matrix."""
  60. @staticmethod
  61. def outMeta(mat_desc, scalar_desc, dtype):
  62. return mat_desc
  63. @cv.gapi.kernel(GAddC)
  64. class GAddCImpl:
  65. """Implementation for GAddC operation."""
  66. @staticmethod
  67. def run(img, sc, dtype):
  68. # NB: dtype is just ignored in this implementation.
  69. # Moreover from G-API kernel got scalar as tuples with 4 elements
  70. # where the last element is equal to zero, just cut him for broadcasting.
  71. return img + np.array(sc, dtype=np.uint8)[:-1]
  72. @cv.gapi.op('custom.size', in_types=[cv.GMat], out_types=[cv.GOpaque.Size])
  73. class GSize:
  74. """Gets dimensions from input matrix."""
  75. @staticmethod
  76. def outMeta(mat_desc):
  77. return cv.empty_gopaque_desc()
  78. @cv.gapi.kernel(GSize)
  79. class GSizeImpl:
  80. """Implementation for GSize operation."""
  81. @staticmethod
  82. def run(img):
  83. # NB: Take only H, W, because the operation should return cv::Size which is 2D.
  84. return img.shape[:2]
  85. @cv.gapi.op('custom.sizeR', in_types=[cv.GOpaque.Rect], out_types=[cv.GOpaque.Size])
  86. class GSizeR:
  87. """Gets dimensions from rectangle."""
  88. @staticmethod
  89. def outMeta(opaq_desc):
  90. return cv.empty_gopaque_desc()
  91. @cv.gapi.kernel(GSizeR)
  92. class GSizeRImpl:
  93. """Implementation for GSizeR operation."""
  94. @staticmethod
  95. def run(rect):
  96. # NB: rect - is tuple (x, y, h, w)
  97. return (rect[2], rect[3])
  98. @cv.gapi.op('custom.boundingRect', in_types=[cv.GArray.Point], out_types=[cv.GOpaque.Rect])
  99. class GBoundingRect:
  100. """Calculates minimal up-right bounding rectangle for the specified
  101. 9 point set or non-zero pixels of gray-scale image."""
  102. @staticmethod
  103. def outMeta(arr_desc):
  104. return cv.empty_gopaque_desc()
  105. @cv.gapi.kernel(GBoundingRect)
  106. class GBoundingRectImpl:
  107. """Implementation for GBoundingRect operation."""
  108. @staticmethod
  109. def run(array):
  110. # NB: OpenCV - numpy array (n_points x 2).
  111. # G-API - array of tuples (n_points).
  112. return cv.boundingRect(np.array(array))
  113. @cv.gapi.op('custom.goodFeaturesToTrack',
  114. in_types=[cv.GMat, int, float, float, int, bool, float],
  115. out_types=[cv.GArray.Point2f])
  116. class GGoodFeatures:
  117. """Finds the most prominent corners in the image
  118. or in the specified image region."""
  119. @staticmethod
  120. def outMeta(desc, max_corners, quality_lvl,
  121. min_distance, block_sz,
  122. use_harris_detector, k):
  123. return cv.empty_array_desc()
  124. @cv.gapi.kernel(GGoodFeatures)
  125. class GGoodFeaturesImpl:
  126. """Implementation for GGoodFeatures operation."""
  127. @staticmethod
  128. def run(img, max_corners, quality_lvl,
  129. min_distance, block_sz,
  130. use_harris_detector, k):
  131. features = cv.goodFeaturesToTrack(img, max_corners, quality_lvl,
  132. min_distance, mask=None,
  133. blockSize=block_sz,
  134. useHarrisDetector=use_harris_detector, k=k)
  135. # NB: The operation output is cv::GArray<cv::Pointf>, so it should be mapped
  136. # to python paramaters like this: [(1.2, 3.4), (5.2, 3.2)], because the cv::Point2f
  137. # according to opencv rules mapped to the tuple and cv::GArray<> mapped to the list.
  138. # OpenCV returns np.array with shape (n_features, 1, 2), so let's to convert it to list
  139. # tuples with size == n_features.
  140. features = list(map(tuple, features.reshape(features.shape[0], -1)))
  141. return features
  142. # To validate invalid cases
  143. def create_op(in_types, out_types):
  144. @cv.gapi.op('custom.op', in_types=in_types, out_types=out_types)
  145. class Op:
  146. """Custom operation for testing."""
  147. @staticmethod
  148. def outMeta(desc):
  149. raise NotImplementedError("outMeta isn't imlemented")
  150. return Op
  151. class gapi_sample_pipelines(NewOpenCVTests):
  152. def test_custom_op_add(self):
  153. sz = (3, 3)
  154. in_mat1 = np.full(sz, 45, dtype=np.uint8)
  155. in_mat2 = np.full(sz, 50, dtype=np.uint8)
  156. # OpenCV
  157. expected = cv.add(in_mat1, in_mat2)
  158. # G-API
  159. g_in1 = cv.GMat()
  160. g_in2 = cv.GMat()
  161. g_out = GAdd.on(g_in1, g_in2, cv.CV_8UC1)
  162. comp = cv.GComputation(cv.GIn(g_in1, g_in2), cv.GOut(g_out))
  163. pkg = cv.gapi.kernels(GAddImpl)
  164. actual = comp.apply(cv.gin(in_mat1, in_mat2), args=cv.gapi.compile_args(pkg))
  165. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  166. def test_custom_op_split3(self):
  167. sz = (4, 4)
  168. in_ch1 = np.full(sz, 1, dtype=np.uint8)
  169. in_ch2 = np.full(sz, 2, dtype=np.uint8)
  170. in_ch3 = np.full(sz, 3, dtype=np.uint8)
  171. # H x W x C
  172. in_mat = np.stack((in_ch1, in_ch2, in_ch3), axis=2)
  173. # G-API
  174. g_in = cv.GMat()
  175. g_ch1, g_ch2, g_ch3 = GSplit3.on(g_in)
  176. comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_ch1, g_ch2, g_ch3))
  177. pkg = cv.gapi.kernels(GSplit3Impl)
  178. ch1, ch2, ch3 = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
  179. self.assertEqual(0.0, cv.norm(in_ch1, ch1, cv.NORM_INF))
  180. self.assertEqual(0.0, cv.norm(in_ch2, ch2, cv.NORM_INF))
  181. self.assertEqual(0.0, cv.norm(in_ch3, ch3, cv.NORM_INF))
  182. def test_custom_op_mean(self):
  183. img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
  184. in_mat = cv.imread(img_path)
  185. # OpenCV
  186. expected = cv.mean(in_mat)
  187. # G-API
  188. g_in = cv.GMat()
  189. g_out = GMean.on(g_in)
  190. comp = cv.GComputation(g_in, g_out)
  191. pkg = cv.gapi.kernels(GMeanImpl)
  192. actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
  193. # Comparison
  194. self.assertEqual(expected, actual)
  195. def test_custom_op_addC(self):
  196. sz = (3, 3, 3)
  197. in_mat = np.full(sz, 45, dtype=np.uint8)
  198. sc = (50, 10, 20)
  199. # Numpy reference, make array from sc to keep uint8 dtype.
  200. expected = in_mat + np.array(sc, dtype=np.uint8)
  201. # G-API
  202. g_in = cv.GMat()
  203. g_sc = cv.GScalar()
  204. g_out = GAddC.on(g_in, g_sc, cv.CV_8UC1)
  205. comp = cv.GComputation(cv.GIn(g_in, g_sc), cv.GOut(g_out))
  206. pkg = cv.gapi.kernels(GAddCImpl)
  207. actual = comp.apply(cv.gin(in_mat, sc), args=cv.gapi.compile_args(pkg))
  208. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  209. def test_custom_op_size(self):
  210. sz = (100, 150, 3)
  211. in_mat = np.full(sz, 45, dtype=np.uint8)
  212. # Open_cV
  213. expected = (100, 150)
  214. # G-API
  215. g_in = cv.GMat()
  216. g_sz = GSize.on(g_in)
  217. comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_sz))
  218. pkg = cv.gapi.kernels(GSizeImpl)
  219. actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
  220. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  221. def test_custom_op_sizeR(self):
  222. # x, y, h, w
  223. roi = (10, 15, 100, 150)
  224. expected = (100, 150)
  225. # G-API
  226. g_r = cv.GOpaque.Rect()
  227. g_sz = GSizeR.on(g_r)
  228. comp = cv.GComputation(cv.GIn(g_r), cv.GOut(g_sz))
  229. pkg = cv.gapi.kernels(GSizeRImpl)
  230. actual = comp.apply(cv.gin(roi), args=cv.gapi.compile_args(pkg))
  231. # cv.norm works with tuples ?
  232. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  233. def test_custom_op_boundingRect(self):
  234. points = [(0,0), (0,1), (1,0), (1,1)]
  235. # OpenCV
  236. expected = cv.boundingRect(np.array(points))
  237. # G-API
  238. g_pts = cv.GArray.Point()
  239. g_br = GBoundingRect.on(g_pts)
  240. comp = cv.GComputation(cv.GIn(g_pts), cv.GOut(g_br))
  241. pkg = cv.gapi.kernels(GBoundingRectImpl)
  242. actual = comp.apply(cv.gin(points), args=cv.gapi.compile_args(pkg))
  243. # cv.norm works with tuples ?
  244. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  245. def test_custom_op_goodFeaturesToTrack(self):
  246. # G-API
  247. img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
  248. in_mat = cv.cvtColor(cv.imread(img_path), cv.COLOR_RGB2GRAY)
  249. # NB: goodFeaturesToTrack configuration
  250. max_corners = 50
  251. quality_lvl = 0.01
  252. min_distance = 10.0
  253. block_sz = 3
  254. use_harris_detector = True
  255. k = 0.04
  256. # OpenCV
  257. expected = cv.goodFeaturesToTrack(in_mat, max_corners, quality_lvl,
  258. min_distance, mask=None,
  259. blockSize=block_sz, useHarrisDetector=use_harris_detector, k=k)
  260. # G-API
  261. g_in = cv.GMat()
  262. g_out = GGoodFeatures.on(g_in, max_corners, quality_lvl,
  263. min_distance, block_sz, use_harris_detector, k)
  264. comp = cv.GComputation(cv.GIn(g_in), cv.GOut(g_out))
  265. pkg = cv.gapi.kernels(GGoodFeaturesImpl)
  266. actual = comp.apply(cv.gin(in_mat), args=cv.gapi.compile_args(pkg))
  267. # NB: OpenCV & G-API have different output types.
  268. # OpenCV - numpy array with shape (num_points, 1, 2)
  269. # G-API - list of tuples with size - num_points
  270. # Comparison
  271. self.assertEqual(0.0, cv.norm(expected.flatten(),
  272. np.array(actual, dtype=np.float32).flatten(), cv.NORM_INF))
  273. def test_invalid_op(self):
  274. # NB: Empty input types list
  275. with self.assertRaises(Exception): create_op(in_types=[], out_types=[cv.GMat])
  276. # NB: Empty output types list
  277. with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[])
  278. # Invalid output types
  279. with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[int])
  280. with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[cv.GMat, int])
  281. with self.assertRaises(Exception): create_op(in_types=[cv.GMat], out_types=[str, cv.GScalar])
  282. def test_invalid_op_input(self):
  283. # NB: Check GMat/GScalar
  284. with self.assertRaises(Exception): create_op([cv.GMat] , [cv.GScalar]).on(cv.GScalar())
  285. with self.assertRaises(Exception): create_op([cv.GScalar], [cv.GScalar]).on(cv.GMat())
  286. # NB: Check GOpaque
  287. op = create_op([cv.GOpaque.Rect], [cv.GMat])
  288. with self.assertRaises(Exception): op.on(cv.GOpaque.Bool())
  289. with self.assertRaises(Exception): op.on(cv.GOpaque.Int())
  290. with self.assertRaises(Exception): op.on(cv.GOpaque.Double())
  291. with self.assertRaises(Exception): op.on(cv.GOpaque.Float())
  292. with self.assertRaises(Exception): op.on(cv.GOpaque.String())
  293. with self.assertRaises(Exception): op.on(cv.GOpaque.Point())
  294. with self.assertRaises(Exception): op.on(cv.GOpaque.Point2f())
  295. with self.assertRaises(Exception): op.on(cv.GOpaque.Size())
  296. # NB: Check GArray
  297. op = create_op([cv.GArray.Rect], [cv.GMat])
  298. with self.assertRaises(Exception): op.on(cv.GArray.Bool())
  299. with self.assertRaises(Exception): op.on(cv.GArray.Int())
  300. with self.assertRaises(Exception): op.on(cv.GArray.Double())
  301. with self.assertRaises(Exception): op.on(cv.GArray.Float())
  302. with self.assertRaises(Exception): op.on(cv.GArray.String())
  303. with self.assertRaises(Exception): op.on(cv.GArray.Point())
  304. with self.assertRaises(Exception): op.on(cv.GArray.Point2f())
  305. with self.assertRaises(Exception): op.on(cv.GArray.Size())
  306. # Check other possible invalid options
  307. with self.assertRaises(Exception): op.on(cv.GMat())
  308. with self.assertRaises(Exception): op.on(cv.GScalar())
  309. with self.assertRaises(Exception): op.on(1)
  310. with self.assertRaises(Exception): op.on('foo')
  311. with self.assertRaises(Exception): op.on(False)
  312. with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat(), 'foo')
  313. with self.assertRaises(Exception): create_op([cv.GMat, int], [cv.GMat]).on(cv.GMat())
  314. def test_stateful_kernel(self):
  315. @cv.gapi.op('custom.sum', in_types=[cv.GArray.Int], out_types=[cv.GOpaque.Int])
  316. class GSum:
  317. @staticmethod
  318. def outMeta(arr_desc):
  319. return cv.empty_gopaque_desc()
  320. @cv.gapi.kernel(GSum)
  321. class GSumImpl:
  322. last_result = 0
  323. @staticmethod
  324. def run(arr):
  325. GSumImpl.last_result = sum(arr)
  326. return GSumImpl.last_result
  327. g_in = cv.GArray.Int()
  328. comp = cv.GComputation(cv.GIn(g_in), cv.GOut(GSum.on(g_in)))
  329. s = comp.apply(cv.gin([1, 2, 3, 4]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
  330. self.assertEqual(10, s)
  331. s = comp.apply(cv.gin([1, 2, 8, 7]), args=cv.gapi.compile_args(cv.gapi.kernels(GSumImpl)))
  332. self.assertEqual(18, s)
  333. self.assertEqual(18, GSumImpl.last_result)
  334. def test_opaq_with_custom_type(self):
  335. @cv.gapi.op('custom.op', in_types=[cv.GOpaque.Any, cv.GOpaque.String], out_types=[cv.GOpaque.Any])
  336. class GLookUp:
  337. @staticmethod
  338. def outMeta(opaq_desc0, opaq_desc1):
  339. return cv.empty_gopaque_desc()
  340. @cv.gapi.kernel(GLookUp)
  341. class GLookUpImpl:
  342. @staticmethod
  343. def run(table, key):
  344. return table[key]
  345. g_table = cv.GOpaque.Any()
  346. g_key = cv.GOpaque.String()
  347. g_out = GLookUp.on(g_table, g_key)
  348. comp = cv.GComputation(cv.GIn(g_table, g_key), cv.GOut(g_out))
  349. table = {
  350. 'int': 42,
  351. 'str': 'hello, world!',
  352. 'tuple': (42, 42)
  353. }
  354. out = comp.apply(cv.gin(table, 'int'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
  355. self.assertEqual(42, out)
  356. out = comp.apply(cv.gin(table, 'str'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
  357. self.assertEqual('hello, world!', out)
  358. out = comp.apply(cv.gin(table, 'tuple'), args=cv.gapi.compile_args(cv.gapi.kernels(GLookUpImpl)))
  359. self.assertEqual((42, 42), out)
  360. def test_array_with_custom_type(self):
  361. @cv.gapi.op('custom.op', in_types=[cv.GArray.Any, cv.GArray.Any], out_types=[cv.GArray.Any])
  362. class GConcat:
  363. @staticmethod
  364. def outMeta(arr_desc0, arr_desc1):
  365. return cv.empty_array_desc()
  366. @cv.gapi.kernel(GConcat)
  367. class GConcatImpl:
  368. @staticmethod
  369. def run(arr0, arr1):
  370. return arr0 + arr1
  371. g_arr0 = cv.GArray.Any()
  372. g_arr1 = cv.GArray.Any()
  373. g_out = GConcat.on(g_arr0, g_arr1)
  374. comp = cv.GComputation(cv.GIn(g_arr0, g_arr1), cv.GOut(g_out))
  375. arr0 = ((2, 2), 2.0)
  376. arr1 = (3, 'str')
  377. out = comp.apply(cv.gin(arr0, arr1),
  378. args=cv.gapi.compile_args(cv.gapi.kernels(GConcatImpl)))
  379. self.assertEqual(arr0 + arr1, out)
  380. def test_raise_in_kernel(self):
  381. @cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
  382. class GAdd:
  383. @staticmethod
  384. def outMeta(desc0, desc1):
  385. return desc0
  386. @cv.gapi.kernel(GAdd)
  387. class GAddImpl:
  388. @staticmethod
  389. def run(img0, img1):
  390. raise Exception('Error')
  391. return img0 + img1
  392. g_in0 = cv.GMat()
  393. g_in1 = cv.GMat()
  394. g_out = GAdd.on(g_in0, g_in1)
  395. comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
  396. img0 = np.array([1, 2, 3])
  397. img1 = np.array([1, 2, 3])
  398. with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
  399. args=cv.gapi.compile_args(
  400. cv.gapi.kernels(GAddImpl)))
  401. def test_raise_in_outMeta(self):
  402. @cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
  403. class GAdd:
  404. @staticmethod
  405. def outMeta(desc0, desc1):
  406. raise NotImplementedError("outMeta isn't implemented")
  407. @cv.gapi.kernel(GAdd)
  408. class GAddImpl:
  409. @staticmethod
  410. def run(img0, img1):
  411. return img0 + img1
  412. g_in0 = cv.GMat()
  413. g_in1 = cv.GMat()
  414. g_out = GAdd.on(g_in0, g_in1)
  415. comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
  416. img0 = np.array([1, 2, 3])
  417. img1 = np.array([1, 2, 3])
  418. with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
  419. args=cv.gapi.compile_args(
  420. cv.gapi.kernels(GAddImpl)))
  421. def test_invalid_outMeta(self):
  422. @cv.gapi.op('custom.op', in_types=[cv.GMat, cv.GMat], out_types=[cv.GMat])
  423. class GAdd:
  424. @staticmethod
  425. def outMeta(desc0, desc1):
  426. # Invalid outMeta
  427. return cv.empty_gopaque_desc()
  428. @cv.gapi.kernel(GAdd)
  429. class GAddImpl:
  430. @staticmethod
  431. def run(img0, img1):
  432. return img0 + img1
  433. g_in0 = cv.GMat()
  434. g_in1 = cv.GMat()
  435. g_out = GAdd.on(g_in0, g_in1)
  436. comp = cv.GComputation(cv.GIn(g_in0, g_in1), cv.GOut(g_out))
  437. img0 = np.array([1, 2, 3])
  438. img1 = np.array([1, 2, 3])
  439. # FIXME: Cause Bad variant access.
  440. # Need to provide more descriptive error messsage.
  441. with self.assertRaises(Exception): comp.apply(cv.gin(img0, img1),
  442. args=cv.gapi.compile_args(
  443. cv.gapi.kernels(GAddImpl)))
  444. def test_pipeline_with_custom_kernels(self):
  445. @cv.gapi.op('custom.resize', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
  446. class GResize:
  447. @staticmethod
  448. def outMeta(desc, size):
  449. return desc.withSize(size)
  450. @cv.gapi.kernel(GResize)
  451. class GResizeImpl:
  452. @staticmethod
  453. def run(img, size):
  454. return cv.resize(img, size)
  455. @cv.gapi.op('custom.transpose', in_types=[cv.GMat, tuple], out_types=[cv.GMat])
  456. class GTranspose:
  457. @staticmethod
  458. def outMeta(desc, order):
  459. return desc
  460. @cv.gapi.kernel(GTranspose)
  461. class GTransposeImpl:
  462. @staticmethod
  463. def run(img, order):
  464. return np.transpose(img, order)
  465. img_path = self.find_file('cv/face/david2.jpg', [os.environ.get('OPENCV_TEST_DATA_PATH')])
  466. img = cv.imread(img_path)
  467. size = (32, 32)
  468. order = (1, 0, 2)
  469. # Dummy pipeline just to validate this case:
  470. # gapi -> custom -> custom -> gapi
  471. # OpenCV
  472. expected = cv.cvtColor(img, cv.COLOR_BGR2RGB)
  473. expected = cv.resize(expected, size)
  474. expected = np.transpose(expected, order)
  475. expected = cv.mean(expected)
  476. # G-API
  477. g_bgr = cv.GMat()
  478. g_rgb = cv.gapi.BGR2RGB(g_bgr)
  479. g_resized = GResize.on(g_rgb, size)
  480. g_transposed = GTranspose.on(g_resized, order)
  481. g_mean = cv.gapi.mean(g_transposed)
  482. comp = cv.GComputation(cv.GIn(g_bgr), cv.GOut(g_mean))
  483. actual = comp.apply(cv.gin(img), args=cv.gapi.compile_args(
  484. cv.gapi.kernels(GResizeImpl, GTransposeImpl)))
  485. self.assertEqual(0.0, cv.norm(expected, actual, cv.NORM_INF))
  486. except unittest.SkipTest as e:
  487. message = str(e)
  488. class TestSkip(unittest.TestCase):
  489. def setUp(self):
  490. self.skipTest('Skip tests: ' + message)
  491. def test_skip():
  492. pass
  493. pass
  494. if __name__ == '__main__':
  495. NewOpenCVTests.bootstrap()