OpenVX图像变换与特征提取实战
立即解锁
发布时间: 2025-09-01 02:02:11 阅读量: 9 订阅数: 25 AIGC 

### OpenVX图像变换与特征提取实战
在计算机视觉领域,图像的处理和特征提取是非常重要的任务。OpenVX作为一个强大的计算机视觉库,提供了丰富的功能来完成这些任务。本文将详细介绍OpenVX中的基本图像变换、感兴趣区域(ROI)操作以及特征提取的相关内容。
#### 1. 基本图像变换
在图像变换过程中,可以对不同通道使用不同的卷积。但需要注意的是,如果在图执行期间更改卷积系数,图每次都需要重新验证,这样OpenVX才能检查滤波器系数和图中滤波器的顺序,看是否能针对特定硬件平台进行优化。最后,可以将灰度图像合并为彩色图像,示例代码如下:
```c
vxChannelCombineNode(graph, virtu8[3], virtu8[4], virtu8[5], NULL, output);
```
“filterImage.c”的编译方式与之前的“filterGaussImage.c”类似。
#### 2. 感兴趣区域(ROI)操作
##### 2.1 从感兴趣区域读取
在计算机视觉中,预处理图像并选择包含感兴趣对象的矩形区域(感兴趣区域,ROI)进行进一步处理是一个标准操作。在OpenVX中,可以使用`vxCreateImageFromROI`函数创建ROI图像,它是父图像的一部分,对ROI图像中像素值的更新会反映在父图像中。
以下是使用ROI进行Scharr滤波的示例代码:
```c
// 定义ROI矩形
vx_rectangle_t rect;
rect.start_x = 48;
rect.start_y = 98;
rect.end_x = 258;
rect.end_y = 202;
int width = rect.end_x - rect.start_x;
int height = rect.end_y - rect.start_y;
vx_image output = vxCreateImage(context, width, height, VX_DF_IMAGE_RGB);
// 创建ROI图像
vx_image roi = vxCreateImageFromROI(input, rect);
// 提取R、G、B通道
vxChannelExtractNode(graph, roi, VX_CHANNEL_R, virtu8[0]);
vxChannelExtractNode(graph, roi, VX_CHANNEL_G, virtu8[1]);
vxChannelExtractNode(graph, roi, VX_CHANNEL_B, virtu8[2]);
```
该示例的编译方式与“filterGaussImage.c”类似。
##### 2.2 向感兴趣区域写入
向ROI写入数据的情况相对较少,通常用于修改图像的一部分。例如,我们可以使用Canny边缘检测器增强杯子上对象的边缘。但使用图API实现会有挑战,因为会出现两个节点向同一数据对象写入的情况,导致图验证失败。因此,我们使用立即模式API。
以下是具体的代码实现:
```c
// 创建ROI图像
vx_rectangle_t rect;
rect.start_x = 48;
rect.start_y = 98;
rect.end_x = 258;
rect.end_y = 202;
vx_image roi = vxCreateImageFromROI(input, &rect);
// 创建临时图像
int width = rect.end_x - rect.start_x;
int height = rect.end_y - rect.start_y;
vx_image copy_channel[3], roi_channel[3], edges, edges_inv;
edges = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
edges_inv = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
// 创建阈值对象
vx_pixel_value_t lower, higher;
lower.U32 = 50;
higher.U32 = 100;
vx_threshold threshold = vxCreateThresholdForImage(context,
VX_THRESHOLD_TYPE_RANGE, VX_DF_IMAGE_U8, VX_DF_IMAGE_U8);
if(vxGetStatus(threshold) != VX_SUCCESS)
{
printf("Threshold creation failed\n");
}
vxCopyThresholdRange(threshold, &lower, &higher, VX_WRITE_ONLY,
VX_MEMORY_TYPE_HOST);
// 遍历通道进行处理
enum vx_channel_e channels[] = {VX_CHANNEL_R, VX_CHANNEL_G, VX_CHANNEL_B};
for(int i = 0; i < 3; i++)
{
roi_channel[i] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
copy_channel[i] = vxCreateImage(context, width, height, VX_DF_IMAGE_U8);
vxuChannelExtract(context, roi, channels[i], roi_channel[i]);
vxuCannyEdgeDetector(context, roi_channel[i], threshold, 3,
VX_NORM_L2, edges);
vxuNot(context, edges, edges_inv);
vxuAnd(context, roi_channel[i], edges_inv, copy_channel[i]);
}
// 合并通道并保存图像
vxuChannelCombine(context, copy_channel[0], copy_channel[1], copy_channel[2], NULL, roi);
if(writeImage(input, "cup_roi.ppm"))
printf("Problem writing the output image\n");
```
该示例的编译方式同样与“filterGaussImage.c”类似。
#### 3. 特征提取
##### 3.1 Hough变换
在计算机视觉中,从图像中提取线条是一个重要的功能。OpenVX提供了`vxHoughLinesPNode`函数,它是概率Hough变换算法的实现。该函数以二值图像为输入,返回一组线条。
以下是使用概率Hough变换提取道路线的示例代码:
```c
// 读取输入图像
const char* input_filename = argv[1];
const char* binary_filename = argv[2];
const char* lines_filename = argv[3];
vx_context context = vxCreateContext();
vx_image image, binary;
vxa_read_image((const char *)input_filename, context, &image);
vx_uint32 width, height;
vxQueryImage(image, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
vxQueryImage(image, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
// 创建线条数组和图
const vx_size max_num_lines = 2000;
lines = vxCreateArray(context, VX_TYPE_LINE_2D, max_num_lines);
vx_graph graph = makeHoughLinesGraph(context, image, &binary, &lines);
vxRegisterLogCallback(context, log_callback, vx_true_e);
vxProcessGraph(graph);
// 保存二值图像并绘制线条
vxa_write_image(binary, binary_filename);
vx_pixel_value_t color;
color.RGB[0] = 0;
color.RGB[1] = 255;
color.RGB[2] = 0;
vx_image image_lines;
vx_size _num_lines;
vxQueryArray(lines, VX_ARRAY_NUMITEMS, &_num_lines, sizeof(_num_lines));
draw_lines(context, binary, lines, _num_lines, &color, 2, &image_lines);
vxa_write_image(image_lines, lines_filename);
```
`makeHoughLinesGraph`函数的实现如下:
```c
vx_graph makeHoughLinesGraph(vx_context context, vx_image input, vx_image* binary, vx_array lines)
{
vx_uint32 width, height;
vxQueryImage(input, VX_IMAGE_WIDTH, &width, sizeof(vx_uint32));
vxQueryImage(input, VX_IMAGE_HEIGHT, &height, sizeof(vx_uint32));
int widthr = width/4;
int heightr = height/4;
vx_graph graph = vxCreateGraph(context);
#define nums16 (3)
vx_image virt_s16[nums16];
vx_image virt_nv12 = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_NV12);
vx_image virt_y = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_U8);
vx_image virt_yr = vxCreateVirtualImage(graph, widthr, heightr, VX_DF_IMAGE_U8);
vx_image binary_thresh = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_U8);
for(int i = 0; i < nums16; i++)
{
virt_s16[i] = vxCreateVirtualImage(graph, 0, 0, VX_DF_IMAGE_S16);
}
*binary = vxCreateImage(context, widthr, heightr, VX_DF_IMAGE_U8);
// 转换颜色格式并提取灰度通道
vxColorConvertNode(graph, input, virt_nv12);
vxChannelExtractNode(graph, virt_nv12, VX_CHANNEL_Y, virt_y);
vxScaleImageNode(graph, virt_y, virt_yr, VX_INTERPOLATION_BILINEAR);
// 计算图像梯度幅值
vxSobel3x3Node(graph, virt_yr, virt_s16[0], virt_s16[1]);
vxMagnitudeNode(graph, virt_s16[0], virt_s16[1], virt_s16[2]);
// 应用阈值
vx_threshold thresh = vxCreateThresholdForImage(context,
VX_THRESHOLD_TYPE_BINARY, VX_DF_IMAGE_S16, VX_DF_IMAGE_U8);
vx_pixel_value_t pixel_value;
pixel_value.S16 = 256;
vxCopyThresholdValue(thresh, &pixel_value, VX_WRITE_ONLY, VX_MEMORY_TYPE_HOST);
vx_node thresh_node = vxThresholdNode(graph, virt_s16[2], thresh, binary_thresh);
// 应用膨胀滤波器
vxDilate3x3Node(graph, binary_thresh, *binary);
// 运行Hough变换
vx_hough_lines_p_t hough_params;
hough_params.rho = 1.0f;
hough_params.theta = 3.14f/180;
hough_params.threshold = 100;
hough_params.line_length = 100;
hough_params.line_gap = 10;
hough_params.theta_max = 3.14;
hough_params.theta_min = 0.0;
vx_scalar num_lines = vxCreateScalar(context, VX_TYPE_SIZE, NULL);
vxHoughLinesPNode(graph, *binary, &hough_params, lines, num_lines);
return graph;
}
```
执行该代码后,会发现存在一些误检的线条,需要进行过滤。
以下是Hough变换的处理流程:
```mermaid
graph TD;
A[读取输入图像] --> B[创建图和数组];
B --> C[转换颜色格式并提取灰度通道];
C --> D[计算图像梯度幅值];
D --> E[应用阈值];
E --> F[应用膨胀滤波器];
F --> G[运行Hough变换];
G --> H[保存二值图像并绘制线条];
```
##### 3.2 Hough变换结果后处理
通常,仅仅找到图像中的线条是不够的,还可以从线条中提取关于场景或3D几何的信息。例如,在车道检测问题中,找到消失点(代表道路标记的平行线的交叉点)是很有用的。
为了过滤掉误检的线条,我们创建一个用户节点。以下是实现线条过滤的用户节点的相关代码:
```c
// 过滤线条的计算函数
vx_status VX_CALLBACK filter_lines_calc_function( vx_node node, const vx_reference * refs, vx_uint32 num )
{
vx_array lines = (vx_array) refs[0];
vx_array lines_output = (vx_array) refs[1];
vx_size num_lines = -1;
ERROR_CHECK_STATUS(vxQueryArray(lines, VX_ARRAY_NUMITEMS, &num_lines, sizeof(num_lines)));
char
```
0
0
复制全文
相关推荐









