diff --git a/MODULE.bazel b/MODULE.bazel index 8ff586ac..84cc8fd4 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -8,10 +8,10 @@ module( ) # Import external dependencies -bazel_dep(name = "rules_cc", version = "0.1.0") +bazel_dep(name = "rules_cc", version = "0.1.1") bazel_dep(name = "rules_foreign_cc", version = "0.11.1") bazel_dep(name = "rules_python", version = "0.40.0") -bazel_dep(name = "platforms", version = "0.0.10") +bazel_dep(name = "platforms", version = "0.0.11") bazel_dep(name = "googletest", version = "1.15.2") bazel_dep(name = "apple_support", version = "1.17.1", repo_name = "build_bazel_apple_support") bazel_dep(name = "curl", version = "8.8.0") @@ -19,6 +19,7 @@ bazel_dep(name = "nlohmann_json", version = "3.11.3") bazel_dep(name = "hedron_compile_commands", dev_dependency = True) bazel_dep(name = "flatbuffers", version = "24.3.25") bazel_dep(name = "opentelemetry-cpp", version = "1.19.0") +bazel_dep(name = "opencv", version = "4.11.0.bcr.2") # Hedron's Compile Commands Extractor for Bazel git_override( diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index fe44bb0a..34ecf36d 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -69,6 +69,8 @@ "https://bcr.bazel.build/modules/curl/8.7.1/MODULE.bazel": "088221c35a2939c555e6e47cb31a81c15f8b59f4daa8009b1e9271a502d33485", "https://bcr.bazel.build/modules/curl/8.8.0/MODULE.bazel": "7da3b3e79b0b4ee8f8c95d640bc6ad7b430ce66ef6e9c9d2bc29b3b5ef85f6fe", "https://bcr.bazel.build/modules/curl/8.8.0/source.json": "d7d138b6878cf38891692fee0649ace35357fd549b425614d571786f054374d4", + "https://bcr.bazel.build/modules/eigen/4.0.0-20241125.bcr.2/MODULE.bazel": "c91e304c16bf95884333152b383a32aacdcfbde3b06f9f4908d31e6f60e44404", + "https://bcr.bazel.build/modules/eigen/4.0.0-20241125.bcr.2/source.json": "fbc35faefa352e7ab59a0175d809f05f2205712a34f06f3f52c807c8fe00267b", "https://bcr.bazel.build/modules/flatbuffers/24.3.25/MODULE.bazel": "2794b084ee385ecd08a22fd90614b93851508ceb7a97e63da399886dedbc696c", "https://bcr.bazel.build/modules/flatbuffers/24.3.25/source.json": "0cea4d62612a34154ffe0208a85f9f197edbb1f8f37a8855ec4aa722fea69276", "https://bcr.bazel.build/modules/gazelle/0.26.0/MODULE.bazel": "6bf5f61b15648e7e35db25fb23cef6b4164fc71c3064ac42ecacafcb6d02abe6", @@ -103,13 +105,19 @@ "https://bcr.bazel.build/modules/grpc/1.66.0.bcr.2/source.json": "d2b273a925507d47b5e2d6852f194e70d2991627d71b13793cc2498400d4f99e", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/MODULE.bazel": "31271aedc59e815656f5736f282bb7509a97c7ecb43e927ac1a37966e0578075", "https://bcr.bazel.build/modules/jsoncpp/1.9.5/source.json": "4108ee5085dd2885a341c7fab149429db457b3169b86eb081fa245eadf69169d", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/MODULE.bazel": "bcc23b7c4866af2d7777ee49db435603ca1e35b90ea0689f8051900fa8c73c6b", + "https://bcr.bazel.build/modules/libjpeg_turbo/2.1.91/source.json": "42ea85708058e2408f229075e1cbeaad13fa2719918ff9c505be5e22b57ef17b", "https://bcr.bazel.build/modules/libpfm/4.11.0/MODULE.bazel": "45061ff025b301940f1e30d2c16bea596c25b176c8b6b3087e92615adbd52902", "https://bcr.bazel.build/modules/libpfm/4.11.0/source.json": "caaffb3ac2b59b8aac456917a4ecf3167d40478ee79f15ab7a877ec9273937c9", + "https://bcr.bazel.build/modules/libpng/1.6.47/MODULE.bazel": "66470450c2040f07d3fc3ee4b72ed25f50ec6b41388a9cf80160b39a1dc75ed1", + "https://bcr.bazel.build/modules/libpng/1.6.47/source.json": "80f668824b3605b52c99e705062019f2c6f9066ec024b70ea5ee88db1e89b6b6", "https://bcr.bazel.build/modules/mbedtls/3.6.0/MODULE.bazel": "8e380e4698107c5f8766264d4df92e36766248447858db28187151d884995a09", "https://bcr.bazel.build/modules/mbedtls/3.6.0/source.json": "1dbe7eb5258050afcc3806b9d43050f71c6f539ce0175535c670df606790b30c", "https://bcr.bazel.build/modules/nlohmann_json/3.11.3/MODULE.bazel": "87023db2f55fc3a9949c7b08dc711fae4d4be339a80a99d04453c4bb3998eefc", "https://bcr.bazel.build/modules/nlohmann_json/3.11.3/source.json": "296c63a90c6813e53b3812d24245711981fc7e563d98fe15625f55181494488a", "https://bcr.bazel.build/modules/nlohmann_json/3.6.1/MODULE.bazel": "6f7b417dcc794d9add9e556673ad25cb3ba835224290f4f848f8e2db1e1fca74", + "https://bcr.bazel.build/modules/opencv/4.11.0.bcr.2/MODULE.bazel": "8eeccd6402fd5cee483501c11409df6b80e94a8d5d53b71c5e9293aaa51be3d6", + "https://bcr.bazel.build/modules/opencv/4.11.0.bcr.2/source.json": "2776c8954ea4e18fad23ca7be60d235493a8decafac3c943bab5134da5ea633c", "https://bcr.bazel.build/modules/opentelemetry-cpp/1.14.2/MODULE.bazel": "089a5613c2a159c7dfde098dabfc61e966889c7d6a81a98422a84c51535ed17d", "https://bcr.bazel.build/modules/opentelemetry-cpp/1.19.0/MODULE.bazel": "3455326c08b28415648a3d60d8e3c811847ebdbe64474f75b25878f25585aea1", "https://bcr.bazel.build/modules/opentelemetry-cpp/1.19.0/source.json": "4e48137e4c3ecb99401ff99876df8fa330598d7da051869bec643446e8a8ff95", @@ -119,7 +127,8 @@ "https://bcr.bazel.build/modules/opentracing-cpp/1.6.0/MODULE.bazel": "b3925269f63561b8b880ae7cf62ccf81f6ece55b62cd791eda9925147ae116ec", "https://bcr.bazel.build/modules/opentracing-cpp/1.6.0/source.json": "da1cb1add160f5e5074b7272e9db6fd8f1b3336c15032cd0a653af9d2f484aed", "https://bcr.bazel.build/modules/platforms/0.0.10/MODULE.bazel": "8cb8efaf200bdeb2150d93e162c40f388529a25852b332cec879373771e48ed5", - "https://bcr.bazel.build/modules/platforms/0.0.10/source.json": "f22828ff4cf021a6b577f1bf6341cb9dcd7965092a439f64fc1bb3b7a5ae4bd5", + "https://bcr.bazel.build/modules/platforms/0.0.11/MODULE.bazel": "0daefc49732e227caa8bfa834d65dc52e8cc18a2faf80df25e8caea151a9413f", + "https://bcr.bazel.build/modules/platforms/0.0.11/source.json": "f7e188b79ebedebfe75e9e1d098b8845226c7992b307e28e1496f23112e8fc29", "https://bcr.bazel.build/modules/platforms/0.0.4/MODULE.bazel": "9b328e31ee156f53f3c416a64f8491f7eb731742655a47c9eec4703a71644aee", "https://bcr.bazel.build/modules/platforms/0.0.5/MODULE.bazel": "5733b54ea419d5eaf7997054bb55f6a1d0b5ff8aedf0176fef9eea44f3acda37", "https://bcr.bazel.build/modules/platforms/0.0.6/MODULE.bazel": "ad6eeef431dc52aefd2d77ed20a4b353f8ebf0f4ecdd26a807d2da5aa8cd0615", @@ -159,13 +168,14 @@ "https://bcr.bazel.build/modules/rules_cc/0.0.14/MODULE.bazel": "5e343a3aac88b8d7af3b1b6d2093b55c347b8eefc2e7d1442f7a02dc8fea48ac", "https://bcr.bazel.build/modules/rules_cc/0.0.15/MODULE.bazel": "6704c35f7b4a72502ee81f61bf88706b54f06b3cbe5558ac17e2e14666cd5dcc", "https://bcr.bazel.build/modules/rules_cc/0.0.16/MODULE.bazel": "7661303b8fc1b4d7f532e54e9d6565771fea666fbdf839e0a86affcd02defe87", + "https://bcr.bazel.build/modules/rules_cc/0.0.17/MODULE.bazel": "2ae1d8f4238ec67d7185d8861cb0a2cdf4bc608697c331b95bf990e69b62e64a", "https://bcr.bazel.build/modules/rules_cc/0.0.2/MODULE.bazel": "6915987c90970493ab97393024c156ea8fb9f3bea953b2f3ec05c34f19b5695c", "https://bcr.bazel.build/modules/rules_cc/0.0.5/MODULE.bazel": "be41f87587998fe8890cd82ea4e848ed8eb799e053c224f78f3ff7fe1a1d9b74", "https://bcr.bazel.build/modules/rules_cc/0.0.6/MODULE.bazel": "abf360251023dfe3efcef65ab9d56beefa8394d4176dd29529750e1c57eaa33f", "https://bcr.bazel.build/modules/rules_cc/0.0.8/MODULE.bazel": "964c85c82cfeb6f3855e6a07054fdb159aced38e99a5eecf7bce9d53990afa3e", "https://bcr.bazel.build/modules/rules_cc/0.0.9/MODULE.bazel": "836e76439f354b89afe6a911a7adf59a6b2518fafb174483ad78a2a2fde7b1c5", - "https://bcr.bazel.build/modules/rules_cc/0.1.0/MODULE.bazel": "2fef03775b9ba995ec543868840041cc69e8bc705eb0cb6604a36eee18c87d8b", - "https://bcr.bazel.build/modules/rules_cc/0.1.0/source.json": "8a4e832d75e073ab56c74dd77008cf7a81e107dec4544019eb1eefc1320d55be", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/MODULE.bazel": "2f0222a6f229f0bf44cd711dc13c858dad98c62d52bd51d8fc3a764a83125513", + "https://bcr.bazel.build/modules/rules_cc/0.1.1/source.json": "d61627377bd7dd1da4652063e368d9366fc9a73920bfa396798ad92172cf645c", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/MODULE.bazel": "40c97d1144356f52905566c55811f13b299453a14ac7769dfba2ac38192337a8", "https://bcr.bazel.build/modules/rules_fuzzing/0.5.2/source.json": "c8b1e2c717646f1702290959a3302a178fb639d987ab61d548105019f11e527e", "https://bcr.bazel.build/modules/rules_go/0.33.0/MODULE.bazel": "a2b11b64cd24bf94f57454f53288a5dacfe6cb86453eee7761b7637728c1910c", @@ -254,7 +264,8 @@ "https://bcr.bazel.build/modules/zlib/1.2.13/MODULE.bazel": "aa6deb1b83c18ffecd940c4119aff9567cd0a671d7bba756741cb2ef043a29d5", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.1/MODULE.bazel": "6a9fe6e3fc865715a7be9823ce694ceb01e364c35f7a846bf0d2b34762bc066b", "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/MODULE.bazel": "af322bc08976524477c79d1e45e241b6efbeb918c497e8840b8ab116802dda79", - "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.3/source.json": "2be409ac3c7601245958cd4fcdff4288be79ed23bd690b4b951f500d54ee6e7d", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/MODULE.bazel": "eec517b5bbe5492629466e11dae908d043364302283de25581e3eb944326c4ca", + "https://bcr.bazel.build/modules/zlib/1.3.1.bcr.5/source.json": "22bc55c47af97246cfc093d0acf683a7869377de362b5d1c552c2c2e16b7a806", "https://bcr.bazel.build/modules/zlib/1.3.1/MODULE.bazel": "751c9940dcfe869f5f7274e1295422a34623555916eb98c174c1e945594bf198", "https://bcr.bazel.build/modules/zlib/1.3/MODULE.bazel": "6a9c02f19a24dcedb05572b2381446e27c272cd383aed11d41d99da9e3167a72" }, @@ -11772,23 +11783,6 @@ ] } }, - "@@platforms//host:extension.bzl%host_platform": { - "general": { - "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", - "usagesDigest": "hgylFkgWSg0ulUwWZzEM1aIftlUnbmw2ynWLdEfHnZc=", - "recordedFileInputs": {}, - "recordedDirentsInputs": {}, - "envVariables": {}, - "generatedRepoSpecs": { - "host_platform": { - "bzlFile": "@@platforms//host:extension.bzl", - "ruleClassName": "host_platform_repo", - "attributes": {} - } - }, - "recordedRepoMappingEntries": [] - } - }, "@@pybind11_bazel~//:internal_configure.bzl%internal_configure_extension": { "general": { "bzlTransitiveDigest": "CyAKLVVonohnkTSqg9II/HA7M49sOlnMkgMHL3CmDuc=", diff --git a/docs/Doxyfile b/docs/Doxyfile index 57013e7e..620cd0ac 100644 --- a/docs/Doxyfile +++ b/docs/Doxyfile @@ -1810,7 +1810,7 @@ FULL_SIDEBAR = NO # Minimum value: 0, maximum value: 20, default value: 4. # This tag requires that the tag GENERATE_HTML is set to YES. -ENUM_VALUES_PER_LINE = 4 +ENUM_VALUES_PER_LINE = 1 # When the SHOW_ENUM_VALUES tag is set doxygen will show the specified # enumeration values besides the enumeration mnemonics. @@ -2813,7 +2813,7 @@ DIR_GRAPH_MAX_DEPTH = 1 # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. diff --git a/framework/include/vx_internal.h b/framework/include/vx_internal.h index c9a0835a..941f305b 100644 --- a/framework/include/vx_internal.h +++ b/framework/include/vx_internal.h @@ -155,7 +155,7 @@ /*! \brief Maximum number of parameters to a kernel. * \ingroup group_int_defines */ -#define VX_INT_MAX_PARAMS (15) +#define VX_INT_MAX_PARAMS (22) /*! \brief Maximum number of loadable modules. * \ingroup group_int_defines diff --git a/framework/src/vx_kernel.cpp b/framework/src/vx_kernel.cpp index 5a35cd49..a274943a 100644 --- a/framework/src/vx_kernel.cpp +++ b/framework/src/vx_kernel.cpp @@ -341,7 +341,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxLoadKernels(vx_context context, const vx_ch status = publish((vx_context)context); if (status != VX_SUCCESS) { - VX_PRINT(VX_ZONE_ERROR, "Failed to publish kernels in module\n"); + VX_PRINT(VX_ZONE_ERROR, + "Failed to publish kernels in module with status %d\n", status); Osal::unloadModule(context->modules[m].handle); context->modules[m].handle = nullptr; } @@ -875,6 +876,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToKernel(vx_kernel kernel, (Parameter::isValidDirection(dir) == vx_false_e) || (Parameter::isValidState(state) == vx_false_e)) { + VX_PRINT(VX_ZONE_ERROR, + "Invalid data type, param direction, or param state!\n"); status = VX_ERROR_INVALID_PARAMETERS; } else @@ -893,6 +896,8 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToKernel(vx_kernel kernel, (Parameter::isValidState(state) == vx_false_e)) || (data_type == VX_TYPE_DELAY && dir != VX_INPUT)) { + VX_PRINT(VX_ZONE_ERROR, + "Invalid data type, param direction, or param state!\n"); status = VX_ERROR_INVALID_PARAMETERS; } else @@ -906,6 +911,7 @@ VX_API_ENTRY vx_status VX_API_CALL vxAddParameterToKernel(vx_kernel kernel, } else { + VX_PRINT(VX_ZONE_ERROR, "Invalid number of parameters associated!\n"); status = VX_ERROR_INVALID_PARAMETERS; } } diff --git a/framework/src/vx_parameter.cpp b/framework/src/vx_parameter.cpp index 5437770e..85d0913d 100644 --- a/framework/src/vx_parameter.cpp +++ b/framework/src/vx_parameter.cpp @@ -34,7 +34,7 @@ Parameter::~Parameter() vx_bool Parameter::isValidDirection(vx_enum dir) { - if ((dir == VX_INPUT) || (dir == VX_OUTPUT)) /* Bidirectional is not valid for user kernels */ + if ((dir == VX_INPUT) || (dir == VX_OUTPUT) || (dir == VX_BIDIRECTIONAL)) { return vx_true_e; } diff --git a/include/VX/vx_corevx_ext.h b/include/VX/vx_corevx_ext.h index 57de24de..6967b51b 100644 --- a/include/VX/vx_corevx_ext.h +++ b/include/VX/vx_corevx_ext.h @@ -171,8 +171,8 @@ */ /*! - * \brief The OpenVX CoreVX Vendor Extension. - * \defgroup group_corevx_ext Extension: CoreVX + * \brief The OpenVX EdgeAI Vendor Extension. + * \defgroup group_corevx_ext Extension: AI/ML * \ingroup group_extensions * * \defgroup group_ort_function_cpu_inference Kernel: ORT Inference diff --git a/samples/README.md b/samples/README.md new file mode 100644 index 00000000..43dc1966 --- /dev/null +++ b/samples/README.md @@ -0,0 +1,38 @@ +[![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://opensource.org/licenses/MIT) + +

