OpenVX 的 立即模式(immediate mode)和图模式(graph mode)和示例讲解

OpenVX 的 立即模式(immediate mode)和图模式(graph mode)

openvx的执行模型一般分为 立即模式 和 图模式。
直接模式非常简单,以vxu…开头的函数类似于opencv,习惯于传统的opencv api的,能够快速体验到openvx的功能,调用一个函数便可得到一个结果。
OpenCVX的真正的强大之处在于graph 模式,他将每一个函数功能抽象成一个node,函数原型被称为kernel, 一个graph 内可以有多个node, 了解过神经网络的朋友便清楚,这样的设计结构非常的契合神经网络的结构,每一个layer都可以被看作是一个node,虽然训练一个神经网络不是openvx的功能,但是在openvx上做推理是它的强大功能之一。关于openvx神经网络的说明,可参考我之前的一篇文章。✈

立即模式(immediate mode)

示例讲解1

接下来会以代码示例的方式讲解立即模式和图模式的应用
程序的功能如下:

编写openvx 程序想到第一个事情就是创建一个context。同时要想到release.
vx_context context = vxCreateContext();//创建
vxReleaseContext(&context);释放

第二件事就是想到如何对创建的上下文进行校验,以验证是否创建成功。一般来说,我们可以调用vxGetStatus()函数来检验vx_reference任何类型的返回值。

void errorCheck(vx_context *context_p, vx_status status, const char *message)
{
    if (status)
    {
      puts("ERROR! ");
      puts(message);
      vxReleaseContext(context_p);
      exit(1);
    }
}
errorCheck(&context, vxGetStatus((vx_reference)context), "Could notcreate a vx_context\n");

然后我们看一下接下来的函数,用于在黑色的背景上创建一个矩形框的图形,用于做Fast角点计算。

vx_image makeInputImage(vx_context context)
{
  //创建一个100*100 vx_image对象
  vx_image image = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_rectangle_t rect = {
    .start_x = 20, .start_y = 40, .end_x=80, .end_y = 60
  };

  if (VX_SUCCESS == vxGetStatus((vx_reference)image))
  {
  	//获取image的ROI
    vx_image roi = vxCreateImageFromROI(image, &rect);
    vx_pixel_value_t pixel_white, pixel_black;
    pixel_white.U8 = 255;
    pixel_black.U8 = 0;
    //设置ROI的像素值
    if (VX_SUCCESS == vxGetStatus((vx_reference)roi) &&
        VX_SUCCESS == vxSetImagePixelValues(image, &pixel_black) &&
        VX_SUCCESS == vxSetImagePixelValues(roi, &pixel_white))
      vxReleaseImage(&roi);
    else
      vxReleaseImage(&image);
  }

  return image;
}

我们通过填充所有的图像来制作黑色的背景,然后通过在这个背景中填充一个ROI(感兴趣的区域)来制作一个白色的矩形。当我们完成ROI后,我们释放它,因为我们不再需要它。注意,如果我们在创建图像时遇到错误,我们将没有进一步触摸图像或ROI,如果我们没有创建ROI或复制数据,那么我们将释放图像并返回一个空指针。
在调用Fast角点检测函数之前,我们还需要其他参数

//用于角点检测的阈值(当中心点的像素值大于绝大多数周围16个点像素值,那么就认为该像素是角点)
vx_float32 strength_thresh_value = 128.0; 
vx_scalar strength_thresh = vxCreateScalar(context, VX_TYPE_FLOAT32,&strength_thresh_value);
//保存坐标点的数组
vx_array corners = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
vx_array corners1 = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
vx_size num_corners_value = 0;
vx_scalar num_corners = vxCreateScalar(context, VX_TYPE_SIZE,
&num_corners_value);
vx_scalar num_corners1 = vxCreateScalar(context, VX_TYPE_SIZE,
&num_corners_value);
vx_keypoint_t *kp = calloc( 100, sizeof(vx_keypoint_t));

