no_wrappers.cpp 12.2 KB
Newer Older
wester committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
#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, USER_MEM
};

vx_image convertCvMatToVxImage(vx_context context, cv::Mat image, bool toCopy);
cv::Mat copyVxImageToCvMat(vx_image ovxImage);
void swapVxImage(vx_image ovxImage);
vx_status createProcessingGraph(vx_image inputImage, vx_image outputImage, vx_graph& graph);
int ovxDemo(std::string inputPath, UserMemoryMode mode);


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
    {
        ovxImage = vxCreateImageFromHandle(context, color, &addr, (void**)&ovxData, VX_MEMORY_TYPE_HOST);
        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 == USER_MEM)
        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"
        "user_mem: 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 == "user_mem")
    {
        mode = USER_MEM;
    }
    else if(modeString == "map")
    {
        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);
}