概述
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 中平滑后的图像与水平和垂直方向的边缘检测滤波器进行滤波,得到 \(G_x\) 和 \(G_y\)。每个像素的强度和角度计算如下\begin{align*} Intensity &= \sqrt{G_x^2 + G_y^2} \\ Angle &= arctan(\frac{G_y}{G_x}) \end{align*}
梯度方向始终垂直于边缘。它被四舍五入为代表垂直、水平和两个对角线方向的四个角度之一。
- 通过非极大值抑制细化边缘
对于图像中的每个像素,检查强度是否是梯度方向上的局部最大值。如果是,则将其保留为边缘像素,否则将其删除为非边缘像素。
- 双阈值处理
提供了两个阈值,它们被称为强阈值和弱阈值。对于每个像素,如果强度大于强阈值,则将其标记为强边缘。如果强度小于弱阈值,则将其标记为非边缘。任何强度值介于强阈值和弱阈值之间都被标记为弱边缘。
- 通过迟滞跟踪边缘
如果弱边缘连接到强边缘,则此弱边缘将更改为强边缘。重复此过程,直到找到所有连接到强边缘的弱边缘。将剩余的弱边缘标记为非边缘。
C API 函数
有关实现该算法的限制、约束和后端的列表,请查阅以下函数的参考文档
用法
语言
- 导入 VPI 模块
- 使用 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)
- 初始化阶段
- 包含定义 Canny 边缘检测器算法函数和参数结构的头文件。
- 定义输入图像对象。
struct VPIImageImpl * VPIImage
图像的句柄。
- 创建输出图像对象。
int32_t w, h;
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)
获取图像尺寸(以像素为单位)。
- 创建将在其中提交算法以执行的流。
struct VPIStreamImpl * VPIStream
流的句柄。
VPIStatus vpiStreamCreate(uint64_t flags, VPIStream *stream)
创建流实例。
- 为将执行校正的 Canny 边缘检测器算法创建负载。
int width, height;
VPIStatus vpiCreateCannyEdgeDetector(uint64_t backends, int32_t imageWidth, int32_t imageHeight, VPIPayload *payload)
为 vpiSubmitCannyEdgeDetector 创建负载。
struct VPIPayloadImpl * VPIPayload
算法负载的句柄。
@ VPI_BACKEND_CUDA
CUDA 后端。
- 处理阶段
- 使用用户提供的参数初始化参数结构。在此示例中,参数设置为反映上面的输出,
VPIStatus vpiInitCannyEdgeDetectorParams(VPICannyEdgeDetectorParams *params)
使用默认值初始化 vpiInitCannyEdgeDetectorParams。
定义 vpiSubmitCannyEdgeDetector 参数的结构。
- 将算法及其参数提交到流。
float thresholdStrong = 300;
float thresholdWeak = 100;
float edgeValue = 255;
float nonEdgeValue = 0;
thresholdWeak, edgeValue, nonEdgeValue, ¶ms));
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 边缘检测器算法。
- (可选)等待直到处理完成。
VPIStatus vpiStreamSync(VPIStream stream)
阻止调用线程,直到此流队列中的所有提交命令都完成(队列为空)。。。
- 清理阶段
- 释放流、输入图像和输出图像所持有的资源。
void vpiImageDestroy(VPIImage img)
销毁图像实例。
void vpiStreamDestroy(VPIStream stream)
销毁流实例并释放所有硬件资源。
有关更多信息,请参阅 VPI - 视觉编程接口 的“C API 参考”部分中的 Canny 边缘检测器。
性能
有关如何使用下面的性能表的信息,请参阅 算法性能表。
在比较测量结果之前,请查阅 比较算法运行时间。
有关性能基准测试方式的更多信息,请参阅 性能基准。
-
参考
- https://en.wikipedia.org/wiki/Canny_edge_detector