+ +# Sample Applications + +Khronos OpenVX™ is an open, royalty-free standard for cross-platform acceleration of computer vision applications. OpenVX enables performance and power-optimized computer vision processing, especially important in embedded and real-time use cases such as face, body, and gesture tracking, smart video surveillance, advanced driver assistance systems (ADAS), object and scene reconstruction, augmented reality, visual inspection, robotics and more. + +In this project, we provide samples that use our optimized libraries to build applications that showcase potential usage or may used as reference to develop your own products. + +## Bubble Pop + +In this sample we will create an OpenVX graph to run Bubble Pop on a live camera. This sample application uses OpenCV to decode input image, draw bubbles/donuts and display the output. + +

+ +## Canny Edge Detector + +In this sample we will create an OpenVX graph to run canny edge detection on an image or a live camera. This sample application uses OpenCV to decode input image and display the output. + +

+ +## Optical Flow + +This sample [application](./optical_flow/README.md#openvx-samples) we will create an OpenVX graph to run Optical Flow on a video/live. This sample application uses OpenCV to decode input video and display the output. + +

+ +## Skin Tone Detector + +In this sample we will create an OpenVX graph to run skintone detection on an image or a live camera. This sample application uses OpenCV to decode input image and display the output. + +

+ +## ORB (Oriented FAST and Rotated BRIEF) +In this sample we will create an OpenVX graph to run ORB (Oriented FAST and Rotated BRIEF) on a live camera. This sample application uses OpenCV to detect and display keypoints. + +

