OpenCV三种边缘检测简介
一般步骤
- 滤波,以除去噪声
- 增强,将领域内有显著变化的像素点凸显
- 检测,从可疑边缘点中舍去非边缘点,一般用threshold进行处理
Canny算子
步骤
- 采用size=5的高斯内核进行卷积降噪
K= 1139 ⎛⎝⎜⎜⎜⎜⎜245424912945121512549129424542⎞⎠⎟⎟⎟⎟⎟ - 计算梯度幅值和方向——此处采用sobel算法
- 非极大值抑制,排除非边缘像素
- 滞后阀值
- 若幅值->(low, high),当且仅当连接到一个高于high阀值的像素时被保留
- 若幅值>high阀值,保留
- 若幅值
应用代码
canny(src, dst, low, high, 3);
Sobel算子
水平方向求导:
K=⎛⎝⎜⎜−1−2−1000+1+2+1⎞⎠⎟⎟∗I
sobel(src, grad_x, CV_16S, 1, 0, 3, scale=1, delta=1, BORDER_DEFAULT);
convertScaleAbs(grad_x, abs_grad_x);
垂直方向求导:
K=⎛⎝⎜⎜−1−2−1000+1+2+1⎞⎠⎟⎟∗I
sobel(src, grad_x, CV_16S, 0, 1, 3, scale=1, delta=1, BORDER_DEFAULT);
convertScaleAbs(grad_y, abs_grad_y);
合并梯度
addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
Laplacian算子
Laplacian(src, dst, CV_16S, 3, 1, 0, BORDER_DEFAULT);
Scharr 滤波器
当内核大小为 3 时, 以上Sobel内核可能产生比较明显的误差(毕竟,Sobel算子只是求取了导数的近似值)。 为解决这一问题,OpenCV提供了 Scharr 函数,但该函数仅作用于大小为3的内核。该函数的运算与Sobel函数一样快,但结果却更加精确。
以下两句代码等价,由于两者参数几乎一致(除了Scharr舍去了ksize,因为默认为3,且不可修改)
Scharr(src, dst, CV_16S, dx, dy, scale=1, delta=1, BORDER_DEFAULT);
Sobel(src, dst, CV_16S, dx, dy, CV_SCHARR, scale=1, delta=1, BORDER_DEFAULT);
示例代码:
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <stdlib.h>
#include <stdio.h>
using namespace cv;
/** @function main */
int main( int argc, char** argv )
{
Mat src, src_gray;
Mat grad;
char* window_name = "Sobel Demo - Simple Edge Detector";
int scale = 1;
int delta = 0;
int ddepth = CV_16S;
int c;
/// 装载图像
src = imread( argv[1] );
if( !src.data )
{ return -1; }
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
/// 转换为灰度图
cvtColor( src, src_gray, CV_RGB2GRAY );
/// 创建显示窗口
namedWindow( window_name, CV_WINDOW_AUTOSIZE );
/// 创建 grad_x 和 grad_y 矩阵
Mat grad_x, grad_y;
Mat abs_grad_x, abs_grad_y;
/// 求 X方向梯度
//Scharr( src_gray, grad_x, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_x, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_x, abs_grad_x );
/// 求Y方向梯度
//Scharr( src_gray, grad_y, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
Sobel( src_gray, grad_y, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT );
convertScaleAbs( grad_y, abs_grad_y );
/// 合并梯度(近似)
addWeighted( abs_grad_x, 0.5, abs_grad_y, 0.5, 0, grad );
imshow( window_name, grad );
waitKey(0);
return 0;
}