Canny

Canny算子是一种边缘检测器,它使用多阶段算法来检测图像中的大范围边缘。

算子效果

输入图像参数输出图像
imagethreshold1 = 100
threshold2 = 400
kernelSize = 3
norm = HB_VP_NORM_L1
image

原理

算子的计算过程分为多个阶段:

  1. 梯度计算

输入图像在垂直和水平方向上使用Sobel内核进行卷积,核大小由Sobel尺寸参数确定。然后在水平和垂直方向上使用边缘检测过滤器进行过滤,从而产生 Gx 和 Gy。 每个像素的强度和角度计算如下:

Intensity=dx2+dy2Intensity=\sqrt{dx^2+dy^2}

Angle=arctan(dydx)Angle=arctan(\frac{dy}{dx})

  1. 非极大值抑制 (non-maximum suppression)

对于图像中的每个像素,检查强度是否是梯度方向上的局部最大值。如果是,则将其保留为边缘像素,否则将其作为非边缘像素移除。

  1. 双重阈值化

将每个像素的强度大小与强阈值(ℎ𝑖𝑔ℎ_𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑)和弱阈值(𝑙𝑜𝑤_𝑡ℎ𝑟𝑒𝑠ℎ𝑜𝑙𝑑)进行比较,如果强度大于强阈值,则将其标记为强边缘。如果强度小于弱阈值,则标记为无边缘。强阈值和弱阈值之间的强度值都被标记为弱边缘。

  1. 边缘追踪

如果弱边连接到强边,那么这条弱边就变成了强边。重复这个过程,直到找到所有连接到强边的弱边。然后将其余的弱边标记为非边,就得到了整个图像的边缘检测结果。

API接口

int32_t hbVPCanny(hbUCPTaskHandle_t *taskHandle,
                  hbVPImage *dstImg,
                  hbVPImage const *srcImg,
                  hbVPCannyParam const *cannyParam);

详细接口信息请查看 hbVPCanny

使用方法

// Include the header
#include "hobot/hb_ucp.h"
#include "hobot/vp/hb_vp.h"
#include "hobot/vp/hb_vp_canny.h"

// init Image, allocate memory for image data
hbUCPSysMem src_mem;
hbUCPMallocCached(&src_mem, src_stride * src_height, 0);
hbVPImage src_img{HB_VP_IMAGE_FORMAT_Y,
                  HB_VP_IMAGE_TYPE_U8C1,
                  src_width,
                  src_height,
                  src_stride,
                  src_mem.virAddr,
                  src_mem.phyAddr,
                  nullptr,
                  0,
                  0};

hbUCPSysMem dst_mem;
hbUCPMallocCached(&dst_mem, dst_stride * dst_height, 0);
hbVPImage dst_img{HB_VP_IMAGE_FORMAT_Y,
                  HB_VP_IMAGE_TYPE_U8C1,
                  dst_width,
                  dst_height,
                  dst_stride,
                  dst_mem.virAddr,
                  dst_mem.phyAddr,
                  nullptr,
                  0,
                  0};

// init param
hbVPCannyParam canny_param;
canny_param.threshold1 = 100;
canny_param.threshold2 = 400;
canny_param.kernelSize = 3;
canny_param.norm = HB_VP_NORM_L1;

// init task handle and schedule param
hbUCPTaskHandle_t task_handle{nullptr};
hbUCPSchedParam sched_param;
HB_UCP_INITIALIZE_SCHED_PARAM(&sched_param);
sched_param.backend = HB_UCP_DSP_CORE_0;

// create task
hbVPCanny(&task_handle, &dst_img, &src_img, &canny_param);

// submit task
hbUCPSubmitTask(task_handle, &sched_param);

// wait for task done 
hbUCPWaitTaskDone(task_handle, 0);

// release task handle
hbUCPReleaseTask(task_handle);

// release memory
hbUCPFree(&src_mem);
hbUCPFree(&dst_mem);