VPI - 视觉编程接口

3.2 版本

Canny 边缘检测器

概述

Canny 边缘检测器是一种边缘检测算子,它使用多阶段算法来检测图像中各种各样的边缘,请参阅 [1]。下表显示了一个输入图像示例、Canny 边缘检测器算法的一组输入参数(如下所述)以及相应的边缘图像。

输入参数输出

\begin{align*} \mathit{normType} &= VPI\_NORM\_L2 \\ \mathit{gradMethod} &= GEN\_GRADIENT\_SOBEL \\ \mathit{gradientSize} &= 3 \\ \mathit{edgeValue} &= 255 \\ \mathit{nonEdgeValue} &= 0 \\ \mathit{thresholdStrong} &= 300 \\ \mathit{thresholdWeak} &= 100 \end{align*}

实现

Canny 边缘检测器是一种多阶段算法

  1. 降噪
    由于边缘检测很容易受到噪声的影响,因此首先对图像应用高斯滤波器。
  2. 查找图像中每个像素的强度和角度
    然后,将阶段 1 中平滑后的图像与水平和垂直方向的边缘检测滤波器进行滤波,得到 \(G_x\) 和 \(G_y\)。每个像素的强度和角度计算如下

    \begin{align*} Intensity &= \sqrt{G_x^2 + G_y^2} \\ Angle &= arctan(\frac{G_y}{G_x}) \end{align*}

    梯度方向始终垂直于边缘。它被四舍五入为代表垂直、水平和两个对角线方向的四个角度之一。
  3. 通过非极大值抑制细化边缘
    对于图像中的每个像素,检查强度是否是梯度方向上的局部最大值。如果是,则将其保留为边缘像素,否则将其删除为非边缘像素。
  4. 双阈值处理
    提供了两个阈值,它们被称为强阈值和弱阈值。对于每个像素,如果强度大于强阈值,则将其标记为强边缘。如果强度小于弱阈值,则将其标记为非边缘。任何强度值介于强阈值和弱阈值之间都被标记为弱边缘。
  5. 通过迟滞跟踪边缘
    如果弱边缘连接到强边缘,则此弱边缘将更改为强边缘。重复此过程,直到找到所有连接到强边缘的弱边缘。将剩余的弱边缘标记为非边缘。

C API 函数

有关实现该算法的限制、约束和后端的列表,请查阅以下函数的参考文档

函数描述
vpiCreateCannyEdgeDetector vpiSubmitCannyEdgeDetector 创建负载。
vpiInitCannyEdgeDetectorParams 使用默认值初始化 vpiInitCannyEdgeDetectorParams
vpiSubmitCannyEdgeDetector 对图像运行 Canny 边缘检测器算法。

用法

语言
  1. 导入 VPI 模块
    import vpi
  2. 使用 CUDA 后端和给定的内核在输入图像上运行 Canny 边缘检测器。输入和输出是 VPI 图像。
    with vpi.Backend.CUDA
    output = input.canny(thresh_strong=300, thresh_weak=100, edge_value=255, nonedge_value=0, norm=vpi.Norm.L2)
  1. 初始化阶段
    1. 包含定义 Canny 边缘检测器算法函数和参数结构的头文件。
      声明实现 Canny 边缘检测器算法的函数。
    2. 定义输入图像对象。
      VPIImage input = /*...*/;
      struct VPIImageImpl * VPIImage
      图像的句柄。
      Definition: Types.h:256
    3. 创建输出图像对象。
      int32_t w, h;
      vpiImageGetSize(input, &w, &h);
      VPIImage output;
      vpiImageCreate(w, h, VPI_IMAGE_FORMAT_U8, 0, &output);
      #define VPI_IMAGE_FORMAT_U8
      具有一个 8 位无符号整数通道的单平面。
      Definition: ImageFormat.h:100
      VPIStatus vpiImageCreate(int32_t width, int32_t height, VPIImageFormat fmt, uint64_t flags, VPIImage *img)
      使用指定的标志创建空的图像实例。
      VPIStatus vpiImageGetSize(VPIImage img, int32_t *width, int32_t *height)
      获取图像尺寸(以像素为单位)。
    4. 创建将在其中提交算法以执行的流。
      VPIStream stream;
      vpiStreamCreate(0, &stream);
      struct VPIStreamImpl * VPIStream
      流的句柄。
      Definition: Types.h:250
      VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
      创建流实例。
    5. 为将执行校正的 Canny 边缘检测器算法创建负载。
      int width, height;
      vpiImageGetSize(input, &width, &height);
      VPIPayload payload;
      vpiCreateCannyEdgeDetector(VPI_BACKEND_CUDA, width, height, &payload);
      VPIStatus vpiCreateCannyEdgeDetector(uint64_t backends, int32_t imageWidth, int32_t imageHeight, VPIPayload *payload)
      为 vpiSubmitCannyEdgeDetector 创建负载。
      struct VPIPayloadImpl * VPIPayload
      算法负载的句柄。
      Definition: Types.h:268
      @ VPI_BACKEND_CUDA
      CUDA 后端。
      Definition: Types.h:93
  2. 处理阶段
    1. 使用用户提供的参数初始化参数结构。在此示例中,参数设置为反映上面的输出,
      VPIStatus vpiInitCannyEdgeDetectorParams(VPICannyEdgeDetectorParams *params)
      使用默认值初始化 vpiInitCannyEdgeDetectorParams。
      定义 vpiSubmitCannyEdgeDetector 参数的结构。
      Definition: CannyEdges.h:108
    2. 将算法及其参数提交到流。
      float thresholdStrong = 300;
      float thresholdWeak = 100;
      float edgeValue = 255;
      float nonEdgeValue = 0;
      VPI_CHECK_STATUS(vpiSubmitCannyEdgeDetector(stream, VPI_BACKEND_CUDA, payload, input, output, thresholdStrong,
      thresholdWeak, edgeValue, nonEdgeValue, &params));
      VPIStatus vpiSubmitCannyEdgeDetector(VPIStream stream, uint64_t backend, VPIPayload payload, VPIImage input, VPIImage output, float thresholdStrong, float thresholdWeak, float edgeValue, float nonEdgeValue, const VPICannyEdgeDetectorParams *params)
      对图像运行 Canny 边缘检测器算法。
    3. (可选)等待直到处理完成。
      vpiStreamSync(stream);
      VPIStatus vpiStreamSync(VPIStream stream)
      阻止调用线程,直到此流队列中的所有提交命令都完成(队列为空)。。。
  3. 清理阶段
    1. 释放流、输入图像和输出图像所持有的资源。
      vpiImageDestroy(output);
      void vpiImageDestroy(VPIImage img)
      销毁图像实例。
      void vpiStreamDestroy(VPIStream stream)
      销毁流实例并释放所有硬件资源。

有关更多信息,请参阅 VPI - 视觉编程接口 的“C API 参考”部分中的 Canny 边缘检测器

性能

有关如何使用下面的性能表的信息,请参阅 算法性能表
在比较测量结果之前,请查阅 比较算法运行时间
有关性能基准测试方式的更多信息,请参阅 性能基准

 - 

参考

  1. https://en.wikipedia.org/wiki/Canny_edge_detector