最后的部分就是执行采用非极大值抑制和不采用非极大值抑制的Fast焦点检测,然后将坐标显示出来。
所有代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <VX/vx.h>
#include <VX/vxu.h>
//错误检测函数
void errorCheck(vx_context *context_p, vx_status status, const char *message)
{
    if (status)
    {
      puts("ERROR! ");
      puts(message);
      vxReleaseContext(context_p);
      exit(1);
    }
}
//图像创建函数
vx_image makeInputImage(vx_context context)
{
  //创建一个100*100的image对象
  vx_image image = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  //坐标
  vx_rectangle_t rect = {
    .start_x = 20, .start_y = 40, .end_x=80, .end_y = 60
  };
  if (VX_SUCCESS == vxGetStatus((vx_reference)image))
  {
  	//创建一个ROI区域
    vx_image roi = vxCreateImageFromROI(image, &rect);
    vx_pixel_value_t pixel_white, pixel_black;
    pixel_white.U8 = 255;
    pixel_black.U8 = 0;
    //像素填充
    if (VX_SUCCESS == vxGetStatus((vx_reference)roi) &&
        VX_SUCCESS == vxSetImagePixelValues(image, &pixel_black) &&
        VX_SUCCESS == vxSetImagePixelValues(roi, &pixel_white))
      vxReleaseImage(&roi);
    else
      vxReleaseImage(&image);
  }
  return image;
}

