进过非极大抑制后的图像如下:

跟Sobel梯度幅图像相比,去除了一些非局部极大点,轮廓也进一步细化。
四、用双阈算法检测和连接边缘
双阈的机理是:
指定一个低阈A,一个高阈B,一般取B为图像整体灰度级分布的70%,且B为1.5到2倍大小的A;
灰度大于B的,置为255,灰度小于A的,置为0;
灰度介于A和B之间的,考察改像素点临近的8像素是否有灰度为255的,若没有255的,表示这是一个孤立的局部极大点,予以排除,置为0;若有255的,表示这是一个跟其他边缘有“接壤”的可造之材,置为255,之后重复执行该步骤,直到考察完之后一个像素点。
这个步骤里处理大于高阈和小于低阈的像素点,分别置为255和0;
实现如下:
//******************双阈值处理*************************
//第一个参数imageInput输入和输出的的Sobel梯度幅值图像;
//第二个参数lowThreshold是低阈值
//第三个参数highThreshold是高阈值
//******************************************************
void DoubleThreshold(Mat &imageIput,double lowThreshold,double highThreshold)
{
for(int i=0;i<imageIput.rows;i++)
{
for(int j=0;j<imageIput.cols;j++)
{
if(imageIput.at<uchar>(i,j)>highThreshold)
{
imageIput.at<uchar>(i,j)=255;
}
if(imageIput.at<uchar>(i,j)<lowThreshold)
{
imageIput.at<uchar>(i,j)=0;
}
}
}
}
这里取低阈为60,高阈100,处理效果:

经过双阈处理后,灰度较低的点被消除掉,较高的点置为了255。上图中仍有灰度小于255的点,它们是介于高、低阈间的像素点。
以下是C编码实现,其中在连接的操作上涉及到一个递归调用:
//******************双阈值中间像素连接处理*********************
//第一个参数imageInput输入和输出的的Sobel梯度幅值图像;
//第二个参数lowThreshold是低阈值
//第三个参数highThreshold是高阈值
//*************************************************************
void DoubleThresholdLink(Mat &imageInput,double lowThreshold,double highThreshold)
{
for(int i=1;i<imageInput.rows-1;i++)
{
for(int j=1;j<imageInput.cols-1;j++)
{
if(imageInput.at<uchar>(i,j)>lowThreshold&&imageInput.at<uchar>(i,j)<255)
{
if(imageInput.at<uchar>(i-1,j-1)==255||imageInput.at<uchar>(i-1,j)==255||imageInput.at<uchar>(i-1,j+1)==255||
imageInput.at<uchar>(i,j-1)==255||imageInput.at<uchar>(i,j)==255||imageInput.at<uchar>(i,j+1)==255||
imageInput.at<uchar>(i+1,j-1)==255||imageInput.at<uchar>(i+1,j)==255||imageInput.at<uchar>(i+1,j+1)==255)
{
imageInput.at<uchar>(i,j)=255;
DoubleThresholdLink(imageInput,lowThreshold,highThreshold); //递归调用
}
else
{
imageInput.at<uchar>(i,j)=0;
}
}
}
}
}
滤除或连接后的最终效果:

到这里,Canny算子检测边缘的四个步骤就全部完成了,以下是整个C工程完整代码,有兴趣可以浏览一下:
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-33925-5.html
又不是啥大事
虽然现在美国也是这么做的