no_wrappers.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. #include <iostream>
  2. #include <stdexcept>
  3. //OpenVX includes
  4. #include <VX/vx.h>
  5. //OpenCV includes
  6. #include "opencv2/core.hpp"
  7. #include "opencv2/imgproc.hpp"
  8. #include "opencv2/imgcodecs.hpp"
  9. #include "opencv2/highgui.hpp"
  10. #ifndef VX_VERSION_1_1
  11. const vx_enum VX_IMAGE_FORMAT = VX_IMAGE_ATTRIBUTE_FORMAT;
  12. const vx_enum VX_IMAGE_WIDTH = VX_IMAGE_ATTRIBUTE_WIDTH;
  13. const vx_enum VX_IMAGE_HEIGHT = VX_IMAGE_ATTRIBUTE_HEIGHT;
  14. const vx_enum VX_MEMORY_TYPE_HOST = VX_IMPORT_TYPE_HOST;
  15. const vx_enum VX_MEMORY_TYPE_NONE = VX_IMPORT_TYPE_NONE;
  16. const vx_enum VX_THRESHOLD_THRESHOLD_VALUE = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_VALUE;
  17. const vx_enum VX_THRESHOLD_THRESHOLD_LOWER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER;
  18. const vx_enum VX_THRESHOLD_THRESHOLD_UPPER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER;
  19. typedef uintptr_t vx_map_id;
  20. #endif
  21. enum UserMemoryMode
  22. {
  23. COPY, USER_MEM
  24. };
  25. vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy);
  26. cv::Mat copyVxImageToCvMat(vx_image ovxImage);
  27. void swapVxImage(vx_image ovxImage);
  28. vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph);
  29. int ovxDemo(std::string inputPath, UserMemoryMode mode);
  30. vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy)
  31. {
  32. if (!(!image.empty() && image.dims <= 2 && image.channels() == 1))
  33. throw std::runtime_error("Invalid format");
  34. vx_uint32 width = image.cols;
  35. vx_uint32 height = image.rows;
  36. vx_df_image color;
  37. switch (image.depth())
  38. {
  39. case CV_8U:
  40. color = VX_DF_IMAGE_U8;
  41. break;
  42. case CV_16U:
  43. color = VX_DF_IMAGE_U16;
  44. break;
  45. case CV_16S:
  46. color = VX_DF_IMAGE_S16;
  47. break;
  48. case CV_32S:
  49. color = VX_DF_IMAGE_S32;
  50. break;
  51. default:
  52. throw std::runtime_error("Invalid format");
  53. break;
  54. }
  55. vx_imagepatch_addressing_t addr;
  56. addr.dim_x = width;
  57. addr.dim_y = height;
  58. addr.stride_x = (vx_uint32)image.elemSize();
  59. addr.stride_y = (vx_uint32)image.step.p[0];
  60. vx_uint8* ovxData = image.data;
  61. vx_image ovxImage;
  62. if (toCopy)
  63. {
  64. ovxImage = vxCreateImage(context, width, height, color);
  65. if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS)
  66. throw std::runtime_error("Failed to create image");
  67. vx_rectangle_t rect;
  68. vx_status status = vxGetValidRegionImage(ovxImage, &rect);
  69. if (status != VX_SUCCESS)
  70. throw std::runtime_error("Failed to get valid region");
  71. #ifdef VX_VERSION_1_1
  72. status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, ovxData, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
  73. if (status != VX_SUCCESS)
  74. throw std::runtime_error("Failed to copy image patch");
  75. #else
  76. status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&ovxData, VX_WRITE_ONLY);
  77. if (status != VX_SUCCESS)
  78. throw std::runtime_error("Failed to access image patch");
  79. status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, ovxData);
  80. if (status != VX_SUCCESS)
  81. throw std::runtime_error("Failed to commit image patch");
  82. #endif
  83. }
  84. else
  85. {
  86. ovxImage = vxCreateImageFromHandle(context, color, &addr, (void**)&ovxData, VX_MEMORY_TYPE_HOST);
  87. if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS)
  88. throw std::runtime_error("Failed to create image from handle");
  89. }
  90. return ovxImage;
  91. }
  92. cv::Mat copyVxImageToCvMat(vx_image ovxImage)
  93. {
  94. vx_status status;
  95. vx_df_image df_image = 0;
  96. vx_uint32 width, height;
  97. status = vxQueryImage(ovxImage, VX_IMAGE_FORMAT, &df_image, sizeof(vx_df_image));
  98. if (status != VX_SUCCESS)
  99. throw std::runtime_error("Failed to query image");
  100. status = vxQueryImage(ovxImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
  101. if (status != VX_SUCCESS)
  102. throw std::runtime_error("Failed to query image");
  103. status = vxQueryImage(ovxImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
  104. if (status != VX_SUCCESS)
  105. throw std::runtime_error("Failed to query image");
  106. if (!(width > 0 && height > 0)) throw std::runtime_error("Invalid format");
  107. int depth;
  108. switch (df_image)
  109. {
  110. case VX_DF_IMAGE_U8:
  111. depth = CV_8U;
  112. break;
  113. case VX_DF_IMAGE_U16:
  114. depth = CV_16U;
  115. break;
  116. case VX_DF_IMAGE_S16:
  117. depth = CV_16S;
  118. break;
  119. case VX_DF_IMAGE_S32:
  120. depth = CV_32S;
  121. break;
  122. default:
  123. throw std::runtime_error("Invalid format");
  124. break;
  125. }
  126. cv::Mat image(height, width, CV_MAKE_TYPE(depth, 1));
  127. vx_rectangle_t rect;
  128. rect.start_x = rect.start_y = 0;
  129. rect.end_x = width; rect.end_y = height;
  130. vx_imagepatch_addressing_t addr;
  131. addr.dim_x = width;
  132. addr.dim_y = height;
  133. addr.stride_x = (vx_uint32)image.elemSize();
  134. addr.stride_y = (vx_uint32)image.step.p[0];
  135. vx_uint8* matData = image.data;
  136. #ifdef VX_VERSION_1_1
  137. status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, matData, VX_READ_ONLY, VX_MEMORY_TYPE_HOST);
  138. if (status != VX_SUCCESS)
  139. throw std::runtime_error("Failed to copy image patch");
  140. #else
  141. status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&matData, VX_READ_ONLY);
  142. if (status != VX_SUCCESS)
  143. throw std::runtime_error("Failed to access image patch");
  144. status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, matData);
  145. if (status != VX_SUCCESS)
  146. throw std::runtime_error("Failed to commit image patch");
  147. #endif
  148. return image;
  149. }
  150. void swapVxImage(vx_image ovxImage)
  151. {
  152. #ifdef VX_VERSION_1_1
  153. vx_status status;
  154. vx_memory_type_e memType;
  155. status = vxQueryImage(ovxImage, VX_IMAGE_MEMORY_TYPE, &memType, sizeof(vx_memory_type_e));
  156. if (status != VX_SUCCESS)
  157. throw std::runtime_error("Failed to query image");
  158. if (memType == VX_MEMORY_TYPE_NONE)
  159. {
  160. //was created by copying user data
  161. throw std::runtime_error("Image wasn't created from user handle");
  162. }
  163. else
  164. {
  165. //was created from user handle
  166. status = vxSwapImageHandle(ovxImage, NULL, NULL, 0);
  167. if (status != VX_SUCCESS)
  168. throw std::runtime_error("Failed to swap image handle");
  169. }
  170. #else
  171. //not supported until OpenVX 1.1
  172. (void) ovxImage;
  173. #endif
  174. }
  175. vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph)
  176. {
  177. vx_status status;
  178. vx_context context = vxGetContext((vx_reference)inputImage);
  179. status = vxGetStatus((vx_reference)context);
  180. if(status != VX_SUCCESS) return status;
  181. graph = vxCreateGraph(context);
  182. status = vxGetStatus((vx_reference)graph);
  183. if (status != VX_SUCCESS) return status;
  184. vx_uint32 width, height;
  185. status = vxQueryImage(inputImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
  186. if (status != VX_SUCCESS) return status;
  187. status = vxQueryImage(inputImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
  188. if (status != VX_SUCCESS) return status;
  189. // Intermediate images
  190. vx_image
  191. smoothed = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT),
  192. cannied = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT),
  193. halfImg = vxCreateImage(context, width, height, VX_DF_IMAGE_U8),
  194. halfCanny = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
  195. vx_image virtualImages[] = {smoothed, cannied, halfImg, halfCanny};
  196. for(size_t i = 0; i < sizeof(virtualImages)/sizeof(vx_image); i++)
  197. {
  198. status = vxGetStatus((vx_reference)virtualImages[i]);
  199. if (status != VX_SUCCESS) return status;
  200. }
  201. // Constants
  202. vx_uint32 threshValue = 50;
  203. vx_threshold thresh = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8);
  204. vxSetThresholdAttribute(thresh, VX_THRESHOLD_THRESHOLD_VALUE,
  205. &threshValue, sizeof(threshValue));
  206. vx_uint32 threshCannyMin = 127;
  207. vx_uint32 threshCannyMax = 192;
  208. vx_threshold threshCanny = vxCreateThreshold(context, VX_THRESHOLD_TYPE_RANGE, VX_TYPE_UINT8);
  209. vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_LOWER, &threshCannyMin,
  210. sizeof(threshCannyMin));
  211. vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_UPPER, &threshCannyMax,
  212. sizeof(threshCannyMax));
  213. vx_float32 alphaValue = 0.5;
  214. vx_scalar alpha = vxCreateScalar(context, VX_TYPE_FLOAT32, &alphaValue);
  215. // Sequence of meaningless image operations
  216. vx_node nodes[] = {
  217. vxGaussian3x3Node(graph, inputImage, smoothed),
  218. vxCannyEdgeDetectorNode(graph, smoothed, threshCanny, 3, VX_NORM_L2, cannied),
  219. vxAccumulateWeightedImageNode(graph, inputImage, alpha, halfImg),
  220. vxAccumulateWeightedImageNode(graph, cannied, alpha, halfCanny),
  221. vxAddNode(graph, halfImg, halfCanny, VX_CONVERT_POLICY_SATURATE, outputImage)
  222. };
  223. for (size_t i = 0; i < sizeof(nodes) / sizeof(vx_node); i++)
  224. {
  225. status = vxGetStatus((vx_reference)nodes[i]);
  226. if (status != VX_SUCCESS) return status;
  227. }
  228. status = vxVerifyGraph(graph);
  229. return status;
  230. }
  231. int ovxDemo(std::string inputPath, UserMemoryMode mode)
  232. {
  233. cv::Mat image = cv::imread(inputPath, cv::IMREAD_GRAYSCALE);
  234. if (image.empty()) return -1;
  235. //check image format
  236. if (image.depth() != CV_8U || image.channels() != 1) return -1;
  237. vx_status status;
  238. vx_context context = vxCreateContext();
  239. status = vxGetStatus((vx_reference)context);
  240. if (status != VX_SUCCESS) return status;
  241. //put user data from cv::Mat to vx_image
  242. vx_image ovxImage;
  243. ovxImage = convertCvMatToVxImage(context, image, mode == COPY);
  244. vx_uint32 width = image.cols, height = image.rows;
  245. vx_image ovxResult;
  246. cv::Mat output;
  247. if (mode == COPY)
  248. {
  249. //we will copy data from vx_image to cv::Mat
  250. ovxResult = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
  251. if (vxGetStatus((vx_reference)ovxResult) != VX_SUCCESS)
  252. throw std::runtime_error("Failed to create image");
  253. }
  254. else
  255. {
  256. //create vx_image based on user data, no copying required
  257. output = cv::Mat(height, width, CV_8U, cv::Scalar(0));
  258. ovxResult = convertCvMatToVxImage(context, output, false);
  259. }
  260. vx_graph graph;
  261. status = createProcessingGraph(ovxImage, ovxResult, graph);
  262. if (status != VX_SUCCESS) return status;
  263. // Graph execution
  264. status = vxProcessGraph(graph);
  265. if (status != VX_SUCCESS) return status;
  266. //getting resulting image in cv::Mat
  267. if (mode == COPY)
  268. {
  269. output = copyVxImageToCvMat(ovxResult);
  270. }
  271. else
  272. {
  273. //we should take user memory back from vx_image before using it (even before reading)
  274. swapVxImage(ovxResult);
  275. }
  276. //here output goes
  277. cv::imshow("processing result", output);
  278. cv::waitKey(0);
  279. //we need to take user memory back before releasing the image
  280. if (mode == USER_MEM)
  281. swapVxImage(ovxImage);
  282. cv::destroyAllWindows();
  283. status = vxReleaseContext(&context);
  284. return status;
  285. }
  286. int main(int argc, char *argv[])
  287. {
  288. const std::string keys =
  289. "{help h usage ? | | }"
  290. "{image | <none> | image to be processed}"
  291. "{mode | copy | user memory interaction mode: \n"
  292. "copy: create VX images and copy data to/from them\n"
  293. "user_mem: use handles to user-allocated memory}"
  294. ;
  295. cv::CommandLineParser parser(argc, argv, keys);
  296. parser.about("OpenVX interoperability sample demonstrating standard OpenVX API."
  297. "The application loads an image, processes it with OpenVX graph and outputs result in a window");
  298. if (parser.has("help"))
  299. {
  300. parser.printMessage();
  301. return 0;
  302. }
  303. std::string imgPath = parser.get<std::string>("image");
  304. std::string modeString = parser.get<std::string>("mode");
  305. UserMemoryMode mode;
  306. if(modeString == "copy")
  307. {
  308. mode = COPY;
  309. }
  310. else if(modeString == "user_mem")
  311. {
  312. mode = USER_MEM;
  313. }
  314. else if(modeString == "map")
  315. {
  316. std::cerr << modeString << " is not implemented in this sample" << std::endl;
  317. return -1;
  318. }
  319. else
  320. {
  321. std::cerr << modeString << ": unknown memory mode" << std::endl;
  322. return -1;
  323. }
  324. if (!parser.check())
  325. {
  326. parser.printErrors();
  327. return -1;
  328. }
  329. return ovxDemo(imgPath, mode);
  330. }