parent
b54bc2db1e
commit
5c969d1972
5 changed files with 891 additions and 0 deletions
@ -0,0 +1,36 @@ |
|||||||
|
cmake_minimum_required(VERSION 2.8.9) |
||||||
|
|
||||||
|
set(OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS opencv_core opencv_imgproc opencv_imgcodecs opencv_videoio opencv_highgui) |
||||||
|
|
||||||
|
ocv_check_dependencies(${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS}) |
||||||
|
|
||||||
|
if(BUILD_EXAMPLES AND OCV_DEPENDENCIES_FOUND) |
||||||
|
set(group "openvx") |
||||||
|
set(name_wrapped "interop") |
||||||
|
set(name_orig "interop_orig") |
||||||
|
set(name_video "interop_video") |
||||||
|
|
||||||
|
project("${group}_sample") |
||||||
|
|
||||||
|
ocv_include_modules_recurse(${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS}) |
||||||
|
|
||||||
|
add_definitions(-DIVX_USE_OPENCV) |
||||||
|
|
||||||
|
file(GLOB srcs_wrapped wrappers.cpp *.hpp) |
||||||
|
file(GLOB srcs_orig no_wrappers.cpp *.hpp) |
||||||
|
file(GLOB srcs_video wrappers_video.cpp *.hpp) |
||||||
|
|
||||||
|
MACRO(OPENVX_DEFINE_SAMPLE name srcs) |
||||||
|
set(target "example_${group}_${name}") |
||||||
|
add_executable(${target} ${srcs}) |
||||||
|
ocv_target_link_libraries(${target} ${OPENCV_LINKER_LIBS} ${OPENCV_OPENVX_SAMPLE_REQUIRED_DEPS} ${OPENVX_LIBRARIES}) |
||||||
|
if(ENABLE_SOLUTION_FOLDERS) |
||||||
|
set_target_properties(${target} PROPERTIES FOLDER "samples//${group}") |
||||||
|
endif() |
||||||
|
ENDMACRO() |
||||||
|
|
||||||
|
OPENVX_DEFINE_SAMPLE(${name_wrapped} ${srcs_wrapped}) |
||||||
|
OPENVX_DEFINE_SAMPLE(${name_orig} ${srcs_orig}) |
||||||
|
OPENVX_DEFINE_SAMPLE(${name_video} ${srcs_video}) |
||||||
|
|
||||||
|
endif() |
@ -0,0 +1,382 @@ |
|||||||
|
#include <iostream> |
||||||
|
#include <stdexcept> |
||||||
|
|
||||||
|
//OpenVX includes
|
||||||
|
#include <VX/vx.h> |
||||||
|
|
||||||
|
//OpenCV includes
|
||||||
|
#include "opencv2/core.hpp" |
||||||
|
#include "opencv2/imgproc.hpp" |
||||||
|
#include "opencv2/imgcodecs.hpp" |
||||||
|
#include "opencv2/highgui.hpp" |
||||||
|
|
||||||
|
#ifndef VX_VERSION_1_1 |
||||||
|
const vx_enum VX_IMAGE_FORMAT = VX_IMAGE_ATTRIBUTE_FORMAT; |
||||||
|
const vx_enum VX_IMAGE_WIDTH = VX_IMAGE_ATTRIBUTE_WIDTH; |
||||||
|
const vx_enum VX_IMAGE_HEIGHT = VX_IMAGE_ATTRIBUTE_HEIGHT; |
||||||
|
const vx_enum VX_MEMORY_TYPE_HOST = VX_IMPORT_TYPE_HOST; |
||||||
|
const vx_enum VX_MEMORY_TYPE_NONE = VX_IMPORT_TYPE_NONE; |
||||||
|
const vx_enum VX_THRESHOLD_THRESHOLD_VALUE = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_VALUE; |
||||||
|
const vx_enum VX_THRESHOLD_THRESHOLD_LOWER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_LOWER; |
||||||
|
const vx_enum VX_THRESHOLD_THRESHOLD_UPPER = VX_THRESHOLD_ATTRIBUTE_THRESHOLD_UPPER; |
||||||
|
typedef uintptr_t vx_map_id; |
||||||
|
#endif |
||||||
|
|
||||||
|
enum UserMemoryMode |
||||||
|
{ |
||||||
|
COPY, MAP_TO_VX |
||||||
|
}; |
||||||
|
|
||||||
|
vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy) |
||||||
|
{ |
||||||
|
if (!(!image.empty() && image.dims <= 2 && image.channels() == 1)) |
||||||
|
throw std::runtime_error("Invalid format"); |
||||||
|
|
||||||
|
vx_uint32 width = image.cols; |
||||||
|
vx_uint32 height = image.rows; |
||||||
|
|
||||||
|
vx_df_image color; |
||||||
|
switch (image.depth()) |
||||||
|
{ |
||||||
|
case CV_8U: |
||||||
|
color = VX_DF_IMAGE_U8; |
||||||
|
break; |
||||||
|
case CV_16U: |
||||||
|
color = VX_DF_IMAGE_U16; |
||||||
|
break; |
||||||
|
case CV_16S: |
||||||
|
color = VX_DF_IMAGE_S16; |
||||||
|
break; |
||||||
|
case CV_32S: |
||||||
|
color = VX_DF_IMAGE_S32; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw std::runtime_error("Invalid format"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
vx_imagepatch_addressing_t addr; |
||||||
|
addr.dim_x = width; |
||||||
|
addr.dim_y = height; |
||||||
|
addr.stride_x = (vx_uint32)image.elemSize(); |
||||||
|
addr.stride_y = (vx_uint32)image.step.p[0]; |
||||||
|
vx_uint8* ovxData = image.data; |
||||||
|
|
||||||
|
vx_image ovxImage; |
||||||
|
if (toCopy) |
||||||
|
{ |
||||||
|
ovxImage = vxCreateImage(context, width, height, color); |
||||||
|
if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to create image"); |
||||||
|
vx_rectangle_t rect; |
||||||
|
|
||||||
|
vx_status status = vxGetValidRegionImage(ovxImage, &rect); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to get valid region"); |
||||||
|
|
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, ovxData, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to copy image patch"); |
||||||
|
#else |
||||||
|
status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&ovxData, VX_WRITE_ONLY); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to access image patch"); |
||||||
|
status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, ovxData); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to commit image patch"); |
||||||
|
#endif |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
ovxImage = vxCreateImageFromHandle(context, color, &addr, (void*const*)&ovxData, VX_MEMORY_TYPE_HOST); |
||||||
|
#else |
||||||
|
ovxImage = vxCreateImageFromHandle(context, color, &addr, (void**)&ovxData, VX_MEMORY_TYPE_HOST); |
||||||
|
#endif |
||||||
|
if (vxGetStatus((vx_reference)ovxImage) != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to create image from handle"); |
||||||
|
} |
||||||
|
|
||||||
|
return ovxImage; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
cv::Mat copyVxImageToCvMat(vx_image ovxImage) |
||||||
|
{ |
||||||
|
vx_status status; |
||||||
|
vx_df_image df_image = 0; |
||||||
|
vx_uint32 width, height; |
||||||
|
status = vxQueryImage(ovxImage, VX_IMAGE_FORMAT, &df_image, sizeof(vx_df_image)); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to query image"); |
||||||
|
status = vxQueryImage(ovxImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32)); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to query image"); |
||||||
|
status = vxQueryImage(ovxImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32)); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to query image"); |
||||||
|
|
||||||
|
if (!(width > 0 && height > 0)) throw std::runtime_error("Invalid format"); |
||||||
|
|
||||||
|
int depth; |
||||||
|
switch (df_image) |
||||||
|
{ |
||||||
|
case VX_DF_IMAGE_U8: |
||||||
|
depth = CV_8U; |
||||||
|
break; |
||||||
|
case VX_DF_IMAGE_U16: |
||||||
|
depth = CV_16U; |
||||||
|
break; |
||||||
|
case VX_DF_IMAGE_S16: |
||||||
|
depth = CV_16S; |
||||||
|
break; |
||||||
|
case VX_DF_IMAGE_S32: |
||||||
|
depth = CV_32S; |
||||||
|
break; |
||||||
|
default: |
||||||
|
throw std::runtime_error("Invalid format"); |
||||||
|
break; |
||||||
|
} |
||||||
|
|
||||||
|
cv::Mat image(height, width, CV_MAKE_TYPE(depth, 1)); |
||||||
|
|
||||||
|
vx_rectangle_t rect; |
||||||
|
rect.start_x = rect.start_y = 0; |
||||||
|
rect.end_x = width; rect.end_y = height; |
||||||
|
|
||||||
|
vx_imagepatch_addressing_t addr; |
||||||
|
addr.dim_x = width; |
||||||
|
addr.dim_y = height; |
||||||
|
addr.stride_x = (vx_uint32)image.elemSize(); |
||||||
|
addr.stride_y = (vx_uint32)image.step.p[0]; |
||||||
|
vx_uint8* matData = image.data; |
||||||
|
|
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
status = vxCopyImagePatch(ovxImage, &rect, 0, &addr, matData, VX_READ_ONLY, VX_MEMORY_TYPE_HOST); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to copy image patch"); |
||||||
|
#else |
||||||
|
status = vxAccessImagePatch(ovxImage, &rect, 0, &addr, (void**)&matData, VX_READ_ONLY); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to access image patch"); |
||||||
|
status = vxCommitImagePatch(ovxImage, &rect, 0, &addr, matData); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to commit image patch"); |
||||||
|
#endif |
||||||
|
|
||||||
|
return image; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
void swapVxImage(vx_image ovxImage) |
||||||
|
{ |
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
vx_status status; |
||||||
|
vx_memory_type_e memType; |
||||||
|
status = vxQueryImage(ovxImage, VX_IMAGE_MEMORY_TYPE, &memType, sizeof(vx_memory_type_e)); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to query image"); |
||||||
|
if (memType == VX_MEMORY_TYPE_NONE) |
||||||
|
{ |
||||||
|
//was created by copying user data
|
||||||
|
throw std::runtime_error("Image wasn't created from user handle"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//was created from user handle
|
||||||
|
status = vxSwapImageHandle(ovxImage, NULL, NULL, 0); |
||||||
|
if (status != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to swap image handle"); |
||||||
|
} |
||||||
|
#else |
||||||
|
//not supported until OpenVX 1.1
|
||||||
|
(void) ovxImage; |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph) |
||||||
|
{ |
||||||
|
vx_status status; |
||||||
|
vx_context context = vxGetContext((vx_reference)inputImage); |
||||||
|
status = vxGetStatus((vx_reference)context); |
||||||
|
if(status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
graph = vxCreateGraph(context); |
||||||
|
status = vxGetStatus((vx_reference)graph); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
vx_uint32 width, height; |
||||||
|
status = vxQueryImage(inputImage, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32)); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
status = vxQueryImage(inputImage, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32)); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
// Intermediate images
|
||||||
|
vx_image |
||||||
|
smoothed = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT), |
||||||
|
cannied = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT), |
||||||
|
halfImg = vxCreateImage(context, width, height, VX_DF_IMAGE_U8), |
||||||
|
halfCanny = vxCreateImage(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
|
||||||
|
vx_image virtualImages[] = {smoothed, cannied, halfImg, halfCanny}; |
||||||
|
for(size_t i = 0; i < sizeof(virtualImages)/sizeof(vx_image); i++) |
||||||
|
{ |
||||||
|
status = vxGetStatus((vx_reference)virtualImages[i]); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
} |
||||||
|
|
||||||
|
// Constants
|
||||||
|
vx_uint32 threshValue = 50; |
||||||
|
vx_threshold thresh = vxCreateThreshold(context, VX_THRESHOLD_TYPE_BINARY, VX_TYPE_UINT8); |
||||||
|
vxSetThresholdAttribute(thresh, VX_THRESHOLD_THRESHOLD_VALUE, |
||||||
|
&threshValue, sizeof(threshValue)); |
||||||
|
|
||||||
|
vx_uint32 threshCannyMin = 127; |
||||||
|
vx_uint32 threshCannyMax = 192; |
||||||
|
vx_threshold threshCanny = vxCreateThreshold(context, VX_THRESHOLD_TYPE_RANGE, VX_TYPE_UINT8); |
||||||
|
vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_LOWER, &threshCannyMin, |
||||||
|
sizeof(threshCannyMin)); |
||||||
|
vxSetThresholdAttribute(threshCanny, VX_THRESHOLD_THRESHOLD_UPPER, &threshCannyMax, |
||||||
|
sizeof(threshCannyMax)); |
||||||
|
vx_float32 alphaValue = 0.5; |
||||||
|
vx_scalar alpha = vxCreateScalar(context, VX_TYPE_FLOAT32, &alphaValue); |
||||||
|
|
||||||
|
// Sequence of meaningless image operations
|
||||||
|
vx_node nodes[] = { |
||||||
|
vxGaussian3x3Node(graph, inputImage, smoothed), |
||||||
|
vxCannyEdgeDetectorNode(graph, smoothed, threshCanny, 3, VX_NORM_L2, cannied), |
||||||
|
vxAccumulateWeightedImageNode(graph, inputImage, alpha, halfImg), |
||||||
|
vxAccumulateWeightedImageNode(graph, cannied, alpha, halfCanny), |
||||||
|
vxAddNode(graph, halfImg, halfCanny, VX_CONVERT_POLICY_SATURATE, outputImage) |
||||||
|
}; |
||||||
|
|
||||||
|
for (size_t i = 0; i < sizeof(nodes) / sizeof(vx_node); i++) |
||||||
|
{ |
||||||
|
status = vxGetStatus((vx_reference)nodes[i]); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
} |
||||||
|
|
||||||
|
status = vxVerifyGraph(graph); |
||||||
|
return status; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int ovxDemo(std::string inputPath, UserMemoryMode mode) |
||||||
|
{ |
||||||
|
cv::Mat image = cv::imread(inputPath, cv::IMREAD_GRAYSCALE); |
||||||
|
if (image.empty()) return -1; |
||||||
|
|
||||||
|
//check image format
|
||||||
|
if (image.depth() != CV_8U || image.channels() != 1) return -1; |
||||||
|
|
||||||
|
vx_status status; |
||||||
|
vx_context context = vxCreateContext(); |
||||||
|
status = vxGetStatus((vx_reference)context); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
//put user data from cv::Mat to vx_image
|
||||||
|
vx_image ovxImage; |
||||||
|
ovxImage = convertCvMatToVxImage(context, image, mode == COPY); |
||||||
|
|
||||||
|
vx_uint32 width = image.cols, height = image.rows; |
||||||
|
|
||||||
|
vx_image ovxResult; |
||||||
|
cv::Mat output; |
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
//we will copy data from vx_image to cv::Mat
|
||||||
|
ovxResult = vxCreateImage(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
if (vxGetStatus((vx_reference)ovxResult) != VX_SUCCESS) |
||||||
|
throw std::runtime_error("Failed to create image"); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//create vx_image based on user data, no copying required
|
||||||
|
output = cv::Mat(height, width, CV_8U, cv::Scalar(0)); |
||||||
|
ovxResult = convertCvMatToVxImage(context, output, false); |
||||||
|
} |
||||||
|
|
||||||
|
vx_graph graph; |
||||||
|
status = createProcessingGraph(ovxImage, ovxResult, graph); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
// Graph execution
|
||||||
|
status = vxProcessGraph(graph); |
||||||
|
if (status != VX_SUCCESS) return status; |
||||||
|
|
||||||
|
//getting resulting image in cv::Mat
|
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
output = copyVxImageToCvMat(ovxResult); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
//we should take user memory back from vx_image before using it (even before reading)
|
||||||
|
swapVxImage(ovxResult); |
||||||
|
} |
||||||
|
|
||||||
|
//here output goes
|
||||||
|
cv::imshow("processing result", output); |
||||||
|
cv::waitKey(0); |
||||||
|
|
||||||
|
//we need to take user memory back before releasing the image
|
||||||
|
if (mode == MAP_TO_VX) |
||||||
|
swapVxImage(ovxImage); |
||||||
|
|
||||||
|
cv::destroyAllWindows(); |
||||||
|
|
||||||
|
status = vxReleaseContext(&context); |
||||||
|
return status; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
const std::string keys = |
||||||
|
"{help h usage ? | | }" |
||||||
|
"{image | <none> | image to be processed}" |
||||||
|
"{mode | copy | user memory interaction mode: \n" |
||||||
|
"copy: create VX images and copy data to/from them\n" |
||||||
|
"map_to_vx: use handles to user-allocated memory}" |
||||||
|
; |
||||||
|
|
||||||
|
cv::CommandLineParser parser(argc, argv, keys); |
||||||
|
parser.about("OpenVX interoperability sample demonstrating standard OpenVX API." |
||||||
|
"The application loads an image, processes it with OpenVX graph and outputs result in a window"); |
||||||
|
if (parser.has("help")) |
||||||
|
{ |
||||||
|
parser.printMessage(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
std::string imgPath = parser.get<std::string>("image"); |
||||||
|
std::string modeString = parser.get<std::string>("mode"); |
||||||
|
UserMemoryMode mode; |
||||||
|
if(modeString == "copy") |
||||||
|
{ |
||||||
|
mode = COPY; |
||||||
|
} |
||||||
|
else if(modeString == "map_to_vx") |
||||||
|
{ |
||||||
|
mode = MAP_TO_VX; |
||||||
|
} |
||||||
|
else if(modeString == "map_from_vx") |
||||||
|
{ |
||||||
|
std::cerr << modeString << " is not implemented in this sample" << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::cerr << modeString << ": unknown memory mode" << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (!parser.check()) |
||||||
|
{ |
||||||
|
parser.printErrors(); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return ovxDemo(imgPath, mode); |
||||||
|
} |
@ -0,0 +1,216 @@ |
|||||||
|
#include <iostream> |
||||||
|
#include <stdexcept> |
||||||
|
|
||||||
|
//wrappers
|
||||||
|
#include "ivx.hpp" |
||||||
|
|
||||||
|
//OpenCV includes
|
||||||
|
#include "opencv2/core.hpp" |
||||||
|
#include "opencv2/imgproc.hpp" |
||||||
|
#include "opencv2/imgcodecs.hpp" |
||||||
|
#include "opencv2/highgui.hpp" |
||||||
|
|
||||||
|
enum UserMemoryMode |
||||||
|
{ |
||||||
|
COPY, MAP_TO_VX, MAP_FROM_VX |
||||||
|
}; |
||||||
|
|
||||||
|
ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage) |
||||||
|
{ |
||||||
|
using namespace ivx; |
||||||
|
|
||||||
|
Context context = inputImage.getContext(); |
||||||
|
|
||||||
|
Graph graph = Graph::create(context); |
||||||
|
|
||||||
|
vx_uint32 width = inputImage.width(); |
||||||
|
vx_uint32 height = inputImage.height(); |
||||||
|
|
||||||
|
// Intermediate images
|
||||||
|
Image |
||||||
|
smoothed = Image::createVirtual(graph), |
||||||
|
cannied = Image::createVirtual(graph), |
||||||
|
halfImg = Image::create(context, width, height, VX_DF_IMAGE_U8), |
||||||
|
halfCanny = Image::create(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
|
||||||
|
// Constants
|
||||||
|
vx_uint32 threshCannyMin = 127; |
||||||
|
vx_uint32 threshCannyMax = 192; |
||||||
|
Threshold threshCanny = Threshold::createRange(context, VX_TYPE_UINT8, threshCannyMin, threshCannyMax); |
||||||
|
|
||||||
|
ivx::Scalar alpha = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, 0.5); |
||||||
|
|
||||||
|
// Sequence of some image operations
|
||||||
|
// Node can also be added in function-like style
|
||||||
|
nodes::gaussian3x3(graph, inputImage, smoothed); |
||||||
|
Node::create(graph, VX_KERNEL_CANNY_EDGE_DETECTOR, smoothed, threshCanny, |
||||||
|
ivx::Scalar::create<VX_TYPE_INT32>(context, 3), |
||||||
|
ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_NORM_L2), cannied); |
||||||
|
Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, inputImage, alpha, halfImg); |
||||||
|
Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, cannied, alpha, halfCanny); |
||||||
|
Node::create(graph, VX_KERNEL_ADD, halfImg, halfCanny, |
||||||
|
ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CONVERT_POLICY_SATURATE), outputImage); |
||||||
|
|
||||||
|
graph.verify(); |
||||||
|
|
||||||
|
return graph; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int ovxDemo(std::string inputPath, UserMemoryMode mode) |
||||||
|
{ |
||||||
|
using namespace cv; |
||||||
|
using namespace ivx; |
||||||
|
|
||||||
|
Mat image = imread(inputPath, IMREAD_GRAYSCALE); |
||||||
|
if (image.empty()) return -1; |
||||||
|
|
||||||
|
//check image format
|
||||||
|
if (image.depth() != CV_8U || image.channels() != 1) return -1; |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
Context context = Context::create(); |
||||||
|
//put user data from cv::Mat to vx_image
|
||||||
|
vx_df_image color = Image::matTypeToFormat(image.type()); |
||||||
|
vx_uint32 width = image.cols, height = image.rows; |
||||||
|
Image ivxImage; |
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
ivxImage = Image::create(context, width, height, color); |
||||||
|
ivxImage.copyFrom(0, image); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
vx_imagepatch_addressing_t addressing = Image::createAddressing(image); |
||||||
|
const std::vector<vx_imagepatch_addressing_t> addrs(1, addressing); |
||||||
|
const std::vector<void*> ptrs(1, image.data); |
||||||
|
ivxImage = Image::createFromHandle(context, color, addrs, ptrs); |
||||||
|
} |
||||||
|
|
||||||
|
Image ivxResult; |
||||||
|
Image::Patch resultPatch; |
||||||
|
Mat output; |
||||||
|
if (mode == COPY || mode == MAP_FROM_VX) |
||||||
|
{ |
||||||
|
//we will copy or map data from vx_image to cv::Mat
|
||||||
|
ivxResult = ivx::Image::create(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
} |
||||||
|
else // if (mode == MAP_TO_VX)
|
||||||
|
{ |
||||||
|
//create vx_image based on user data, no copying required
|
||||||
|
output = cv::Mat(height, width, CV_8U, cv::Scalar(0)); |
||||||
|
vx_imagepatch_addressing_t addressing = Image::createAddressing(output); |
||||||
|
const std::vector<vx_imagepatch_addressing_t> addrs(1, addressing); |
||||||
|
const std::vector<void*> ptrs(1, output.data); |
||||||
|
ivxResult = Image::createFromHandle(context, Image::matTypeToFormat(CV_8U), addrs, ptrs); |
||||||
|
} |
||||||
|
|
||||||
|
Graph graph = createProcessingGraph(ivxImage, ivxResult); |
||||||
|
|
||||||
|
// Graph execution
|
||||||
|
graph.process(); |
||||||
|
|
||||||
|
//getting resulting image in cv::Mat
|
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
ivxResult.copyTo(0, output); |
||||||
|
} |
||||||
|
else if (mode == MAP_FROM_VX) |
||||||
|
{ |
||||||
|
//create cv::Mat based on vx_image mapped data
|
||||||
|
resultPatch.map(ivxResult, 0, ivxResult.getValidRegion()); |
||||||
|
//generally this is very bad idea!
|
||||||
|
//but in our case unmap() won't happen until output is in use
|
||||||
|
output = resultPatch.getMat(); |
||||||
|
} |
||||||
|
else // if (mode == MAP_TO_VX)
|
||||||
|
{ |
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
//we should take user memory back from vx_image before using it (even before reading)
|
||||||
|
ivxResult.swapHandle(); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
//here output goes
|
||||||
|
cv::imshow("processing result", output); |
||||||
|
cv::waitKey(0); |
||||||
|
|
||||||
|
cv::destroyAllWindows(); |
||||||
|
|
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
if (mode != COPY) |
||||||
|
{ |
||||||
|
//we should take user memory back before release
|
||||||
|
//(it's not done automatically according to standard)
|
||||||
|
ivxImage.swapHandle(); |
||||||
|
if (mode == MAP_TO_VX) ivxResult.swapHandle(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
//the line is unnecessary since unmapping is done on destruction of patch
|
||||||
|
//resultPatch.unmap();
|
||||||
|
} |
||||||
|
catch (const ivx::RuntimeError& e) |
||||||
|
{ |
||||||
|
std::cerr << "Error: code = " << e.status() << ", message = " << e.what() << std::endl; |
||||||
|
return e.status(); |
||||||
|
} |
||||||
|
catch (const ivx::WrapperError& e) |
||||||
|
{ |
||||||
|
std::cerr << "Error: message = " << e.what() << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
const std::string keys = |
||||||
|
"{help h usage ? | | }" |
||||||
|
"{image | <none> | image to be processed}" |
||||||
|
"{mode | copy | user memory interaction mode: \n" |
||||||
|
"copy: create VX images and copy data to/from them\n" |
||||||
|
"map_to_vx: use handles to user-allocated memory\n" |
||||||
|
"map_from_vx: map resulting VX image to user memory}" |
||||||
|
; |
||||||
|
|
||||||
|
cv::CommandLineParser parser(argc, argv, keys); |
||||||
|
parser.about("OpenVX interoperability sample demonstrating OpenVX wrappers usage." |
||||||
|
"The application loads an image, processes it with OpenVX graph and outputs result in a window"); |
||||||
|
if (parser.has("help")) |
||||||
|
{ |
||||||
|
parser.printMessage(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
std::string imgPath = parser.get<std::string>("image"); |
||||||
|
std::string modeString = parser.get<std::string>("mode"); |
||||||
|
UserMemoryMode mode; |
||||||
|
if(modeString == "copy") |
||||||
|
{ |
||||||
|
mode = COPY; |
||||||
|
} |
||||||
|
else if(modeString == "map_to_vx") |
||||||
|
{ |
||||||
|
mode = MAP_TO_VX; |
||||||
|
} |
||||||
|
else if(modeString == "map_from_vx") |
||||||
|
{ |
||||||
|
mode = MAP_FROM_VX; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::cerr << modeString << ": unknown memory mode" << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (!parser.check()) |
||||||
|
{ |
||||||
|
parser.printErrors(); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return ovxDemo(imgPath, mode); |
||||||
|
} |
@ -0,0 +1,253 @@ |
|||||||
|
#include <iostream> |
||||||
|
#include <stdexcept> |
||||||
|
|
||||||
|
//wrappers
|
||||||
|
#include "ivx.hpp" |
||||||
|
|
||||||
|
//OpenCV includes
|
||||||
|
#include "opencv2/core.hpp" |
||||||
|
#include "opencv2/imgproc.hpp" |
||||||
|
#include "opencv2/imgcodecs.hpp" |
||||||
|
#include "opencv2/highgui.hpp" |
||||||
|
|
||||||
|
enum UserMemoryMode |
||||||
|
{ |
||||||
|
COPY, MAP_TO_VX, MAP_FROM_VX |
||||||
|
}; |
||||||
|
|
||||||
|
ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage) |
||||||
|
{ |
||||||
|
using namespace ivx; |
||||||
|
|
||||||
|
Context context = inputImage.getContext(); |
||||||
|
|
||||||
|
Graph graph = Graph::create(context); |
||||||
|
|
||||||
|
vx_uint32 width = inputImage.width(); |
||||||
|
vx_uint32 height = inputImage.height(); |
||||||
|
|
||||||
|
// Intermediate images
|
||||||
|
Image |
||||||
|
yuv = Image::createVirtual(graph, 0, 0, VX_DF_IMAGE_YUV4), |
||||||
|
gray = Image::createVirtual(graph), |
||||||
|
smoothed = Image::createVirtual(graph), |
||||||
|
cannied = Image::createVirtual(graph), |
||||||
|
halfImg = Image::create(context, width, height, VX_DF_IMAGE_U8), |
||||||
|
halfCanny = Image::create(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
|
||||||
|
// Constants
|
||||||
|
vx_uint32 threshCannyMin = 127; |
||||||
|
vx_uint32 threshCannyMax = 192; |
||||||
|
Threshold threshCanny = Threshold::createRange(context, VX_TYPE_UINT8, threshCannyMin, threshCannyMax); |
||||||
|
|
||||||
|
ivx::Scalar alpha = ivx::Scalar::create<VX_TYPE_FLOAT32>(context, 0.5); |
||||||
|
|
||||||
|
// Sequence of some image operations
|
||||||
|
Node::create(graph, VX_KERNEL_COLOR_CONVERT, inputImage, yuv); |
||||||
|
Node::create(graph, VX_KERNEL_CHANNEL_EXTRACT, yuv, |
||||||
|
ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CHANNEL_Y), gray); |
||||||
|
//node can also be added in function-like style
|
||||||
|
nodes::gaussian3x3(graph, gray, smoothed); |
||||||
|
Node::create(graph, VX_KERNEL_CANNY_EDGE_DETECTOR, smoothed, threshCanny, |
||||||
|
ivx::Scalar::create<VX_TYPE_INT32>(context, 3), |
||||||
|
ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_NORM_L2), cannied); |
||||||
|
Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, gray, alpha, halfImg); |
||||||
|
Node::create(graph, VX_KERNEL_ACCUMULATE_WEIGHTED, cannied, alpha, halfCanny); |
||||||
|
Node::create(graph, VX_KERNEL_ADD, halfImg, halfCanny, |
||||||
|
ivx::Scalar::create<VX_TYPE_ENUM>(context, VX_CONVERT_POLICY_SATURATE), outputImage); |
||||||
|
|
||||||
|
graph.verify(); |
||||||
|
|
||||||
|
return graph; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int ovxDemo(std::string inputPath, UserMemoryMode mode) |
||||||
|
{ |
||||||
|
using namespace cv; |
||||||
|
using namespace ivx; |
||||||
|
|
||||||
|
Mat frame; |
||||||
|
VideoCapture vc(inputPath); |
||||||
|
if (!vc.isOpened()) |
||||||
|
return -1; |
||||||
|
|
||||||
|
vc >> frame; |
||||||
|
if (frame.empty()) return -1; |
||||||
|
|
||||||
|
//check frame format
|
||||||
|
if (frame.type() != CV_8UC3) return -1; |
||||||
|
|
||||||
|
try |
||||||
|
{ |
||||||
|
Context context = Context::create(); |
||||||
|
//put user data from cv::Mat to vx_image
|
||||||
|
vx_df_image color = Image::matTypeToFormat(frame.type()); |
||||||
|
vx_uint32 width = frame.cols, height = frame.rows; |
||||||
|
Image ivxImage; |
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
ivxImage = Image::create(context, width, height, color); |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
vx_imagepatch_addressing_t addressing = Image::createAddressing(frame); |
||||||
|
const std::vector<vx_imagepatch_addressing_t> addrs(1, addressing); |
||||||
|
const std::vector<void*> ptrs(1, frame.data); |
||||||
|
ivxImage = Image::createFromHandle(context, color, addrs, ptrs); |
||||||
|
} |
||||||
|
|
||||||
|
Image ivxResult; |
||||||
|
|
||||||
|
Mat output; |
||||||
|
if (mode == COPY || mode == MAP_FROM_VX) |
||||||
|
{ |
||||||
|
//we will copy or map data from vx_image to cv::Mat
|
||||||
|
ivxResult = ivx::Image::create(context, width, height, VX_DF_IMAGE_U8); |
||||||
|
} |
||||||
|
else // if (mode == MAP_TO_VX)
|
||||||
|
{ |
||||||
|
//create vx_image based on user data, no copying required
|
||||||
|
output = cv::Mat(height, width, CV_8U, cv::Scalar(0)); |
||||||
|
vx_imagepatch_addressing_t addressing = Image::createAddressing(output); |
||||||
|
const std::vector<vx_imagepatch_addressing_t> addrs(1, addressing); |
||||||
|
const std::vector<void*> ptrs(1, output.data); |
||||||
|
ivxResult = Image::createFromHandle(context, Image::matTypeToFormat(CV_8U), addrs, ptrs); |
||||||
|
} |
||||||
|
|
||||||
|
Graph graph = createProcessingGraph(ivxImage, ivxResult); |
||||||
|
|
||||||
|
std::vector<void*> ptrs; |
||||||
|
|
||||||
|
bool stop = false; |
||||||
|
while (!stop) |
||||||
|
{ |
||||||
|
if (mode == COPY) ivxImage.copyFrom(0, frame); |
||||||
|
|
||||||
|
// Graph execution
|
||||||
|
graph.process(); |
||||||
|
|
||||||
|
//getting resulting image in cv::Mat
|
||||||
|
Image::Patch resultPatch; |
||||||
|
std::vector<void*> prevPtrs; |
||||||
|
if (mode == COPY) |
||||||
|
{ |
||||||
|
ivxResult.copyTo(0, output); |
||||||
|
} |
||||||
|
else if (mode == MAP_FROM_VX) |
||||||
|
{ |
||||||
|
//create cv::Mat based on vx_image mapped data
|
||||||
|
resultPatch.map(ivxResult, 0, ivxResult.getValidRegion(), VX_READ_AND_WRITE); |
||||||
|
//generally this is very bad idea!
|
||||||
|
//but in our case unmap() won't happen until output is in use
|
||||||
|
output = resultPatch.getMat(); |
||||||
|
} |
||||||
|
else // if(mode == MAP_TO_VX)
|
||||||
|
{ |
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
//we should take user memory back from vx_image before using it (even before reading)
|
||||||
|
ivxResult.swapHandle(ptrs, prevPtrs); |
||||||
|
#endif |
||||||
|
} |
||||||
|
|
||||||
|
//here output goes
|
||||||
|
imshow("press q to quit", output); |
||||||
|
if ((char)waitKey(1) == 'q') stop = true; |
||||||
|
|
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
//restore handle
|
||||||
|
if (mode == MAP_TO_VX) |
||||||
|
{ |
||||||
|
ivxResult.swapHandle(prevPtrs); |
||||||
|
} |
||||||
|
#endif |
||||||
|
|
||||||
|
//this line is unnecessary since unmapping is done on destruction of patch
|
||||||
|
//resultPatch.unmap();
|
||||||
|
|
||||||
|
//grab next frame
|
||||||
|
Mat temp = frame; |
||||||
|
vc >> frame; |
||||||
|
if (frame.empty()) stop = true; |
||||||
|
if (mode != COPY && frame.data != temp.data) |
||||||
|
{ |
||||||
|
//frame was reallocated, pointer to data changed
|
||||||
|
frame.copyTo(temp); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
destroyAllWindows(); |
||||||
|
|
||||||
|
#ifdef VX_VERSION_1_1 |
||||||
|
if (mode != COPY) |
||||||
|
{ |
||||||
|
//we should take user memory back before release
|
||||||
|
//(it's not done automatically according to standard)
|
||||||
|
ivxImage.swapHandle(); |
||||||
|
if (mode == MAP_TO_VX) ivxResult.swapHandle(); |
||||||
|
} |
||||||
|
#endif |
||||||
|
} |
||||||
|
catch (const ivx::RuntimeError& e) |
||||||
|
{ |
||||||
|
std::cerr << "Error: code = " << e.status() << ", message = " << e.what() << std::endl; |
||||||
|
return e.status(); |
||||||
|
} |
||||||
|
catch (const ivx::WrapperError& e) |
||||||
|
{ |
||||||
|
std::cerr << "Error: message = " << e.what() << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
int main(int argc, char *argv[]) |
||||||
|
{ |
||||||
|
const std::string keys = |
||||||
|
"{help h usage ? | | }" |
||||||
|
"{video | <none> | video file to be processed}" |
||||||
|
"{mode | copy | user memory interaction mode: \n" |
||||||
|
"copy: create VX images and copy data to/from them\n" |
||||||
|
"map_to_vx: use handles to user-allocated memory\n" |
||||||
|
"map_from_vx: map resulting VX image to user memory}" |
||||||
|
; |
||||||
|
|
||||||
|
cv::CommandLineParser parser(argc, argv, keys); |
||||||
|
parser.about("OpenVX interoperability sample demonstrating OpenVX wrappers usage." |
||||||
|
"The application opens a video and processes it with OpenVX graph while outputting result in a window"); |
||||||
|
if (parser.has("help")) |
||||||
|
{ |
||||||
|
parser.printMessage(); |
||||||
|
return 0; |
||||||
|
} |
||||||
|
std::string videoPath = parser.get<std::string>("video"); |
||||||
|
std::string modeString = parser.get<std::string>("mode"); |
||||||
|
UserMemoryMode mode; |
||||||
|
if(modeString == "copy") |
||||||
|
{ |
||||||
|
mode = COPY; |
||||||
|
} |
||||||
|
else if(modeString == "map_to_vx") |
||||||
|
{ |
||||||
|
mode = MAP_TO_VX; |
||||||
|
} |
||||||
|
else if(modeString == "map_from_vx") |
||||||
|
{ |
||||||
|
mode = MAP_FROM_VX; |
||||||
|
} |
||||||
|
else |
||||||
|
{ |
||||||
|
std::cerr << modeString << ": unknown memory mode" << std::endl; |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
if (!parser.check()) |
||||||
|
{ |
||||||
|
parser.printErrors(); |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
return ovxDemo(videoPath, mode); |
||||||
|
} |
Loading…
Reference in new issue