cameracv/libs/opencv/samples/openvx/wrappers.cpp
2023-05-18 21:39:43 +03:00

214 lines
6.4 KiB
C++

#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, USER_MEM, MAP
};
ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage);
int ovxDemo(std::string inputPath, UserMemoryMode mode);
ivx::Graph createProcessingGraph(ivx::Image& inputImage, ivx::Image& outputImage)
{
using namespace ivx;
Context context = inputImage.get<Context>();
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
{
ivxImage = Image::createFromHandle(context, color, Image::createAddressing(image), image.data);
}
Image ivxResult;
Image::Patch resultPatch;
Mat output;
if (mode == COPY || mode == MAP)
{
//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));
ivxResult = Image::createFromHandle(context, Image::matTypeToFormat(CV_8U),
Image::createAddressing(output), output.data);
}
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)
{
//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 == USER_MEM) 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"
"user_mem: use handles to user-allocated memory\n"
"map: 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 == "user_mem")
{
mode = USER_MEM;
}
else if(modeString == "map")
{
mode = MAP;
}
else
{
std::cerr << modeString << ": unknown memory mode" << std::endl;
return -1;
}
if (!parser.check())
{
parser.printErrors();
return -1;
}
return ovxDemo(imgPath, mode);
}