int main(void)
{
  //创建上下文
  vx_context context = vxCreateContext();
  errorCheck(&context, vxGetStatus((vx_reference)context), "Could not create a vx_context\n");
 //创建测试图像
  vx_image image1 = makeInputImage(context);
  errorCheck(&context, vxGetStatus((vx_reference)image1), "Could not create image");
 //快速角点检测阈值
  vx_float32 strength_thresh_value = 128.0;
  vx_scalar strength_thresh = vxCreateScalar(context, VX_TYPE_FLOAT32, &strength_thresh_value);
  vx_array corners = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
  vx_array corners1 = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
  vx_size num_corners_value = 0;
  vx_scalar num_corners = vxCreateScalar(context, VX_TYPE_SIZE, &num_corners_value);
  vx_scalar num_corners1 = vxCreateScalar(context, VX_TYPE_SIZE, &num_corners_value);
  vx_keypoint_t *kp = calloc( 100, sizeof(vx_keypoint_t));

  errorCheck(&context,
             kp == NULL ||
             vxGetStatus((vx_reference)strength_thresh) ||
             vxGetStatus((vx_reference)corners) ||
             vxGetStatus((vx_reference)num_corners) ||
             vxGetStatus((vx_reference)corners1) ||
             vxGetStatus((vx_reference)num_corners1),
             "Could not create parameters for FastCorners");
//采用非极大值移抑制的Fast角点检测算子
  errorCheck(&context, vxuFastCorners(context, image1, strength_thresh, vx_true_e, corners, num_corners), "Fast Corners function failed");
//不采用非极大值移抑制的Fast角点检测算子
  errorCheck(&context, vxuFastCorners(context, image1, strength_thresh, vx_false_e, corners1, num_corners1), "Fast Corners function failed");
//角点个数
  errorCheck(&context, vxCopyScalar(num_corners, &num_corners_value, VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyScalar failed");
  printf("Found %zu corners with non-max suppression\n", num_corners_value);
//坐标保存数组
  errorCheck(&context, vxCopyArrayRange( corners, 0, num_corners_value, sizeof(vx_keypoint_t), kp,VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyArrayRange failed");
//显示坐标                                      
  for (int i=0; i<num_corners_value; ++i)
  {
    printf("Entry %3d: x = %d, y = %d\n", i, kp[i].x, kp[i].y);
  }
//角点个数
  errorCheck(&context, vxCopyScalar(num_corners1, &num_corners_value, VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyScalar failed");
  printf("Found %zu corners without non-max suppression\n", num_corners_value);
//坐标保存数组
  errorCheck(&context, vxCopyArrayRange( corners1, 0, num_corners_value, sizeof(vx_keypoint_t), kp,VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyArrayRange failed");
  //显示坐标
  for (int i=0; i<num_corners_value; ++i)
  {
    printf("Entry %3d: x = %d, y = %d\n", i, kp[i].x, kp[i].y);
  }

  free(kp);
  vxReleaseContext(&context);
  return 0;
}

运算结果:采用非极大值抑制,检测到4个角点,不采用检测到24个角点。
在这里插入图片描述

示例讲解2

接下来我们丰富一些示例1 的内容, 我们可以采用vxuWarpAffine仿射变换将输入图像旋转90度,然后vxuOr()逻辑或处理两个图像,在黑色背景上创建一个白色的十字,这样我们看到12个角了。
关于什么是仿射变换,有兴趣的朋友可以参考一些连接 :仿射变换✈
在这里插入图片描述
仿射变换是一种旋转,其中每个输出x和y像素从输入地址的线性组合给出的地址处的像素中获取;如果输入地址不是积分,则按照指定执行插值。在代码中给出的系数作为matrix_values只是简单地交换x和y,没有偏移量;

//仿射变换所需的Mtrix
vx_matrix warp_matrix = vxCreateMatrix(context, VX_TYPE_FLOAT32, 2U,3U);
vx_float32 matrix_values[3][2] = { /* Rotate through 90 degrees */
	{0.0, 1.0}, /* x coefficients */
	{1.0, 0.0}, /* y coefficients */
	{0.0, 0.0} /* offsets */
};
errorCheck(&context, vxCopyMatrix(warp_matrix, matrix_values,VX_WRITE_ONLY,VX_MEMORY_TYPE_HOST), "Could not initialize thematrix");
/* Now image2 set to image 1 rotated */
//仿射变换
errorCheck(&context, vxuWarpAffine(context, image1, warp_matrix,VX_INTERPOLATION_NEAREST_NEIGHBOR, image2) ||
/* image3 set to logical OR of images 1 and 2 */
//逻辑或
vxuOr(context, image1, image2, image3) ||
/*And now count the corners */
//Fast角点检测
vxuFastCorners(context, image3, strength_thresh, vx_true_e,corners, num_corners),"Image functions failed");
实例讲解3

更进一步的优化,我们增加对图像的处理,使用Sobel、Magnitude和 Dilate filters(膨胀过滤器)用白色十字的轮廓替换白色十字,计算和内外角点的计数。
Sobel滤波器是一个边缘检测滤波器,将其应用于交叉得到两个输出图像,x方向的梯度和y方向的梯度。
取x和y图像的Magnitude,我们得到了一条勾画交叉的单像素实线。注意,vxuMagnitude函数接受两个作为vxuSobel输出的16位有符号图像的输出,并生成一个16位有符号图像作为输出。然而,大多数其他的OpenVX函数只操作8位无符号图像,所以我们使用vxu转换深度函数来生成这样的图像,VX_CONVERT_POLICY_SATURATE指定低于零的值应该设置为零,高于255的值应该设置为255。
最后,vxuDilate3x3功能应用膨胀过滤器,使薄轮廓更实质性。

/* Now image2 set to image 1 rotated */
 vx_status status = vxuWarpAffine(context, image1, warp_matrix, VX_INTERPOLATION_NEAREST_NEIGHBOR, image2);
/* image3 set to logical OR of images 1 and 2 and then processed as described above */
errorCheck(&context, vxuOr(context, image1, image2, image3) ||
	vxuSobel3x3(context, image3, grad_x, grad_y) ||
	vxuMagnitude(context, grad_x, grad_y, magnitude) ||
	vxuConvertDepth(context, magnitude, converted, VX_CONVERT_POLICY_SATURATE, 1) ||
	vxuDilate3x3(context, converted, dilated) ||
	/* And now count the corners */
	vxuFastCorners(context, dilated, strength_thresh, vx_true_e, corners, num_corners),"Image functions failed");

在这里插入图片描述
以下代码是经过多次优化后的整体代码

#include <stdio.h>
#include <stdlib.h>
#include "VX/vx.h"
#include "VX/vxu.h"

void errorCheck(vx_context *context_p, vx_status status, const char *message)
{
    if (status)
    {
      puts("ERROR! ");
      puts(message);
      vxReleaseContext(context_p);
      exit(1);
    }
}

vx_image makeInputImage(vx_context context)
{
  vx_image image = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_rectangle_t rect = {
    .start_x = 20, .start_y = 40, .end_x=80, .end_y = 60
  };

  if (VX_SUCCESS == vxGetStatus((vx_reference)image))
  {
    vx_image roi = vxCreateImageFromROI(image, &rect);
    vx_pixel_value_t pixel_white, pixel_black;
    pixel_white.U8 = 255;
    pixel_black.U8 = 0;
    if (VX_SUCCESS == vxGetStatus((vx_reference)roi) &&
        VX_SUCCESS == vxSetImagePixelValues(image, &pixel_black) &&
        VX_SUCCESS == vxSetImagePixelValues(roi, &pixel_white))
      vxReleaseImage(&roi);
    else
      vxReleaseImage(&image);
  }

  return image;
}

int main(void)
{
  vx_context context = vxCreateContext();

  errorCheck(&context, vxGetStatus((vx_reference)context), "Could not create a vx_context\n");

  vx_image image1 = makeInputImage(context);

  errorCheck(&context, vxGetStatus((vx_reference)image1), "Could not create first image");

  vx_image image2 = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_image image3 = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_image grad_x = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_S16);
  vx_image grad_y = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_S16);
  vx_image magnitude = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_S16);
  vx_image converted = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_image dilated = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_image image4 = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  vx_matrix warp_matrix = vxCreateMatrix(context, VX_TYPE_FLOAT32, 2U, 3U);
  vx_float32 matrix_values[3][2] = {       /* Rotate through 90 degrees */
      {0.0, 1.0},         /* x coefficients */
      {1.0, 0.0},         /* y coefficients */
      {0.0, 0.0}          /* offsets */
  };
  vx_float32 strength_thresh_value = 128.0;
  vx_scalar strength_thresh = vxCreateScalar(context, VX_TYPE_FLOAT32, &strength_thresh_value);
  vx_array corners = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
  vx_size num_corners_value = 0;
  vx_scalar num_corners = vxCreateScalar(context, VX_TYPE_SIZE, &num_corners_value);
  vx_keypoint_t *kp = calloc( 100, sizeof(vx_keypoint_t));

  errorCheck(&context,
             kp == NULL ||
             vxGetStatus((vx_reference)strength_thresh) ||
             vxGetStatus((vx_reference)corners) ||
             vxGetStatus((vx_reference)num_corners) ||
             vxGetStatus((vx_reference)image2) ||
             vxGetStatus((vx_reference)image3) ||
             vxGetStatus((vx_reference)grad_x) ||
             vxGetStatus((vx_reference)grad_y) ||
             vxGetStatus((vx_reference)magnitude) ||
             vxGetStatus((vx_reference)converted) ||
             vxGetStatus((vx_reference)dilated) ||
             vxGetStatus((vx_reference)image4) ||
             vxGetStatus((vx_reference)warp_matrix),
             "Could not create objects");

  errorCheck(&context, vxCopyMatrix(warp_matrix, matrix_values, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST), "Could not initialise the matrix");

  /* Now image2 set to image 1 rotated */
  vx_status status = vxuWarpAffine(context, image1, warp_matrix, VX_INTERPOLATION_NEAREST_NEIGHBOR, image2);
  /* image3 set to logical OR of images 1 and 2 and then processed as described above */
  errorCheck(&context, vxuOr(context, image1, image2, image3) ||
                                   vxuSobel3x3(context, image3, grad_x, grad_y) ||
                                   vxuMagnitude(context, grad_x, grad_y, magnitude) ||
                                   vxuConvertDepth(context, magnitude, converted, VX_CONVERT_POLICY_SATURATE, 1) ||
                                   vxuDilate3x3(context, converted, dilated) ||
                                   /* And now count the corners */
                                   vxuFastCorners(context, dilated, strength_thresh, vx_true_e, corners, num_corners),
                                   "Image functions failed");

  errorCheck(&context, vxCopyScalar(num_corners, &num_corners_value, VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyScalar failed");
  printf("Found %zu corners with non-max suppression\n", num_corners_value);

  errorCheck(&context, vxCopyArrayRange( corners, 0, num_corners_value, sizeof(vx_keypoint_t), kp,
                                        VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyArrayRange failed");
  for (int i=0; i<num_corners_value; ++i)
  {
    printf("Entry %3d: x = %d, y = %d\n", i, kp[i].x, kp[i].y);
  }

  free(kp);
  vxReleaseContext(&context);
  return 0;
}

我们使用了很多image 对象,事实上,大多数这些图像确实不需要保留,因为我们对中间数据不感兴趣。唯一感兴趣的图像实际上是我们创建的输入图像。在此之后,我们只使用来自最终转角检测器的输出。

图模式(Graph mode)

关于Graph mode的使用,我们可以对比上面的模式,graph模式是如何实现和执行的。
先直接上代码,大家可以看一下实现共一个功能的程序在两种模式下有什么区别,然后我会一一讲解其中主要函数的意义。

#include <stdio.h>
#include <stdlib.h>
#include "VX/vx.h"

void errorCheck(vx_context *context_p, vx_status status, const char *message)
{
    if (status)
    {
      puts("ERROR! ");
      puts(message);
      vxReleaseContext(context_p);
      exit(1);
    }
}

vx_image makeInputImage(vx_context context, vx_uint32 width, vx_uint32 height)
{
  vx_image image = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);
  if (width > 48)
      width = 48;
  if (height > 48)
      height = 48;
  vx_rectangle_t rect = {
    .start_x = 50 - width, .start_y = 50 - height, .end_x = 50 + width, .end_y = 50 + height
  };

  if (VX_SUCCESS == vxGetStatus((vx_reference)image))
  {
    vx_image roi = vxCreateImageFromROI(image, &rect);
    vx_pixel_value_t pixel_white, pixel_black;
    pixel_white.U8 = 255;
    pixel_black.U8 = 0;
    if (VX_SUCCESS == vxGetStatus((vx_reference)roi) &&
        VX_SUCCESS == vxSetImagePixelValues(image, &pixel_black) &&
        VX_SUCCESS == vxSetImagePixelValues(roi, &pixel_white))
      vxReleaseImage(&roi);
    else
      vxReleaseImage(&image);
  }
  return image;
}

vx_graph makeTestGraph(vx_context context)
{
    vx_graph graph = vxCreateGraph(context);
    int i;
    vx_image imagesU8[5], imagesS16[3];
    vx_image input = vxCreateImage(context, 100U, 100U, VX_DF_IMAGE_U8);

	//节点所需的虚拟图像对象
    for (i = 0; i < 5; ++i)
      imagesU8[i] = vxCreateVirtualImage(graph, 100, 100, VX_DF_IMAGE_U8);
    for (i = 0; i < 3; ++i)
        imagesS16[i] = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_VIRT);
	//所需参数创建
    vx_matrix warp_matrix = vxCreateMatrix(context, VX_TYPE_FLOAT32, 2U, 3U);
    vx_float32 matrix_values[6] = {0.0, 1.0, 1.0, 0.0, 0.0, 0.0 };       /* Rotate through 90 degrees */
    vx_float32 strength_thresh_value = 128.0;
    vx_scalar strength_thresh = vxCreateScalar(context, VX_TYPE_FLOAT32, &strength_thresh_value);
    vx_array corners = vxCreateArray(context, VX_TYPE_KEYPOINT, 100);
    vx_size num_corners_value = 0;
    vx_int32 shift_value = 1;
    vx_scalar num_corners = vxCreateScalar(context, VX_TYPE_SIZE, &num_corners_value);
    vx_scalar shift = vxCreateScalar(context, VX_TYPE_INT32, &shift_value);

    vxCopyMatrix(warp_matrix, matrix_values, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
	//节点连接:节点的连接方式是以数据为支撑
    /* Create the nodes to do the processing, order of creation is not important */
    vx_node last_node = vxFastCornersNode(graph, imagesU8[4], strength_thresh, vx_true_e, corners, num_corners);
    vxDilate3x3Node(graph, imagesU8[3], imagesU8[4]);
    vxConvertDepthNode(graph, imagesS16[2], imagesU8[3], VX_CONVERT_POLICY_SATURATE, shift);
    vxMagnitudeNode(graph, imagesS16[0], imagesS16[1], imagesS16[2]);
    vxSobel3x3Node(graph, imagesU8[2], imagesS16[0], imagesS16[1]);
    vxOrNode(graph, imagesU8[0], imagesU8[1], imagesU8[2]);
    vxWarpAffineNode(graph, imagesU8[0], warp_matrix, VX_INTERPOLATION_NEAREST_NEIGHBOR, imagesU8[1]);

	//设置grpah 输入,Index:节点的第几个参数
    /* Setup input parameter using a Copy node */
    vxAddParameterToGraph(graph, vxGetParameterByIndex(vxCopyNode(graph, (vx_reference)input, (vx_reference)imagesU8[0]), 0));
	//设置grpah 输出,Index:节点的第几个参数
    /* Setup the output parameters from the last node */
    vxAddParameterToGraph(graph, vxGetParameterByIndex(last_node, 3));    /* array of corners */
    vxAddParameterToGraph(graph, vxGetParameterByIndex(last_node, 4));    /* number of corners */

    /* Release resources */
    vxReleaseImage(&input);
    for (i = 0; i < 5; ++i)
        vxReleaseImage(&imagesU8[i]);
    for (i = 0; i < 3; ++i)
        vxReleaseImage(&imagesS16[i]);
    vxReleaseMatrix(&warp_matrix);
    vxReleaseScalar(&strength_thresh);
    vxReleaseScalar(&num_corners);
    vxReleaseScalar(&shift);
    vxReleaseArray(&corners);

    return graph;
}
//获取Graph的参数
vx_reference getGraphParameter(vx_graph graph, vx_uint32 index)
{
    vx_parameter p = vxGetGraphParameterByIndex(graph, index);
    vx_reference ref = NULL;
    vxQueryParameter(p, VX_PARAMETER_REF, &ref, sizeof(ref));
    vxReleaseParameter(&p);
    return ref;
}

void showResults(vx_graph graph, vx_image image, const char * message)
{
	vx_status status;
	//创建上下文
    vx_context context = vxGetContext((vx_reference)graph);
    puts(message);
	//设置Graph的输出参数,Index:0 第0个参数
    vxSetGraphParameterByIndex(graph, 0, (vx_reference)image);
	//graph 认证
	errorCheck(&context,vxVerifyGraph(graph),"Graph verify fail!");
	//graph 执行
	status = vxProcessGraph(graph);	
    if (VX_SUCCESS == status)
    {
        vx_size num_corners_value = 0;
        vx_keypoint_t *kp = calloc( 100, sizeof(vx_keypoint_t));
		//执行成功后,将scaler参数拷贝值num_corners_value
        errorCheck(&context, vxCopyScalar((vx_scalar)getGraphParameter(graph, 2), &num_corners_value,
                                          VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyScalar failed");
        printf("Found %zu corners with non-max suppression\n", num_corners_value);

        /* Array can only hold 100 values */
        if (num_corners_value > 100)
            num_corners_value = 100;
		//执行成功后,将scaler参数拷贝值vx_keypoint_t 数组
        errorCheck(&context, vxCopyArrayRange((vx_array)getGraphParameter(graph, 1), 0,
                                              num_corners_value, sizeof(vx_keypoint_t), kp,
                                              VX_READ_ONLY, VX_MEMORY_TYPE_HOST), "vxCopyArrayRange failed");
        for (int i=0; i<num_corners_value; ++i)
        {
            printf("Entry %3d: x = %d, y = %d\n", i, kp[i].x, kp[i].y);
        }

        free(kp);
    }
    else
    {
        printf("Graph processing failed[%d]!\n",status);
    }
}

int main(void)
{
    vx_context context = vxCreateContext();
    errorCheck(&context, vxGetStatus((vx_reference)context), "Could not create a vx_context\n");

    vx_graph graph = makeTestGraph(context);

    vx_image image1 = makeInputImage(context, 30, 10);
    vx_image image2 = makeInputImage(context, 25, 25);

    showResults(graph, image1, "Results for Image 1");
    showResults(graph, image2, "Results for Image 2");

    vxReleaseContext(&context);
    return 0;
}


各函数的含义及讲解

  • vx_graph graph = vxCreateGraph(context);
    基于上下文创建一个graph
  • vxCreateVirtualImage( )
    该函数用于创建一个虚拟image,我们往往不关心中间的数据,但是节点的连接还是要以数据对象作为支撑,所以,虚拟对象技术就应用而生。
  • vxCreateMatrix( )
    创建一个矩阵对象
  • vxCreateScalar( )
    创建一个标量对象
  • vxCreateArray( )
    创建一个数组对象
  • vxCopyNode( )
    复制一个节点
  • vxGetParameterByIndex(vx_node node, vx_uint32 index)
    获取节点的参数,其中的index,便是节点的参数的索引,是几便是除去graph参数之外的第几个参数。
  • vxAddParameterToGraph(vx_graph graph, vx_parameter param)
    将参数添加进graph
  • vxVerifyGraph(graph)
    节点认证,主要验证graph结构是否合法
    -vxProcessGraph(graph)
    graph 执行,此函数便会执行graph中所有node函数功能。
  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

疯狂的蕉尼基

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值