\ No newline at end of file diff --git a/samples/bubble-pop/BUILD b/samples/bubble-pop/BUILD new file mode 100644 index 00000000..6e504ebd --- /dev/null +++ b/samples/bubble-pop/BUILD @@ -0,0 +1,57 @@ + + +cc_import( + name = "import_vx_pop", + shared_library = ":vx_pop", +) + +cc_shared_library( + name = "vx_pop", + deps = [":vx_pop_a"] +) + +cc_library( + name = "vx_pop_a", + srcs = [ + "source/AMD_VX_Pop_Bubble.cpp", + "source/AMD_VX_Pop_Donut.cpp", + "source/internal_dataTranslator.cpp", + "source/internal_publishKernels.cpp", + "source/internal_vxNodes.cpp" + ], + deps = [ + "//:corevx", + "@opencv", + "//targets/ai_server:imported_openvx_ai_server", + "//targets/c_model:imported_openvx_c_model", + "//targets/debug:imported_openvx_debug", + "//targets/extras:imported_openvx_extras", + "//targets/liteRT:imported_openvx_liteRT", + "//targets/opencl:imported_openvx_opencl", + "//targets/onnxRT:imported_openvx_onnxRT", + "//targets/executorch:imported_openvx_torch", + "//third_party:opencv-prebuilt", + ], + hdrs = glob([ + "include/*.h" + ]), + includes = ["include"], +) + +cc_binary( + name = "bubble-pop", + srcs = [ + "source/AMD_app.cpp", + "include/vx_ext_pop.h", + "include/vx_pop.h", + ], + includes = ["include"], + data = [ + "image/bubble.png", + ], + deps = [ + ":vx_pop_a", + ":import_vx_pop" + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/samples/bubble-pop/README.md b/samples/bubble-pop/README.md new file mode 100644 index 00000000..9a1dd6d1 --- /dev/null +++ b/samples/bubble-pop/README.md @@ -0,0 +1,65 @@ +## Bubble Pop Sample +In this sample we will create an OpenVX graph to run Bubble Pop on a live camera. This sample application uses OpenCV to decode input image, draw bubbles/donuts and display the output. + +

+ +### Prerequisites + +* [Conformant OpenVX Implementation](https://github.com/KhronosGroup/Khronosdotorg/blob/master/api/openvx/resources.md) + +* [OpenCV](https://github.com/opencv/opencv/releases/tag/3.4.0) + +* Camera + +### Steps to run the Bubble Pop sample + +* **Step - 1:** Build and install [Conformant OpenVX Implementation](https://github.com/KhronosGroup/OpenVX-sample-impl). In this example we will use the OpenVX Sample Implementation available on [GitHub](https://github.com/KhronosGroup/OpenVX-sample-impl) + +``` +Build OpenVX on Linux + +* Git Clone project with a recursive flag to get submodules + + git clone --recursive https://github.com/KhronosGroup/OpenVX-sample-impl.git + +* Use Build.py script + + cd OpenVX-sample-impl/ + python Build.py --os=Linux --arch=64 --conf=Debug --conf_vision --enh_vision --conf_nn +``` + +* **Step - 2:** Export OpenVX Directory Path + +``` +export OPENVX_DIR=$(pwd)/install/Linux/x64/Debug +``` + +* **Step - 3:** Clone the OpenVX Samples project and build the bubble pop application + +``` +cd ~/ && mkdir OpenVXSample-pop +cd OpenVXSample-pop/ +git clone https://github.com/kiritigowda/openvx-samples.git +``` + +* **Step - 4:** CMake and Build the pop application + +``` +mkdir pop-build && cd pop-build +cmake -DOPENVX_INCLUDES=$OPENVX_DIR/include -DOPENVX_LIBRARIES=$OPENVX_DIR/bin/libopenvx.so ../openvx-samples/bubble-pop/ +make +``` + +* **Step - 5:** Run VX Pop application + + * **Bubbles** + + ``` + ./vxPop --bubble + ``` + + * **Donuts** + + ```` + ./vxPop --donut + ```` diff --git a/samples/bubble-pop/image/bubble.png b/samples/bubble-pop/image/bubble.png new file mode 100644 index 00000000..09fe7731 Binary files /dev/null and b/samples/bubble-pop/image/bubble.png differ diff --git a/samples/bubble-pop/include/internal_opencvTunnel.h b/samples/bubble-pop/include/internal_opencvTunnel.h new file mode 100644 index 00000000..a546fbfe --- /dev/null +++ b/samples/bubble-pop/include/internal_opencvTunnel.h @@ -0,0 +1,107 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef CV_TUNNEL +#define CV_TUNNEL + +#if _WIN32 +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vx_pop.h" + +using namespace cv; +using namespace std; + +#define STATUS_ERROR_CHECK(call){vx_status status = call; if(status!= VX_SUCCESS) return status;} +#define PARAM_ERROR_CHECK(call){vx_status status = call; if(status!= VX_SUCCESS) goto exit;} + +int VX_to_CV_Image(Mat**, vx_image); +int VX_to_CV_MATRIX(Mat**, vx_matrix); + +int CV_to_VX_Pyramid(vx_pyramid, vector); +int CV_to_VX_Image(vx_image, Mat*); + +int CV_to_VX_keypoints(vector, vx_array); +int CVPoints2f_to_VX_keypoints(vector, vx_array); +int CV_DESP_to_VX_DESP(Mat, vx_array, int); + +int match_vx_image_parameters(vx_image, vx_image); +void overlay_bubble(const Mat &, const Mat &, Mat &, Point2i); + +class Kernellist +{ +public: + struct node{ public: std::function func; node* next; }; + int count; + Kernellist(int max){ top = nullptr; maxnum = max; count = 0;} + + vx_status ADD(std::function element) + { + vx_status status = VX_SUCCESS; + if (count == maxnum) return VX_ERROR_NO_RESOURCES; + else + { + node *newTop = new node; + if (top == nullptr){ newTop->func = element; newTop->next = nullptr; top = newTop; count++; } + else{ newTop->func = element; newTop->next = top; top = newTop; count++; } + } + return status; + } + + vx_status REMOVE() + { + vx_status status = VX_SUCCESS; + if (top == nullptr) return VX_ERROR_NO_RESOURCES; + else{ node * old = top; top = top->next; count--; delete(old); } + return status; + } + + vx_status PUBLISH(vx_context context) + { + vx_status status = VX_SUCCESS; + + if (top == nullptr) { vxAddLogEntry((vx_reference)context, VX_ERROR_NO_RESOURCES, "PUBLISH Fail, Kernel list is empty"); return VX_ERROR_NO_RESOURCES; } + + else + { + node * Kernel = top; + for (int i = 0; i < count; i++){ STATUS_ERROR_CHECK(Kernel->func(context)); Kernel = Kernel->next;} + } + return status; + } + +private: + node *top; int maxnum; +}; + +static Kernellist *Kernel_List; + +#endif /* CV_TUNNEL */ diff --git a/samples/bubble-pop/include/internal_publishKernels.h b/samples/bubble-pop/include/internal_publishKernels.h new file mode 100644 index 00000000..59784d77 --- /dev/null +++ b/samples/bubble-pop/include/internal_publishKernels.h @@ -0,0 +1,46 @@ +/* +Copyright (c) 2015 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#ifndef PUBLISH_KERNELS_H +#define PUBLISH_KERNELS_H + +#include "internal_opencvTunnel.h" + +#if _WIN32 +#define SHARED_PUBLIC __declspec(dllexport) +#else +#define SHARED_PUBLIC __attribute__ ((visibility ("default"))) +#endif + +#define MAX_KERNELS 10 + +extern "C" SHARED_PUBLIC vx_status VX_API_CALL vxPublishKernels(vx_context context); + +vx_status ADD_KERENEL(std::function); +vx_status get_kernels_to_publish(); + +vx_status VX_bubbles_pop_Register(vx_context); +vx_status VX_donut_pop_Register(vx_context); + +#define VX_KERNEL_EXT_POP_BUBBLE_POP_NAME "org.pop.bubble_pop" +#define VX_KERNEL_EXT_POP_DONUT_POP_NAME "org.pop.donut_pop" + +#endif /* PUBLISH_KERNELS_H */ diff --git a/samples/bubble-pop/include/vx_ext_pop.h b/samples/bubble-pop/include/vx_ext_pop.h new file mode 100644 index 00000000..2d8aed6a --- /dev/null +++ b/samples/bubble-pop/include/vx_ext_pop.h @@ -0,0 +1,68 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include "VX/vx.h" +#include +#include +#include +#include + +#if _WIN32 +#define SHARED_PUBLIC __declspec(dllexport) +#else +#define SHARED_PUBLIC __attribute__ ((visibility ("default"))) +#endif + +#ifndef dimof +#define dimof(x) (sizeof(x)/sizeof(x[0])) +#endif + +vx_node vxCreateNodeByStructure(vx_graph graph, vx_enum kernelenum, vx_reference params[], vx_uint32 num); + +#ifdef __cplusplus +extern "C" { +#endif + + /*!*********************************************************************************************************** + VX POP - Bubble Pop VX_API_ENTRY C Function NODE + *************************************************************************************************************/ + /*! \brief [Graph] Creates a OpenCV blur function node. + * \param [in] graph The reference to the graph. + * \param [in] input The input image in \ref VX_DF_IMAGE_U8 format. + * \param [out] output The output image is as same size and type of input. + * \return \ref vx_node. + * \retval vx_node A node reference. Any possible errors preventing a successful creation should be checked using \ref vxGetStatus*/ + extern "C" SHARED_PUBLIC vx_node VX_API_CALL vxExtPopNode_bubblePop(vx_graph graph, vx_image input, vx_image output); + + /*!*********************************************************************************************************** + VX POP - Donut Pop VX_API_ENTRY C Function NODE + *************************************************************************************************************/ + /*! \brief [Graph] Creates a OpenCV blur function node. + * \param [in] graph The reference to the graph. + * \param [in] input The input image in \ref VX_DF_IMAGE_U8 format. + * \param [out] output The output image is as same size and type of input. + * \return \ref vx_node. + * \retval vx_node A node reference. Any possible errors preventing a successful creation should be checked using \ref vxGetStatus*/ + extern "C" SHARED_PUBLIC vx_node VX_API_CALL vxExtPopNode_donutPop(vx_graph graph, vx_image input, vx_image output); + +#ifdef __cplusplus +} +#endif diff --git a/samples/bubble-pop/include/vx_pop.h b/samples/bubble-pop/include/vx_pop.h new file mode 100644 index 00000000..edd7a7d1 --- /dev/null +++ b/samples/bubble-pop/include/vx_pop.h @@ -0,0 +1,54 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifndef _VX_EXT_AMD_POP_H_ +#define _VX_EXT_AMD_POP_H_ + +#include"vx_ext_pop.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*! \brief The AMD extension library for Pop */ +#define VX_LIBRARY_EXT_POP 3 + + /*! + * \brief The list of available vision kernels in the Pop extension library. + */ + enum vx_kernel_ext_amd_pop_e + { + /*! + * \brief The Bubble Pop kernel. Kernel name is "org.pop.bubble_pop". + */ + VX_KERNEL_EXT_POP_BUBBLE_POP = VX_KERNEL_BASE(VX_ID_AMD, VX_LIBRARY_EXT_POP) + 0x001, + /*! + * \brief The Donut Pop kernel. Kernel name is "org.pop.donut_pop". + */ + VX_KERNEL_EXT_POP_DONUT_POP = VX_KERNEL_BASE(VX_ID_AMD, VX_LIBRARY_EXT_POP) + 0x002, + }; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/samples/bubble-pop/source/AMD_VX_Pop_Bubble.cpp b/samples/bubble-pop/source/AMD_VX_Pop_Bubble.cpp new file mode 100644 index 00000000..46d25742 --- /dev/null +++ b/samples/bubble-pop/source/AMD_VX_Pop_Bubble.cpp @@ -0,0 +1,415 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include + +#include "internal_publishKernels.h" + +int poppedBubbles = 0; +int globalBubblesflag = 0; +Mat globalBubblesRefImage; +int globalBubblesChange = 0; +Mat bubble_PNG; + +/************************************************************************************************************ +Overlay Image Function +*************************************************************************************************************/ +void overlayImage(const Mat &background, const Mat &foreground,Mat &output, Point2i location) +{ + background.copyTo(output); + + for (int y = std::max(location.y, 0); y < background.rows; ++y) + { + int fY = y - location.y; + if (fY >= foreground.rows) + break; + + for (int x = std::max(location.x, 0); x < background.cols; ++x) + { + int fX = x - location.x; + + + if (fX >= foreground.cols) + break; + + double opacity = + ((double)foreground.data[fY * foreground.step + fX * foreground.channels() + 3]) + + / 255.; + + for (int c = 0; opacity > 0 && c < output.channels(); ++c) + { + unsigned char foregroundPx = + foreground.data[fY * foreground.step + fX * foreground.channels() + c]; + unsigned char backgroundPx = + background.data[y * background.step + x * background.channels() + c]; + output.data[y*output.step + output.channels()*x + c] = + backgroundPx * (1. - opacity) + foregroundPx * opacity; + } + } + } +} + +/************************************************************************************************************ +Bubbles +*************************************************************************************************************/ +class AMD_bubble_pop +{ +private: + int bubbleX, bubbleY, bubbleWidth, bubbleHeight; + +public: + AMD_bubble_pop(int bX, int bY, int bW, int bH) + { + bubbleX = bX; bubbleY = bY; bubbleWidth = bW; bubbleHeight = bH; + bubble_PNG = imread("./samples/bubble-pop/image/bubble.png", -1); + } + + ~AMD_bubble_pop() + { + bubbleX = 0; bubbleY = 0; bubbleWidth = 0; bubbleHeight = 0; + } + + int update(int width, int height, Mat *Image) + { + (void)width; + int movementAmount = 0; + if (globalBubblesflag > 10) + { + Mat diff_image; + absdiff(*Image, globalBubblesRefImage, diff_image); + blur(diff_image, diff_image, Size(3, 3)); + + cv::erode(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::erode(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::dilate(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::dilate(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + + cv::threshold(diff_image, diff_image, 160, 255, 0); + + unsigned char *input = (unsigned char*)(diff_image.data); + int b; + + for (int x = bubbleX; x <= (bubbleX + (bubbleWidth - 1)); x++) + for (int y = bubbleY; y <= (bubbleY + (bubbleWidth - 1)); y++) + { + if ((x < diff_image.cols && x > 0) && (y < diff_image.rows && y > 0)) + { + b = input[diff_image.cols * y + x]; + if (b == 255) + movementAmount++; + } + } + } + + if (movementAmount > 100) + { + poppedBubbles++; + return 1; + } + else + { + bubbleY += 5; + + if (bubbleY > height) + return 1; + + Mat test_image; + test_image = *Image; + + // draw bubbles + if(bubble_PNG.empty()){ printf("--image/bubble.png-- Image not found\n"); return -1;}; + overlayImage(test_image, bubble_PNG, *Image, cv::Point(bubbleX, bubbleY)); + + return 0; + } + } +}; + +struct Linked_list_pop{ + AMD_bubble_pop bubble; + int data; + struct Linked_list_pop* next; +}; +typedef struct Linked_list_pop BubbleNode; + +//Function Prototyping +BubbleNode* insert_pop(BubbleNode* head, BubbleNode* x); +BubbleNode* pop_position_delete(BubbleNode* head, int p); +BubbleNode* pop_clean_node(BubbleNode* head); +void draw_pop_bubbles(int, int, Mat*); +BubbleNode *POPbubble = NULL; + +/************************************************************************************************************ +Draw Bubbles +*************************************************************************************************************/ +void draw_pop_bubbles(int width, int height, Mat *Image) +{ + static int count = 0; + + int randx = rand() % (width + 1); + AMD_bubble_pop new_element = AMD_bubble_pop(randx, 0, 20, 20); + + BubbleNode * temp = (BubbleNode*)malloc(sizeof(BubbleNode)); + temp->bubble = new_element; + temp->next = NULL; + POPbubble = insert_pop(POPbubble, temp); + count++; + + BubbleNode *_bubbles; + _bubbles = POPbubble; + int K = 0; + int flag = 0; + + while (_bubbles != NULL) + { + K++; + flag = 0; + + if (_bubbles->bubble.update(width, height, Image) == 1) + { + _bubbles = _bubbles->next; + POPbubble = pop_position_delete(POPbubble, K); + count--; + K--; + flag = 1; + } + + if (flag == 0) + _bubbles = _bubbles->next; + } + + (void)count; + return; + +} + +/************************************************************************************************************ +input parameter validator. +param [in] node The handle to the node. +param [in] index The index of the parameter to validate. +*************************************************************************************************************/ +static vx_status VX_CALLBACK VX_bubbles_InputValidator(vx_node node, vx_uint32 index) +{ + vx_status status = VX_SUCCESS; + vx_parameter param = vxGetParameterByIndex(node, index); + + if (index == 0) + { + vx_image image; + vx_df_image df_image = VX_DF_IMAGE_VIRT; + STATUS_ERROR_CHECK(vxQueryParameter(param, VX_PARAMETER_ATTRIBUTE_REF, &image, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &df_image, sizeof(df_image))); + if (df_image != VX_DF_IMAGE_U8) + status = VX_ERROR_INVALID_VALUE; + vxReleaseImage(&image); + } + + else if (index == 1) + { + vx_image image; + vx_df_image df_image = VX_DF_IMAGE_VIRT; + STATUS_ERROR_CHECK(vxQueryParameter(param, VX_PARAMETER_ATTRIBUTE_REF, &image, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &df_image, sizeof(df_image))); + if (df_image != VX_DF_IMAGE_U8 && df_image != VX_DF_IMAGE_RGB) + status = VX_ERROR_INVALID_VALUE; + vxReleaseImage(&image); + } + + vxReleaseParameter(¶m); + return status; +} + +/************************************************************************************************************ +output parameter validator. +*************************************************************************************************************/ +static vx_status VX_CALLBACK VX_bubbles_OutputValidator(vx_node node, vx_uint32 index, vx_meta_format meta) +{ + vx_status status = VX_SUCCESS; + if (index == 1) + { + vx_parameter output_param = vxGetParameterByIndex(node, 1); + vx_image output; vx_uint32 width = 0, height = 0; vx_df_image format = VX_DF_IMAGE_VIRT; + + STATUS_ERROR_CHECK(vxQueryParameter(output_param, VX_PARAMETER_ATTRIBUTE_REF, &output, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + + if (format != VX_DF_IMAGE_U8 && format != VX_DF_IMAGE_RGB) + status = VX_ERROR_INVALID_VALUE; + + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); + + vxReleaseImage(&output); + vxReleaseParameter(&output_param); + } + return status; +} + +/************************************************************************************************************ +Execution Kernel +*************************************************************************************************************/ +static vx_status VX_CALLBACK VX_bubbles_Kernel(vx_node node, const vx_reference *parameters, vx_uint32 num) +{ + (void)node; + (void)num; + vx_status status = VX_SUCCESS; + + vx_image image_in = (vx_image)parameters[0]; + vx_image image_out = (vx_image)parameters[1]; + Mat *mat, bl; + + // wait to restart - press any key + if(poppedBubbles >= 1015){ poppedBubbles = 0; waitKey(0);} + + //Converting VX Image to OpenCV Mat + STATUS_ERROR_CHECK(VX_to_CV_Image(&mat, image_in)); + Mat Image = *mat, clean_img; + flip(Image, Image, 1); + + if (globalBubblesflag == 0){ globalBubblesRefImage = Image;} else{clean_img = Image;} + + draw_pop_bubbles(Image.cols, Image.rows, &Image); + + std::ostringstream statusStr; + if (poppedBubbles >= 1000) + { + statusStr << "Congratulations! Click any Key to Contiue Popping!"; + cv::putText(Image, statusStr.str(), cv::Point(5, int(Image.rows/2)), FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(200, 200, 250), 1, cv::LINE_AA); + } + else + { + statusStr << "Bubbles Popped: " << poppedBubbles; + cv::putText(Image, statusStr.str(), cv::Point(30, 30), FONT_HERSHEY_COMPLEX_SMALL, 1.2, cv::Scalar(200, 200, 250), 1, cv::LINE_AA); + } + + //Converting OpenCV Mat into VX Image + STATUS_ERROR_CHECK(CV_to_VX_Image(image_out, &Image)); + + if (globalBubblesflag == 0) globalBubblesflag++; else{ globalBubblesRefImage = clean_img; globalBubblesflag++; } + + return status; +} + +/************************************************************************************************************ +Function to Register the Kernel for Publish +*************************************************************************************************************/ +vx_status VX_bubbles_pop_Register(vx_context context) +{ + vx_status status = VX_SUCCESS; + vx_kernel kernel = vxAddKernel(context, + "org.pop.bubble_pop", + VX_KERNEL_EXT_POP_BUBBLE_POP, + VX_bubbles_Kernel, + 2, + VX_bubbles_InputValidator, + VX_bubbles_OutputValidator, + nullptr, + nullptr); + + if (kernel) + { + PARAM_ERROR_CHECK(vxAddParameterToKernel(kernel, 0, VX_INPUT, VX_TYPE_IMAGE, VX_PARAMETER_STATE_REQUIRED)); + PARAM_ERROR_CHECK(vxAddParameterToKernel(kernel, 1, VX_OUTPUT, VX_TYPE_IMAGE, VX_PARAMETER_STATE_REQUIRED)); + PARAM_ERROR_CHECK(vxFinalizeKernel(kernel)); + } + + if (status != VX_SUCCESS) + { + exit: vxRemoveKernel(kernel); return VX_FAILURE; + } + + return status; +} + +/* +* linked_list.c +* Author: Kiriti Nagesh Gowda +*/ + +//Insert a variable function +BubbleNode* insert_pop(BubbleNode* head, BubbleNode* x) +{ + BubbleNode* temp; + BubbleNode* temp1 = x; + + if (head == NULL) + head = temp1; + + else{ + temp = head; + while (temp->next != NULL){ + temp = temp->next; + } + temp->next = temp1; + } + return (head); +} + +//Delete a node from the list +BubbleNode* pop_position_delete(BubbleNode* head, int p) +{ + BubbleNode* temp; + BubbleNode* temp1; + int count = 2; + temp = head; + + if (temp == NULL || p <= 0){ + printf("The List is empty or the position is invalid\n"); + return (head); + } + + if (p == 1){ + head = temp->next; + free(temp); + return (head); + } + while (temp != NULL){ + if (count == (p)) + { + temp1 = temp->next; + temp->next = temp1->next; + free(temp1); + return (head); + } + temp = temp->next; + + if (temp == NULL) break; + ++count; + } + return head; +} + +//clean node +BubbleNode *pop_clean_node(BubbleNode * head) +{ + + BubbleNode *temp1; + while (head != NULL){ + temp1 = head->next; + free(head); + head = temp1; + } + return(head); +} diff --git a/samples/bubble-pop/source/AMD_VX_Pop_Donut.cpp b/samples/bubble-pop/source/AMD_VX_Pop_Donut.cpp new file mode 100644 index 00000000..e4f5108c --- /dev/null +++ b/samples/bubble-pop/source/AMD_VX_Pop_Donut.cpp @@ -0,0 +1,390 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ +#include + +#include "internal_publishKernels.h" + +int poppedDonuts = 0; +int globalDonutFlag = 0; +Mat globalDonutRefImage; +int globalDonutChange = 0; + +/************************************************************************************************************ +Bubbles +*************************************************************************************************************/ +class AMD_donut_pop +{ +private: + int donutX, donutY, donutWidth, donutHeight; + +public: + AMD_donut_pop(int bX, int bY, int bW, int bH) + { + donutX = bX; donutY = bY; donutWidth = bW; donutHeight = bH; + } + + ~AMD_donut_pop() + { + donutX = 0; donutY = 0; donutWidth = 0; donutHeight = 0; + } + + int update(int width, int height, Mat *Image) + { + (void)width; + int movementAmount = 0; + if (globalDonutFlag > 10) + { + Mat diff_image; + absdiff(*Image, globalDonutRefImage, diff_image); + blur(diff_image, diff_image, Size(3, 3)); + + cv::erode(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::erode(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::dilate(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + cv::dilate(diff_image, diff_image, getStructuringElement(MORPH_ELLIPSE, Size(3, 3))); + + cv::threshold(diff_image, diff_image, 160, 255, 0); + + unsigned char *input = (unsigned char*)(diff_image.data); + int b; + + for (int x = donutX; x <= (donutX + (donutWidth - 1)); x++) + for (int y = donutY; y <= (donutY + (donutWidth - 1)); y++) + { + if ((x < diff_image.cols && x > 0) && (y < diff_image.rows && y > 0)) + { + b = input[diff_image.cols * y + x]; + if (b == 255) + movementAmount++; + } + } + } + + if (movementAmount > 100) + { + poppedDonuts++; + return 1; + } + else + { + donutY += 5; + + if (donutY > height) + return 1; + + Mat test_image; + test_image = *Image; + + // draw Donuts + if (globalDonutChange == 0) + { + Point2f cen(donutX, donutY); + cv::circle(*Image, cen, 8, cv::Scalar(255, 255, 55), 5); + } + else + { + Point2f cen(donutX, donutY); + cv::circle(*Image, cen, 5, cv::Scalar(255, 255, 55), 5); + } + + return 0; + } + } +}; + +struct Linked_list_pop{ + AMD_donut_pop donut; + int data; + struct Linked_list_pop* next; +}; +typedef struct Linked_list_pop donutNode; + +//Function Prototyping +donutNode* donut_insert(donutNode* head, donutNode* x); +donutNode* donut_position_delete(donutNode* head, int p); +donutNode* donut_clean_node(donutNode* head); +int draw_pop_donuts(int, int, Mat*); +donutNode *PopDonuts = NULL; + +/************************************************************************************************************ +Draw Bubbles +*************************************************************************************************************/ +int draw_pop_donuts(int width, int height, Mat *Image) +{ + static int count = 0; + + int randx = rand() % (width + 1); + AMD_donut_pop new_element = AMD_donut_pop(randx, 0, 20, 20); + + donutNode * temp = (donutNode*)malloc(sizeof(donutNode)); + temp->donut = new_element; + temp->next = NULL; + PopDonuts = donut_insert(PopDonuts, temp); + count++; + + donutNode *_donuts; + _donuts = PopDonuts; + int K = 0; + int flag = 0; + + while (_donuts != NULL) + { + K++; + flag = 0; + + if (_donuts->donut.update(width, height, Image) == 1) + { + _donuts = _donuts->next; + PopDonuts = donut_position_delete(PopDonuts, K); + count--; + K--; + flag = 1; + } + + if (flag == 0) + _donuts = _donuts->next; + } + + (void)count; + return 0; + +} + +/************************************************************************************************************ +input parameter validator. +param [in] node The handle to the node. +param [in] index The index of the parameter to validate. +*************************************************************************************************************/ +vx_status VX_CALLBACK VX_bubbles_InputValidator(vx_node node, vx_uint32 index) +{ + vx_status status = VX_SUCCESS; + vx_parameter param = vxGetParameterByIndex(node, index); + + if (index == 0) + { + vx_image image; + vx_df_image df_image = VX_DF_IMAGE_VIRT; + STATUS_ERROR_CHECK(vxQueryParameter(param, VX_PARAMETER_ATTRIBUTE_REF, &image, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &df_image, sizeof(df_image))); + if (df_image != VX_DF_IMAGE_U8) + status = VX_ERROR_INVALID_VALUE; + vxReleaseImage(&image); + } + + else if (index == 1) + { + vx_image image; + vx_df_image df_image = VX_DF_IMAGE_VIRT; + STATUS_ERROR_CHECK(vxQueryParameter(param, VX_PARAMETER_ATTRIBUTE_REF, &image, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &df_image, sizeof(df_image))); + if (df_image != VX_DF_IMAGE_U8 && df_image != VX_DF_IMAGE_RGB) + status = VX_ERROR_INVALID_VALUE; + vxReleaseImage(&image); + } + + vxReleaseParameter(¶m); + return status; +} + +/************************************************************************************************************ +output parameter validator. +*************************************************************************************************************/ +vx_status VX_CALLBACK VX_bubbles_OutputValidator(vx_node node, vx_uint32 index, vx_meta_format meta) +{ + vx_status status = VX_SUCCESS; + if (index == 1) + { + vx_parameter output_param = vxGetParameterByIndex(node, 1); + vx_image output; vx_uint32 width = 0, height = 0; vx_df_image format = VX_DF_IMAGE_VIRT; + + STATUS_ERROR_CHECK(vxQueryParameter(output_param, VX_PARAMETER_ATTRIBUTE_REF, &output, sizeof(vx_image))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxQueryImage(output, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + + if (format != VX_DF_IMAGE_U8 && format != VX_DF_IMAGE_RGB) + status = VX_ERROR_INVALID_VALUE; + + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + STATUS_ERROR_CHECK(vxSetMetaFormatAttribute(meta, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); + + vxReleaseImage(&output); + vxReleaseParameter(&output_param); + } + return status; +} + +/************************************************************************************************************ +Execution Kernel +*************************************************************************************************************/ +vx_status VX_CALLBACK VX_bubbles_Kernel(vx_node node, const vx_reference *parameters, vx_uint32 num) +{ + (void)node; + (void)num; + vx_status status = VX_SUCCESS; + + vx_image image_in = (vx_image)parameters[0]; + vx_image image_out = (vx_image)parameters[1]; + Mat *mat, bl; + + // wait to restart - press any key + if(poppedDonuts >= 1015){ poppedDonuts = 0; waitKey(0);} + + //Converting VX Image to OpenCV Mat + STATUS_ERROR_CHECK(VX_to_CV_Image(&mat, image_in)); + Mat Image = *mat, clean_img; + flip(Image, Image, 1); + + if (globalDonutFlag == 0){ + globalDonutRefImage = Image; + } + else{ + clean_img = Image; + } + + // change donut size - press "d" + if(waitKey(2) == 100){if (globalDonutChange == 0) globalDonutChange = 1; else globalDonutChange = 0;} + if(draw_pop_donuts(Image.cols, Image.rows, &Image)) + return VX_FAILURE; + + std::ostringstream statusStr; + if (poppedDonuts >= 1000) + { + statusStr << "Congratulations! Click any Key to Contiue Popping!"; + cv::putText(Image, statusStr.str(), cv::Point(5, int(Image.rows/2)), FONT_HERSHEY_COMPLEX_SMALL, 1, cv::Scalar(200, 200, 250), 1, cv::LINE_AA); + } + else + { + statusStr << "Bubbles Popped: " << poppedDonuts; + cv::putText(Image, statusStr.str(), cv::Point(30, 30), FONT_HERSHEY_COMPLEX_SMALL, 1.2, cv::Scalar(200, 200, 250), 1, cv::LINE_AA); + } + + //Converting OpenCV Mat into VX Image + STATUS_ERROR_CHECK(CV_to_VX_Image(image_out, &Image)); + + if (globalDonutFlag == 0) globalDonutFlag++; else{ globalDonutRefImage = clean_img; globalDonutFlag++; } + + return status; +} + +/************************************************************************************************************ +Function to Register the Kernel for Publish +*************************************************************************************************************/ +vx_status VX_donut_pop_Register(vx_context context) +{ + vx_status status = VX_SUCCESS; + vx_kernel kernel = vxAddKernel(context, + "org.pop.donut_pop", + VX_KERNEL_EXT_POP_DONUT_POP, + VX_bubbles_Kernel, + 2, + VX_bubbles_InputValidator, + VX_bubbles_OutputValidator, + nullptr, + nullptr); + + if (kernel) + { + PARAM_ERROR_CHECK(vxAddParameterToKernel(kernel, 0, VX_INPUT, VX_TYPE_IMAGE, VX_PARAMETER_STATE_REQUIRED)); + PARAM_ERROR_CHECK(vxAddParameterToKernel(kernel, 1, VX_OUTPUT, VX_TYPE_IMAGE, VX_PARAMETER_STATE_REQUIRED)); + PARAM_ERROR_CHECK(vxFinalizeKernel(kernel)); + } + + if (status != VX_SUCCESS) + { + exit: vxRemoveKernel(kernel); return VX_FAILURE; + } + + return status; +} + +/* +* linked_list.c +* Author: Kiriti Nagesh Gowda +*/ + +//Insert a variable function +donutNode* donut_insert(donutNode* head, donutNode* x) +{ + donutNode* temp; + donutNode* temp1 = x; + + if (head == NULL) + head = temp1; + + else{ + temp = head; + while (temp->next != NULL){ + temp = temp->next; + } + temp->next = temp1; + } + return (head); +} + +//Delete a node from the list +donutNode* donut_position_delete(donutNode* head, int p) +{ + donutNode* temp; + donutNode* temp1; + int count = 2; + temp = head; + + if (temp == NULL || p <= 0){ + printf("The List is empty or the position is invalid\n"); + return (head); + } + + if (p == 1){ + head = temp->next; + free(temp); + return (head); + } + while (temp != NULL){ + if (count == (p)) + { + temp1 = temp->next; + temp->next = temp1->next; + free(temp1); + return (head); + } + temp = temp->next; + + if (temp == NULL) break; + ++count; + } + return head; +} + +//clean node +donutNode *donut_clean_node(donutNode * head) +{ + + donutNode *temp1; + while (head != NULL){ + temp1 = head->next; + free(head); + head = temp1; + } + return(head); +} \ No newline at end of file diff --git a/samples/bubble-pop/source/AMD_app.cpp b/samples/bubble-pop/source/AMD_app.cpp new file mode 100644 index 00000000..f6572114 --- /dev/null +++ b/samples/bubble-pop/source/AMD_app.cpp @@ -0,0 +1,288 @@ +#include + +#include +#include + +#include "vx_ext_pop.h" + +using namespace cv; +using namespace std; + +#define ERROR_CHECK_STATUS( status ) { \ + vx_status status_ = (status); \ + if(status_ != VX_SUCCESS) { \ + printf("ERROR: failed with status = (%d) at " __FILE__ "#%d\n", status_, __LINE__); \ + exit(1); \ + } \ +} + +#define ERROR_CHECK_OBJECT( obj ) { \ + vx_status status_ = vxGetStatus((vx_reference)(obj)); \ + if(status_ != VX_SUCCESS) { \ + printf("ERROR: failed with status = (%d) at " __FILE__ "#%d\n", status_, __LINE__); \ + exit(1); \ + } \ +} + +static void VX_CALLBACK log_callback(vx_context context, vx_reference ref, vx_status status, const vx_char string[]) +{ + (void)context; + (void)ref; + (void)status; + size_t len = strlen(string); + if (len > 0) { + printf("%s", string); + if (string[len - 1] != '\n') + printf("\n"); + fflush(stdout); + } +} + +int main(int argc, char **argv) +{ + if (argc < 2) { + printf("Usage:\n" + "./vxPop --donut\n" + "./vxPop --bubble \n"); + return 0; + } + + int width = 720, height = 480; + + // create OpenVX Context + vx_context context = vxCreateContext(); + ERROR_CHECK_OBJECT(context); + vxRegisterLogCallback(context, log_callback, vx_false_e); + + // load vx_pop kernels + ERROR_CHECK_STATUS(vxLoadKernels(context, "vx_pop")); + + // create OpenVX Graph + vx_graph graph = vxCreateGraph(context); + ERROR_CHECK_OBJECT(graph); + + // create OpenVX Images + vx_image input_rgb_image = vxCreateImage(context, width, height, VX_DF_IMAGE_RGB); + vx_image output_pop_image = vxCreateImage(context, width, height, VX_DF_IMAGE_U8); + ERROR_CHECK_OBJECT(input_rgb_image); + ERROR_CHECK_OBJECT(output_pop_image); + + // create intermediate images + vx_image yuv_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_IYUV); + vx_image luma_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image output_canny_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image output_skinTone_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image output_canny_skinTone_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + ERROR_CHECK_OBJECT(yuv_image); + ERROR_CHECK_OBJECT(luma_image); + ERROR_CHECK_OBJECT(output_canny_image); + ERROR_CHECK_OBJECT(output_skinTone_image); + ERROR_CHECK_OBJECT(output_canny_skinTone_image); + + // create threshold variable + vx_threshold hyst = vxCreateThreshold(context, VX_THRESHOLD_TYPE_RANGE, VX_TYPE_UINT8); + vx_int32 lower = 80, upper = 100; + vxSetThresholdAttribute(hyst, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER, &lower, sizeof(lower)); + vxSetThresholdAttribute(hyst, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER, &upper, sizeof(upper)); + ERROR_CHECK_OBJECT(hyst); + vx_int32 gradient_size = 3; + + // create intermediate images which are not accessed by the user to be mem optimized + vx_image R_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image G_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image B_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image RmG_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image RmB_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image R95_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image G40_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image B20_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image RmG15_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image RmB0_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image and1_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image and2_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + vx_image and3_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + ERROR_CHECK_OBJECT(R_image); + ERROR_CHECK_OBJECT(G_image); + ERROR_CHECK_OBJECT(B_image); + ERROR_CHECK_OBJECT(RmG_image); + ERROR_CHECK_OBJECT(RmB_image); + ERROR_CHECK_OBJECT(R95_image); + ERROR_CHECK_OBJECT(G40_image); + ERROR_CHECK_OBJECT(B20_image); + ERROR_CHECK_OBJECT(RmG15_image); + ERROR_CHECK_OBJECT(RmB0_image); + ERROR_CHECK_OBJECT(and1_image); + ERROR_CHECK_OBJECT(and2_image); + ERROR_CHECK_OBJECT(and3_image); + + // create threshold values + vx_threshold thresh95 = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); + vx_int32 thresValue95 = 95; + vxSetThresholdAttribute(thresh95, VX_THRESHOLD_THRESHOLD_VALUE, &thresValue95, sizeof(vx_int32)); + ERROR_CHECK_OBJECT(thresh95); + vx_threshold thresh40 = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); + vx_int32 thresValue40 = 40; + vxSetThresholdAttribute(thresh40, VX_THRESHOLD_THRESHOLD_VALUE, &thresValue40, sizeof(vx_int32)); + ERROR_CHECK_OBJECT(thresh40); + vx_threshold thresh20 = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); + vx_int32 thresValue20 = 20; + vxSetThresholdAttribute(thresh20, VX_THRESHOLD_THRESHOLD_VALUE, &thresValue20, sizeof(vx_int32)); + ERROR_CHECK_OBJECT(thresh20); + vx_threshold thresh15 = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); + vx_int32 thresValue15 = 15; + vxSetThresholdAttribute(thresh15, VX_THRESHOLD_THRESHOLD_VALUE, &thresValue15, sizeof(vx_int32)); + ERROR_CHECK_OBJECT(thresh15); + vx_threshold thresh0 = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); + vx_int32 thresValue0 = 0; + vxSetThresholdAttribute(thresh0, VX_THRESHOLD_THRESHOLD_VALUE, &thresValue0, sizeof(vx_int32)); + ERROR_CHECK_OBJECT(thresh0); + + // add nodes to the graph + string option = argv[1]; + if (option == "--bubble") + { + vx_node nodes[] = + { + // extract R,G,B channels and compute R-G and R-B + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_R, R_image), + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_G, G_image), + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_B, B_image), + vxSubtractNode(graph, R_image, G_image, VX_CONVERT_POLICY_SATURATE, RmG_image), + vxSubtractNode(graph, R_image, B_image, VX_CONVERT_POLICY_SATURATE, RmB_image), + // compute threshold + vxThresholdNode(graph, R_image, thresh95, R95_image), + vxThresholdNode(graph, G_image, thresh40, G40_image), + vxThresholdNode(graph, B_image, thresh20, B20_image), + vxThresholdNode(graph, RmG_image, thresh15, RmG15_image), + vxThresholdNode(graph, RmB_image, thresh0, RmB0_image), + // aggregate all thresholded values to produce SKIN pixels + vxAndNode(graph, R95_image, G40_image, and1_image), + vxAndNode(graph, and1_image, B20_image, and2_image), + vxAndNode(graph, RmG15_image, RmB0_image, and3_image), + vxAndNode(graph, and2_image, and3_image, output_skinTone_image), + // create canny edge + vxColorConvertNode(graph, input_rgb_image, yuv_image), + vxChannelExtractNode(graph, yuv_image, VX_CHANNEL_Y, luma_image), + vxCannyEdgeDetectorNode(graph, luma_image, hyst, gradient_size, VX_NORM_L1, output_canny_image), + // or - canny & skintone images + vxOrNode(graph, output_canny_image, output_skinTone_image, output_canny_skinTone_image), + // vx pop - bubble pop + vxExtPopNode_bubblePop(graph, output_canny_skinTone_image, output_pop_image) + }; + for( vx_size i = 0; i < sizeof( nodes ) / sizeof( nodes[0] ); i++ ) + { + ERROR_CHECK_OBJECT( nodes[i] ); + ERROR_CHECK_STATUS( vxReleaseNode( &nodes[i] ) ); + } + } + else + { + vx_node nodes[] = + { + // extract R,G,B channels and compute R-G and R-B + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_R, R_image), + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_G, G_image), + vxChannelExtractNode(graph, input_rgb_image, VX_CHANNEL_B, B_image), + vxSubtractNode(graph, R_image, G_image, VX_CONVERT_POLICY_SATURATE, RmG_image), + vxSubtractNode(graph, R_image, B_image, VX_CONVERT_POLICY_SATURATE, RmB_image), + // compute threshold + vxThresholdNode(graph, R_image, thresh95, R95_image), + vxThresholdNode(graph, G_image, thresh40, G40_image), + vxThresholdNode(graph, B_image, thresh20, B20_image), + vxThresholdNode(graph, RmG_image, thresh15, RmG15_image), + vxThresholdNode(graph, RmB_image, thresh0, RmB0_image), + // aggregate all thresholded values to produce SKIN pixels + vxAndNode(graph, R95_image, G40_image, and1_image), + vxAndNode(graph, and1_image, B20_image, and2_image), + vxAndNode(graph, RmG15_image, RmB0_image, and3_image), + vxAndNode(graph, and2_image, and3_image, output_skinTone_image), + // create canny edge + vxColorConvertNode(graph, input_rgb_image, yuv_image), + vxChannelExtractNode(graph, yuv_image, VX_CHANNEL_Y, luma_image), + vxCannyEdgeDetectorNode(graph, luma_image, hyst, gradient_size, VX_NORM_L1, output_canny_image), + // or - canny & skintone images + vxOrNode(graph, output_canny_image, output_skinTone_image, output_canny_skinTone_image), + // vx pop - donut pop + vxExtPopNode_donutPop(graph, output_canny_skinTone_image, output_pop_image) + }; + for( vx_size i = 0; i < sizeof( nodes ) / sizeof( nodes[0] ); i++ ) + { + ERROR_CHECK_OBJECT( nodes[i] ); + ERROR_CHECK_STATUS( vxReleaseNode( &nodes[i] ) ); + } + } + + // verify graph - only once + ERROR_CHECK_STATUS( vxVerifyGraph( graph ) ); + + Mat input, input_rgb; + cv::namedWindow("VX POP - LIVE", cv::WINDOW_GUI_EXPANDED); + VideoCapture cap(0); + if (!cap.isOpened()) { + printf("Unable to open camera\n"); + return 0; + } + for(;;) + { + cap >> input; + resize(input, input, Size(width, height)); + cvtColor(input, input_rgb, COLOR_BGR2RGB); + if(waitKey(30) >= 0) break; + vx_rectangle_t cv_rgb_image_region; + cv_rgb_image_region.start_x = 0; + cv_rgb_image_region.start_y = 0; + cv_rgb_image_region.end_x = width; + cv_rgb_image_region.end_y = height; + vx_imagepatch_addressing_t cv_rgb_image_layout{}; + cv_rgb_image_layout.dim_x = input_rgb.cols; + cv_rgb_image_layout.dim_y = input_rgb.rows; + cv_rgb_image_layout.stride_x = input_rgb.elemSize(); + cv_rgb_image_layout.stride_y = input_rgb.step; + vx_uint8 * cv_rgb_image_buffer = input_rgb.data; + ERROR_CHECK_STATUS( vxCopyImagePatch( input_rgb_image, &cv_rgb_image_region, 0, + &cv_rgb_image_layout, cv_rgb_image_buffer, + VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST ) ); + ERROR_CHECK_STATUS( vxProcessGraph( graph ) ); + vx_rectangle_t rect = { 0, 0, (vx_uint32)width, (vx_uint32)height }; + vx_map_id map_id; + vx_imagepatch_addressing_t addr; + void * ptr; + ERROR_CHECK_STATUS( vxMapImagePatch( output_pop_image, &rect, 0, &map_id, &addr, &ptr, + VX_READ_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X ) ); + Mat mat( height, width, CV_8U, ptr, addr.stride_y ); + imshow( "VX POP - LIVE", mat ); + if(waitKey(30) >= 0) break; + ERROR_CHECK_STATUS( vxUnmapImagePatch( output_pop_image, map_id ) ); + } + + // release objects + ERROR_CHECK_STATUS(vxReleaseGraph( &graph ) ); + ERROR_CHECK_STATUS(vxReleaseThreshold( &hyst )); + ERROR_CHECK_STATUS(vxReleaseThreshold( &thresh95 )); + ERROR_CHECK_STATUS(vxReleaseThreshold( &thresh40 )); + ERROR_CHECK_STATUS(vxReleaseThreshold( &thresh20 )); + ERROR_CHECK_STATUS(vxReleaseThreshold( &thresh15 )); + ERROR_CHECK_STATUS(vxReleaseThreshold( &thresh0 )); + ERROR_CHECK_STATUS(vxReleaseImage( &yuv_image ) ); + ERROR_CHECK_STATUS(vxReleaseImage( &luma_image ) ); + ERROR_CHECK_STATUS(vxReleaseImage( &output_canny_image ) ); + ERROR_CHECK_STATUS(vxReleaseImage( &input_rgb_image ) ); + ERROR_CHECK_STATUS(vxReleaseImage( &R_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &G_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &B_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &RmG_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &RmB_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &R95_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &G40_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &B20_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &RmG15_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &RmB0_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &and1_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &and2_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &and3_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &output_skinTone_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &output_canny_skinTone_image )); + ERROR_CHECK_STATUS(vxReleaseImage( &output_pop_image ) ); + ERROR_CHECK_STATUS(vxReleaseContext( &context ) ); + return 0; +} diff --git a/samples/bubble-pop/source/internal_dataTranslator.cpp b/samples/bubble-pop/source/internal_dataTranslator.cpp new file mode 100644 index 00000000..3f228515 --- /dev/null +++ b/samples/bubble-pop/source/internal_dataTranslator.cpp @@ -0,0 +1,299 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include"internal_opencvTunnel.h" + +/************************************************************************************************************ +Converting CV Pyramid into an OpenVX Pyramid +*************************************************************************************************************/ +int CV_to_VX_Pyramid(vx_pyramid pyramid_vx, vector pyramid_cv) +{ + // vx_status status = VX_SUCCESS; + vx_size Level_vx = 0; vx_uint32 width = 0; vx_uint32 height = 0; vx_int32 i; + + STATUS_ERROR_CHECK(vxQueryPyramid(pyramid_vx, VX_PYRAMID_ATTRIBUTE_LEVELS, &Level_vx, sizeof(Level_vx))); + for (i = 0; i < (int)Level_vx; i++) + { + vx_image this_level = vxGetPyramidLevel(pyramid_vx, i); + STATUS_ERROR_CHECK(vxQueryImage(this_level, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxQueryImage(this_level, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + if (width != (vx_uint32)pyramid_cv[i].cols && height != (vx_uint32)pyramid_cv[i].rows) + { + vxAddLogEntry((vx_reference)pyramid_vx, VX_ERROR_INVALID_DIMENSION, "CV_to_VX_Pyramid ERROR: Pyramid Image Mismatch\n"); return VX_ERROR_INVALID_DIMENSION; + } + Mat* pyr_level; + pyr_level = &pyramid_cv[i]; + CV_to_VX_Image(this_level, pyr_level); + } + return 0; +} + +/************************************************************************************************************ +Converting VX matrix into an OpenCV Mat +*************************************************************************************************************/ +int VX_to_CV_MATRIX(Mat** mat, vx_matrix matrix_vx) +{ + vx_status status = VX_SUCCESS; + vx_size numRows = 0; vx_size numCols = 0; vx_enum type; int Type_CV = 0; + + STATUS_ERROR_CHECK(vxQueryMatrix(matrix_vx, VX_MATRIX_ATTRIBUTE_ROWS, &numRows, sizeof(numRows))); + STATUS_ERROR_CHECK(vxQueryMatrix(matrix_vx, VX_MATRIX_ATTRIBUTE_COLUMNS, &numCols, sizeof(numCols))); + STATUS_ERROR_CHECK(vxQueryMatrix(matrix_vx, VX_MATRIX_ATTRIBUTE_TYPE, &type, sizeof(type))); + + if (type == VX_TYPE_INT32)Type_CV = CV_32S; + if (type == VX_TYPE_FLOAT32)Type_CV = CV_32F; + + if (type != VX_TYPE_FLOAT32 && type != VX_TYPE_INT32) + { + vxAddLogEntry((vx_reference)matrix_vx, VX_ERROR_INVALID_FORMAT, "VX_to_CV_MATRIX ERROR: Matrix type not Supported in this RELEASE\n"); return VX_ERROR_INVALID_FORMAT; + } + + Mat * m_cv; m_cv = new Mat((int)numRows, (int)numCols, Type_CV); vx_size mat_size = numRows * numCols; + float *dyn_matrix = new float[mat_size]; int z = 0; + + STATUS_ERROR_CHECK(vxReadMatrix(matrix_vx, (void *)dyn_matrix)); + for (int i = 0; i < (int)numRows; i++) + for (int j = 0; j < (int)numCols; j++) + { + m_cv->at(i, j) = dyn_matrix[z]; z++; + } + + *mat = m_cv; + return status; +} + +/************************************************************************************************************ +Converting VX Image into an OpenCV Mat +*************************************************************************************************************/ +int VX_to_CV_Image(Mat** mat, vx_image image) +{ + vx_status status = VX_SUCCESS; + vx_uint32 width = 0; vx_uint32 height = 0; vx_df_image format = VX_DF_IMAGE_VIRT; int CV_format = 0; vx_size planes = 0; + + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_FORMAT, &format, sizeof(format))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &planes, sizeof(planes))); + + if (format == VX_DF_IMAGE_U8)CV_format = CV_8U; + if (format == VX_DF_IMAGE_S16)CV_format = CV_16S; + if (format == VX_DF_IMAGE_RGB)CV_format = CV_8UC3; + + if (format != VX_DF_IMAGE_U8 && format != VX_DF_IMAGE_S16 && format != VX_DF_IMAGE_RGB) + { + vxAddLogEntry((vx_reference)image, VX_ERROR_INVALID_FORMAT, "VX_to_CV_Image ERROR: Image type not Supported in this RELEASE\n"); return VX_ERROR_INVALID_FORMAT; + } + + Mat * m_cv; m_cv = new Mat(height, width, CV_format); Mat *pMat = (Mat *)m_cv; + vx_rectangle_t rect; rect.start_x = 0; rect.start_y = 0; rect.end_x = width; rect.end_y = height; + + vx_uint8 *src[4] = { NULL, NULL, NULL, NULL }; vx_uint32 p; void *ptr = NULL; + vx_imagepatch_addressing_t addr[4] = {}; vx_uint32 y = 0u; + + for (p = 0u; (p < planes); p++) + { + STATUS_ERROR_CHECK(vxAccessImagePatch(image, &rect, p, &addr[p], (void **)&src[p], VX_READ_ONLY)); + size_t len = addr[p].stride_x * (addr[p].dim_x * addr[p].scale_x) / VX_SCALE_UNITY; + for (y = 0; y < height; y += addr[p].step_y) + { + ptr = vxFormatImagePatchAddress2d(src[p], 0, y - rect.start_y, &addr[p]); + memcpy(pMat->data + y * pMat->step, ptr, len); + } + } + + for (p = 0u; p < planes; p++) + STATUS_ERROR_CHECK(vxCommitImagePatch(image, &rect, p, &addr[p], src[p])); + + *mat = pMat; + + return status; +} + +/************************************************************************************************************ +Converting CV Image into an OpenVX Image +*************************************************************************************************************/ +int CV_to_VX_Image(vx_image image, Mat* mat) +{ + vx_status status = VX_SUCCESS; vx_uint32 width = 0; vx_uint32 height = 0; vx_size planes = 0; + + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_WIDTH, &width, sizeof(width))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_HEIGHT, &height, sizeof(height))); + STATUS_ERROR_CHECK(vxQueryImage(image, VX_IMAGE_ATTRIBUTE_PLANES, &planes, sizeof(planes))); + + Mat *pMat = mat; vx_rectangle_t rect; rect.start_x = 0; rect.start_y = 0; rect.end_x = width; rect.end_y = height; + + vx_uint8 *src[4] = { NULL, NULL, NULL, NULL }; vx_uint32 p; void *ptr = NULL; + vx_imagepatch_addressing_t addr[4] = {}; vx_uint32 y = 0u; + + for (p = 0u; (p < planes); p++) + { + STATUS_ERROR_CHECK(vxAccessImagePatch(image, &rect, p, &addr[p], (void **)&src[p], VX_READ_ONLY)); + size_t len = addr[p].stride_x * (addr[p].dim_x * addr[p].scale_x) / VX_SCALE_UNITY; + for (y = 0; y < height; y += addr[p].step_y) + { + ptr = vxFormatImagePatchAddress2d(src[p], 0, y - rect.start_y, &addr[p]); + memcpy(ptr, pMat->data + y * pMat->step, len); + } + } + + for (p = 0u; p < planes; p++) + STATUS_ERROR_CHECK(vxCommitImagePatch(image, &rect, p, &addr[p], src[p])); + + return status; +} + +/************************************************************************************************************ +sort function. +*************************************************************************************************************/ +bool sortbysize_CV(const KeyPoint &lhs, const KeyPoint &rhs) +{ + return lhs.size < rhs.size; +} + +/************************************************************************************************************ +OpenCV Keypoints to OpenVX Keypoints +*************************************************************************************************************/ +int CV_to_VX_keypoints(vector key_points, vx_array array) +{ + + vx_status status = VX_SUCCESS; + vector Keypoint_VX; + + float X, Y, K_Size, K_Angle, K_Response; int x, y, j = 0; + // void *ptr = NULL; + vx_size size = 0; + + STATUS_ERROR_CHECK(vxQueryArray(array, VX_ARRAY_ATTRIBUTE_CAPACITY, &size, sizeof(size))); + + size_t S = key_points.size(); Keypoint_VX.resize(S); + sort(key_points.begin(), key_points.end(), sortbysize_CV); + // vx_size stride = 0; void *base = NULL; vx_size L = 0; + + for (vector::const_iterator i = key_points.begin(); i != key_points.end(); ++i) + { + X = key_points[j].pt.x; Y = key_points[j].pt.y; + K_Size = key_points[j].size; K_Angle = key_points[j].angle; K_Response = key_points[j].response; + + if (fmod(X, 1) >= 0.5)x = (int)ceil(X); else x = (int)floor(X); + if (fmod(Y, 1) >= 0.5)y = (int)ceil(Y); else y = (int)floor(Y); + + Keypoint_VX[j].x = x; Keypoint_VX[j].y = y; + Keypoint_VX[j].strength = K_Size; Keypoint_VX[j].orientation = K_Angle; Keypoint_VX[j].scale = K_Response; + Keypoint_VX[j].tracking_status = 1; Keypoint_VX[j].error = 0; + j++; + } + + vx_keypoint_t * keypoint_ptr = &Keypoint_VX[0]; size = min(size, S); + + status = vxTruncateArray(array, 0); + if (status){ vxAddLogEntry((vx_reference)array, status, "CV_to_VX_keypoints ERROR: vxTruncateArray failed\n"); return status; } + + status = vxAddArrayItems(array, size, keypoint_ptr, sizeof(vx_keypoint_t)); + if (status){ vxAddLogEntry((vx_reference)array, status, "CV_to_VX_keypoints ERROR: vxAddArrayItems failed\n"); return status; } + + return status; +} + +/************************************************************************************************************ +OpenCV Points to OpenVX Keypoints +*************************************************************************************************************/ +int CVPoints2f_to_VX_keypoints(vector key_points, vx_array array) +{ + vx_status status = VX_SUCCESS; + vector Keypoint_VX; float X, Y; int x, y, j = 0; + // void *ptr = NULL; + vx_size size = 0; + + STATUS_ERROR_CHECK(vxQueryArray(array, VX_ARRAY_ATTRIBUTE_CAPACITY, &size, sizeof(size))); + + size_t S = key_points.size(); Keypoint_VX.resize(S); + + for (int i = 0; i < (int)key_points.size(); ++i) + { + X = key_points[j].x; Y = key_points[j].y; + + if (fmod(X, 1) >= 0.5)x = (int)ceil(X); else x = (int)floor(X); + if (fmod(Y, 1) >= 0.5)y = (int)ceil(Y); else y = (int)floor(Y); + + Keypoint_VX[j].x = x; Keypoint_VX[j].y = y; + Keypoint_VX[j].strength = 0; Keypoint_VX[j].orientation = 0; Keypoint_VX[j].scale = 0; + Keypoint_VX[j].tracking_status = 0; Keypoint_VX[j].error = 0; + + j++; + } + + vx_keypoint_t * keypoint_ptr = &Keypoint_VX[0]; size = min(size, S); + + status = vxTruncateArray(array, 0); + if (status){ vxAddLogEntry((vx_reference)array, status, "CVPoints2f_to_VX_keypoints ERROR: vxTruncateArray failed\n"); return status; } + + status = vxAddArrayItems(array, size, keypoint_ptr, sizeof(vx_keypoint_t)); + if (status){ vxAddLogEntry((vx_reference)array, status, "CVPoints2f_to_VX_keypoints ERROR: vxAddArrayItems failed\n"); return status; } + + return status; + +} + +/************************************************************************************************************ +OpenCV Descriptors to OpenVX Descriptors +*************************************************************************************************************/ +int CV_DESP_to_VX_DESP(Mat mat, vx_array array, int stride) +{ + vx_status status = VX_SUCCESS; vx_size size = 0; + + STATUS_ERROR_CHECK(vxQueryArray(array, VX_ARRAY_ATTRIBUTE_CAPACITY, &size, sizeof(size))); + + uchar *p = mat.data; + + status = vxTruncateArray(array, 0); + if (status){ vxAddLogEntry((vx_reference)array, status, "CV_DESP_to_VX_DESP ERROR: vxTruncateArray failed\n"); return status; } + + status = vxAddArrayItems(array, size, p, stride); + if (status){ vxAddLogEntry((vx_reference)array, status, "CV_DESP_to_VX_DESP ERROR: vxAddArrayItems failed\n"); return status; } + + return status; +} + +/************************************************************************************************************ +Match VX in and out image size +*************************************************************************************************************/ +int match_vx_image_parameters(vx_image image1, vx_image image2) +{ + vx_status status = VX_SUCCESS; + vx_uint32 W1 = 0; vx_uint32 H1 = 0; + STATUS_ERROR_CHECK(vxQueryImage(image1, VX_IMAGE_ATTRIBUTE_WIDTH, &W1, sizeof(W1))); + STATUS_ERROR_CHECK(vxQueryImage(image1, VX_IMAGE_ATTRIBUTE_HEIGHT, &H1, sizeof(H1))); + + vx_uint32 W2 = 0; vx_uint32 H2 = 0; + STATUS_ERROR_CHECK(vxQueryImage(image2, VX_IMAGE_ATTRIBUTE_WIDTH, &W2, sizeof(W2))); + STATUS_ERROR_CHECK(vxQueryImage(image2, VX_IMAGE_ATTRIBUTE_HEIGHT, &H2, sizeof(H2))); + + //Input and Output image size match check + if (W1 != W2 || H1 != H2) + { + status = VX_ERROR_INVALID_DIMENSION; + vxAddLogEntry((vx_reference)image1, status, "match_vx_image_parameters ERROR: Image1 Height or Width Not Equal to Image2\n"); + return status; + } + + return status; +} diff --git a/samples/bubble-pop/source/internal_publishKernels.cpp b/samples/bubble-pop/source/internal_publishKernels.cpp new file mode 100644 index 00000000..ccf74b0a --- /dev/null +++ b/samples/bubble-pop/source/internal_publishKernels.cpp @@ -0,0 +1,63 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "internal_publishKernels.h" + +#include "vx_ext_pop.h" + +/********************************************************************** + PUBLIC FUNCTION for VX POP user defined functions + **********************************************************************/ +extern "C" SHARED_PUBLIC vx_status VX_API_CALL vxPublishKernels(vx_context context) +{ + vx_status status = VX_SUCCESS; + printf("vxPublishKernels\n"); + + STATUS_ERROR_CHECK(get_kernels_to_publish()); + STATUS_ERROR_CHECK(Kernel_List->PUBLISH(context)); + + return status; +} + +/************************************************************************************************************ +Add All Kernels to the Kernel List +*************************************************************************************************************/ +vx_status get_kernels_to_publish() +{ + vx_status status = VX_SUCCESS; + + Kernel_List = new Kernellist(MAX_KERNELS); + + STATUS_ERROR_CHECK(ADD_KERENEL(VX_bubbles_pop_Register)); + STATUS_ERROR_CHECK(ADD_KERENEL(VX_donut_pop_Register)); + return status; +} + +/************************************************************************************************************ +Add Kernels to the Kernel List +*************************************************************************************************************/ +vx_status ADD_KERENEL(std::function func) +{ + vx_status status = VX_SUCCESS; + STATUS_ERROR_CHECK(Kernel_List->ADD(func)); + return status; +} \ No newline at end of file diff --git a/samples/bubble-pop/source/internal_vxNodes.cpp b/samples/bubble-pop/source/internal_vxNodes.cpp new file mode 100644 index 00000000..b562030b --- /dev/null +++ b/samples/bubble-pop/source/internal_vxNodes.cpp @@ -0,0 +1,105 @@ +/* +Copyright (c) 2020 Advanced Micro Devices, Inc. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#include "internal_publishKernels.h" +#include "vx_ext_pop.h" + +vx_node vxCreateNodeByStructure(vx_graph graph, + vx_enum kernelenum, + vx_reference params[], + vx_uint32 num) +{ + vx_status status = VX_SUCCESS; + vx_node node = 0; + vx_context context = vxGetContext((vx_reference)graph); + vx_kernel kernel = vxGetKernelByEnum(context, kernelenum); + if (kernel) + { + node = vxCreateGenericNode(graph, kernel); + if (node) + { + vx_uint32 p = 0; + for (p = 0; p < num; p++) + { + if (params[p]) + { + status = vxSetParameterByIndex(node, + p, + params[p]); + if (status != VX_SUCCESS) + { + vxAddLogEntry((vx_reference)graph, status, "Kernel %d Parameter %u is invalid.\n", kernelenum, p); + vxReleaseNode(&node); + node = 0; + break; + } + } + } + } + else + { + vxAddLogEntry((vx_reference)graph, VX_ERROR_INVALID_PARAMETERS, "Failed to create node with kernel enum %d\n", kernelenum); + status = VX_ERROR_NO_MEMORY; + } + vxReleaseKernel(&kernel); + } + else + { + vxAddLogEntry((vx_reference)graph, VX_ERROR_INVALID_PARAMETERS, "failed to retrieve kernel enum %d\n", kernelenum); + status = VX_ERROR_NOT_SUPPORTED; + } + return node; +} + +/******************************************************************************************************************* +Bubble Pop C Function +*******************************************************************************************************************/ +extern "C" SHARED_PUBLIC vx_node VX_API_CALL vxExtPopNode_bubblePop(vx_graph graph, vx_image input, vx_image output) +{ + + vx_reference params[] = { + (vx_reference)input, + (vx_reference)output, + }; + + return vxCreateNodeByStructure(graph, + VX_KERNEL_EXT_POP_BUBBLE_POP, + params, + dimof(params)); +} + +/******************************************************************************************************************* +Donut Pop C Function +*******************************************************************************************************************/ +extern "C" SHARED_PUBLIC vx_node VX_API_CALL vxExtPopNode_donutPop(vx_graph graph, vx_image input, vx_image output) +{ + + vx_reference params[] = { + (vx_reference)input, + (vx_reference)output, + }; + + return vxCreateNodeByStructure(graph, + VX_KERNEL_EXT_POP_DONUT_POP, + params, + dimof(params)); +} \ No newline at end of file diff --git a/samples/canny-edge-detector/BUILD b/samples/canny-edge-detector/BUILD new file mode 100644 index 00000000..73434a1a --- /dev/null +++ b/samples/canny-edge-detector/BUILD @@ -0,0 +1,21 @@ + +cc_binary( + name = "canny-edge-detector", + srcs = [ + "src/canny.cpp", + ], + deps = [ + "//:corevx", + "@opencv", + "//targets/ai_server:imported_openvx_ai_server", + "//targets/c_model:imported_openvx_c_model", + "//targets/debug:imported_openvx_debug", + "//targets/extras:imported_openvx_extras", + "//targets/liteRT:imported_openvx_liteRT", + "//targets/opencl:imported_openvx_opencl", + "//targets/onnxRT:imported_openvx_onnxRT", + "//targets/executorch:imported_openvx_torch", + "//third_party:opencv-prebuilt", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/samples/canny-edge-detector/README.md b/samples/canny-edge-detector/README.md new file mode 100644 index 00000000..44e61d55 --- /dev/null +++ b/samples/canny-edge-detector/README.md @@ -0,0 +1,64 @@ +## Canny Edge Detector Sample +In this sample we will create an OpenVX graph to run canny edge detection on an image or a live camera. This sample application uses OpenCV to decode input image and display the output. + +

+ +### Prerequisites + +* [Conformant OpenVX Implementation](https://github.com/KhronosGroup/Khronosdotorg/blob/master/api/openvx/resources.md) + +* [OpenCV](https://github.com/opencv/opencv/releases/tag/3.4.0) + +### Steps to run the canny sample + +* **Step - 1:** Build and install [Conformant OpenVX Implementation](https://github.com/KhronosGroup/OpenVX-sample-impl). In this example we will use the OpenVX Sample Implementation available on [GitHub](https://github.com/KhronosGroup/OpenVX-sample-impl) + +``` +Build OpenVX on Linux + +* Git Clone project with a recursive flag to get submodules + + git clone --recursive https://github.com/KhronosGroup/OpenVX-sample-impl.git + +* Use Build.py script + + cd OpenVX-sample-impl/ + python Build.py --os=Linux --arch=64 --conf=Debug --conf_vision --enh_vision --conf_nn +``` + +* **Step - 2:** Export OpenVX Directory Path + +``` +export OPENVX_DIR=$(pwd)/install/Linux/x64/Debug +``` + +* **Step - 3:** Clone the OpenVX Samples project and build the canny application + +``` +cd ~/ && mkdir OpenVXSample-canny +cd OpenVXSample-canny/ +git clone https://github.com/kiritigowda/openvx-samples.git +``` + +* **Step - 4:** CMake and Build the canny application + +``` +mkdir canny-build && cd canny-build +cmake -DOPENVX_INCLUDES=$OPENVX_DIR/include -DOPENVX_LIBRARIES=$OPENVX_DIR/bin/libopenvx.so ../openvx-samples/canny-edge-detector/ +make +``` + +* **Step - 5:** Run Canny application + + * **Live** + + ``` + ./cannyEdgeDetector --live + ``` + + * **Image** + + ```` + ./cannyEdgeDetector --image ../openvx-samples/images/face.png + ```` +

diff --git a/samples/canny-edge-detector/src/canny.cpp b/samples/canny-edge-detector/src/canny.cpp new file mode 100644 index 00000000..c8bf4466 --- /dev/null +++ b/samples/canny-edge-detector/src/canny.cpp @@ -0,0 +1,193 @@ +#include + +#include +#include +#include +#include +#include + +using namespace cv; +using namespace std; + +#define ERROR_CHECK_STATUS(status) \ + { \ + vx_status status_ = (status); \ + if (status_ != VX_SUCCESS) \ + { \ + printf("ERROR: failed with status = (%d) at " __FILE__ "#%d\n", status_, __LINE__); \ + exit(1); \ + } \ + } + +#define ERROR_CHECK_OBJECT(obj) \ + { \ + vx_status status_ = vxGetStatus((vx_reference)(obj)); \ + if (status_ != VX_SUCCESS) \ + { \ + printf("ERROR: failed with status = (%d) at " __FILE__ "#%d\n", status_, __LINE__); \ + exit(1); \ + } \ + } + +static void VX_CALLBACK log_callback(vx_context context, vx_reference ref, vx_status status, + const vx_char string[]) +{ + (void)context; + (void)ref; + (void)status; + size_t len = strlen(string); + if (len > 0) + { + printf("%s", string); + if (string[len - 1] != '\n') printf("\n"); + fflush(stdout); + } +} + +int main(int argc, char **argv) +{ + if (argc < 2) + { + printf( + "Usage:\n" + "./cannyDetect --image \n" + "./cannyDetect --live \n"); + return 0; + } + + int width = 480, height = 360; + + vx_context context = vxCreateContext(); + ERROR_CHECK_OBJECT(context); + vxRegisterLogCallback(context, log_callback, vx_false_e); + + vx_graph graph = vxCreateGraph(context); + ERROR_CHECK_OBJECT(graph); + + vx_image input_rgb_image = vxCreateImage(context, width, height, VX_DF_IMAGE_RGB); + vx_image output_filtered_image = vxCreateImage(context, width, height, VX_DF_IMAGE_U8); + ERROR_CHECK_OBJECT(input_rgb_image); + ERROR_CHECK_OBJECT(output_filtered_image); + + vx_image yuv_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_IYUV); + vx_image luma_image = vxCreateVirtualImage(graph, width, height, VX_DF_IMAGE_U8); + ERROR_CHECK_OBJECT(yuv_image); + ERROR_CHECK_OBJECT(luma_image); + + vx_threshold hyst = vxCreateThreshold(context, VX_THRESHOLD_TYPE_RANGE, VX_TYPE_UINT8); + vx_int32 lower = 80, upper = 100; + vxSetThresholdAttribute(hyst, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER, &lower, sizeof(lower)); + vxSetThresholdAttribute(hyst, VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER, &upper, sizeof(upper)); + ERROR_CHECK_OBJECT(hyst); + vx_int32 gradient_size = 3; + + vx_node nodes[] = {vxColorConvertNode(graph, input_rgb_image, yuv_image), + vxChannelExtractNode(graph, yuv_image, VX_CHANNEL_Y, luma_image), + vxCannyEdgeDetectorNode(graph, luma_image, hyst, gradient_size, VX_NORM_L1, + output_filtered_image)}; + + for (vx_size i = 0; i < sizeof(nodes) / sizeof(nodes[0]); i++) + { + ERROR_CHECK_OBJECT(nodes[i]); + ERROR_CHECK_STATUS(vxReleaseNode(&nodes[i])); + } + + ERROR_CHECK_STATUS(vxVerifyGraph(graph)); + + string option = argv[1]; + Mat input; + + if (option == "--image") + { + string imageLocation = argv[2]; + input = imread(imageLocation.c_str()); + if (input.empty()) + { + printf("Image not found\n"); + return 0; + } + resize(input, input, Size(width, height)); + imshow("inputWindow", input); + vx_rectangle_t cv_rgb_image_region; + cv_rgb_image_region.start_x = 0; + cv_rgb_image_region.start_y = 0; + cv_rgb_image_region.end_x = width; + cv_rgb_image_region.end_y = height; + vx_imagepatch_addressing_t cv_rgb_image_layout{}; + cv_rgb_image_layout.dim_x = input.cols; + cv_rgb_image_layout.dim_y = input.rows; + cv_rgb_image_layout.stride_x = input.elemSize(); + cv_rgb_image_layout.stride_y = input.step; + vx_uint8 *cv_rgb_image_buffer = input.data; + ERROR_CHECK_STATUS(vxCopyImagePatch(input_rgb_image, &cv_rgb_image_region, 0, + &cv_rgb_image_layout, cv_rgb_image_buffer, + VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); + ERROR_CHECK_STATUS(vxProcessGraph(graph)); + vx_rectangle_t rect = {0, 0, (vx_uint32)width, (vx_uint32)height}; + vx_map_id map_id; + vx_imagepatch_addressing_t addr; + void *ptr; + ERROR_CHECK_STATUS(vxMapImagePatch(output_filtered_image, &rect, 0, &map_id, &addr, &ptr, + VX_READ_ONLY, VX_MEMORY_TYPE_HOST, VX_NOGAP_X)); + Mat mat(height, width, CV_8U, ptr, addr.stride_y); + imshow("CannyDetect", mat); + waitKey(0); + ERROR_CHECK_STATUS(vxUnmapImagePatch(output_filtered_image, map_id)); + } + else if (option == "--live") + { + VideoCapture cap(0); + if (!cap.isOpened()) + { + printf("Unable to open camera\n"); + return 0; + } + for (;;) + { + cap >> input; + resize(input, input, Size(width, height)); + imshow("inputWindow", input); + if (waitKey(30) >= 0) break; + vx_rectangle_t cv_rgb_image_region; + cv_rgb_image_region.start_x = 0; + cv_rgb_image_region.start_y = 0; + cv_rgb_image_region.end_x = width; + cv_rgb_image_region.end_y = height; + vx_imagepatch_addressing_t cv_rgb_image_layout; + cv_rgb_image_layout.stride_x = 3; + cv_rgb_image_layout.stride_y = input.step; + vx_uint8 *cv_rgb_image_buffer = input.data; + ERROR_CHECK_STATUS(vxCopyImagePatch(input_rgb_image, &cv_rgb_image_region, 0, + &cv_rgb_image_layout, cv_rgb_image_buffer, + VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST)); + ERROR_CHECK_STATUS(vxProcessGraph(graph)); + vx_rectangle_t rect = {0, 0, (vx_uint32)width, (vx_uint32)height}; + vx_map_id map_id; + vx_imagepatch_addressing_t addr; + void *ptr; + ERROR_CHECK_STATUS(vxMapImagePatch(output_filtered_image, &rect, 0, &map_id, &addr, + &ptr, VX_READ_ONLY, VX_MEMORY_TYPE_HOST, + VX_NOGAP_X)); + Mat mat(height, width, CV_8U, ptr, addr.stride_y); + imshow("CannyDetect", mat); + if (waitKey(30) >= 0) break; + ERROR_CHECK_STATUS(vxUnmapImagePatch(output_filtered_image, map_id)); + } + } + else + { + printf( + "Usage:\n" + "./cannyDetect --image \n" + "./cannyDetect --live \n"); + return 0; + } + + ERROR_CHECK_STATUS(vxReleaseGraph(&graph)); + ERROR_CHECK_STATUS(vxReleaseImage(&yuv_image)); + ERROR_CHECK_STATUS(vxReleaseImage(&luma_image)); + ERROR_CHECK_STATUS(vxReleaseImage(&input_rgb_image)); + ERROR_CHECK_STATUS(vxReleaseImage(&output_filtered_image)); + ERROR_CHECK_STATUS(vxReleaseContext(&context)); + return 0; +} diff --git a/samples/images/canny-app.png b/samples/images/canny-app.png new file mode 100644 index 00000000..dff4e8ee Binary files /dev/null and b/samples/images/canny-app.png differ diff --git a/samples/images/canny_image.PNG b/samples/images/canny_image.PNG new file mode 100644 index 00000000..c67c2731 Binary files /dev/null and b/samples/images/canny_image.PNG differ diff --git a/samples/images/face.png b/samples/images/face.png new file mode 100644 index 00000000..5c1fd6a8 Binary files /dev/null and b/samples/images/face.png differ diff --git a/samples/images/orb_kp.jpg b/samples/images/orb_kp.jpg new file mode 100644 index 00000000..eb58247e Binary files /dev/null and b/samples/images/orb_kp.jpg differ diff --git a/samples/images/skintone-detect-app.png b/samples/images/skintone-detect-app.png new file mode 100644 index 00000000..e0f3219c Binary files /dev/null and b/samples/images/skintone-detect-app.png differ diff --git a/samples/images/vx-pop-app.gif b/samples/images/vx-pop-app.gif new file mode 100644 index 00000000..7ea1e305 Binary files /dev/null and b/samples/images/vx-pop-app.gif differ diff --git a/samples/optical_flow/BUILD b/samples/optical_flow/BUILD new file mode 100644 index 00000000..b7bf613b --- /dev/null +++ b/samples/optical_flow/BUILD @@ -0,0 +1,22 @@ + + +cc_binary( + name = "optical_flow", + srcs = [ + "source/optical_flow.cpp", + ], + deps = [ + "//:corevx", + "@opencv", + "//targets/ai_server:imported_openvx_ai_server", + "//targets/c_model:imported_openvx_c_model", + "//targets/debug:imported_openvx_debug", + "//targets/extras:imported_openvx_extras", + "//targets/liteRT:imported_openvx_liteRT", + "//targets/opencl:imported_openvx_opencl", + "//targets/onnxRT:imported_openvx_onnxRT", + "//targets/executorch:imported_openvx_torch", + "//third_party:opencv-prebuilt", + ], + visibility = ["//visibility:public"], +) \ No newline at end of file diff --git a/samples/optical_flow/README.md b/samples/optical_flow/README.md new file mode 100644 index 00000000..4ccc5b80 --- /dev/null +++ b/samples/optical_flow/README.md @@ -0,0 +1,63 @@ +## Optical Flow Sample + +In this sample we will create an OpenVX graph to run Optical Flow on a video/live. This sample application uses OpenCV to decode input video and display the output. + +

+ +### Prerequisites + +* [Conformant OpenVX Implementation](https://github.com/ROCm/MIVisionX) + +* [OpenCV](https://github.com/opencv/opencv/releases/tag/3.4.0) + + +### Steps to run the Optical Flow sample + +* **Step - 1:** Build and install [Conformant OpenVX Implementation](https://github.com/ROCm/MIVisionX). + +``` +Build OpenVX on Linux + +* Git Clone project + + git clone https://github.com/ROCm/MIVisionX.git + +* Use CMake to build + + mkdir build && cd build + cmake ../MIVisionX + make -j8 + sudo make install +``` + +* **Step - 2:** Export OpenVX Directory Path + +``` +export OPENVX_DIR=/opt/rocm/ +``` + + +* **Step - 3:** CMake and Build the optical flow application + +``` +mkdir opticalFlow-build && cd opticalFlow-build +cmake -DOPENVX_INCLUDES=$OPENVX_DIR/include/mivisionx -DOPENVX_LIBRARIES=$OPENVX_DIR/lib/libopenvx.so ../optical_flow +make +``` + +* **Step - 4:** Run VX Optical Flow application + + ``` + Usage: + ./opticalFlow --video