a.高斯模糊——GaussianBlur
b. 灰度转换——cvtColor
c. 计算梯度——Sobel/Scharr
d. 非最大信号抑制
e. 高低阈值输出二值图像
首先经过梯度的计算,得到X,Y方向上的两个梯度,然后计算总梯度(对GX,GY的平方和开平方或者绝对值相加)
X方向
-1 | 0 | +1 |
---|---|---|
-2 | 0 | +2 |
-1 | 0 | +1 |
Y方向
-1 | -2 | -1 |
---|---|---|
0 | 0 | 0 |
+1 | +2 | +1 |
梯度计算公式:
G=√Gx2+Gy2
梯度方向(0-180)
α = a r c t a n ( G y / G x ) \alpha=arctan(G~y~/G~x~) α=arctan(G y /G x )
根据方向做切线,在切线方向上看左右两个相邻的两个像素,如果大于左右两个像素,则记为边缘,若小于左右两个像素,则该像素值像素值应该用0填充。
T1,T2为阈值,凡是和高于T2的都保留,凡是小于T1的都丢弃,从高于T2的像素出发,凡是大于T1而且相互连接的,都保留,最终得到一个输出二值图像。
推荐的高低阈值比值为T2:T1=3:1/2:1,其中T2为高阈值,T1为低阈值。
Canny(
InputArray src, //8-bit的输入图像
OutputArray edges, //输出边缘图像,一般都是二值图像,背景是黑色
double threshold1, //低阈值,常取高阈值的1/2或者1/3
double threshold2, //高阈值
int aptertureSize, //Sobel算子的size,通常是3*3,取值3
bool L2gradient //选择true表示是L2来归一化,否则用L1归一化
)
代码演示:
#include
#include
#include
using namespace cv;
Mat src, dstGaussian,dst;
Mat gray;
int t1_value = 40; //滑块的初始值
int max_value = 255; //滑块的最大值
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int,void*) {
Mat edge_output;
//GaussianBlur(gray, dstGaussian, Size(3, 3), 0, 0);
blur(gray, dstGaussian, Size(3, 3), Point(-1,-1), BORDER_DEFAULT);
Canny(dstGaussian, edge_output, t1_value, t1_value * 2, 3, false);
dst.create(src.size(), src.type());
src.copyTo(dst, edge_output); //把边缘中非零的复制过去,显示出来彩色图像
//函数的说明:把edge_output作为一个mask,mask上为0的图像不复制,复制值为1的图像。
//dege_output本身就是一个二值图像
imshow(OUTPUT_TITLE, edge_output);
imshow(OUTPUT_TITLE, ~edge_output);
//在dege_output前面加上~,表示把原来黑色变成白色,白色变成黑色
}
int main(int argc, int argv) {
src = imread("D:/image/img1.jpg");
if (src.empty()) {
printf("could not load image...\n");
return -1;
}
imshow("src", src);
cvtColor(src, gray, COLOR_BGR2GRAY);
createTrackbar("Threshold Value:",OUTPUT_TITLE,&t1_value,max_value,Canny_Demo);
Canny_Demo(0,0);
waitKey(0);
return 0;
}