边缘检测算子类别
常见边缘检测算子:Roberts 、Sobel 、Prewitt、Laplacian、Log/Marr、Canny、Kirsch、Nevitia
1、一阶微分算子:Roberts 、Sobel 、Prewitt
我们看这三种边缘检测算子模板及写成差分的形式
Roberts算子:
Sobel算子:
Prewitt算子:
计算边缘幅值与方向
以Sobel算子为例:
G很多情况下简化为:
或者
各向同性Sobel算子:
Sobel各向同性算子的权值比普通Sobel算子的权值更准确。为什么?模板的权值是离中心位置越远则权值(看绝对值)影响越小,如上图,把模板看成是9个小正方形,小正方形边长为1,则虚线三角形的斜边长为,下直角边长为1,则如果(0,0)位置权值绝对值大小为1,则按照距离关系,位置(1,0)处的权值绝对值大小应该为才是准确的。
二阶微分算子:Laplacian、Log/Marr
Laplacian算子:
拉普拉斯算子数学公式是:
写成差分形式为:
Log算子:
Log边缘检测则是先进行高斯滤波再进行拉普拉斯算子检测,然后找过零点来确定边缘位置,很多时候我们只是知道Log 5*5模板如上图所示。
非微分边缘检测算子:Canny
Canny边缘检测步骤:
1. 对图像进行高斯模糊----GaussianBlur
2. 彩色图像转换为灰度图像----cvtcolor
3. 计算图像梯度,根据梯度计算图像边缘幅值与角度(这里其实用到了微分边缘检测算子来计算梯 度幅值方向)---Sobel/Scharr
4. 非最大信号压制处理(边缘细化)
*俗意义上是指寻找像素点局部最大值,将非极大值点所对应的灰度值置为0
5. 高低阈值输出二值图像
*T1,T2为阈值,凡是高于T2的部分都保留,凡是低于T1的都丢弃,从T2的像素出发,凡是大于T1且相互连接的都保留。最终得到一个输出二值图像。
*推荐的高低阈值比为T2/T1=3:1或者2:1,其中T2为高阈值,T1为低阈值。
以下是opencv实现canny算法:
#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace cv;
Mat src, gray_src, dst;
int threshold_value = 50;
int max_value = 255;
void Canny_Demo(int, void*);
int main(int argc, char**argv) {
src = imread("D:/picture/opencv/images/lenna.png");
if (!src.data) {
printf("could not load image.../n");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
namedWindow("output image", CV_WINDOW_AUTOSIZE);
imshow("input image", src);
createTrackbar("Threshold Value:", "output image", &threshold_value, max_value, Canny_Demo);
Canny_Demo(0, 0);
waitKey(0);
return 0;
}
void Canny_Demo(int, void*) {
Mat edge_image;
blur(src, src, Size(3, 3), Point(-1,-1),BORDER_DEFAULT);
cvtColor(src, gray_src, CV_BGR2GRAY);
Canny(gray_src, edge_image, threshold_value, 2 * threshold_value, 3, false);
imshow("edge_image", edge_image);
dst.create(src.size(), src.type());
src.copyTo(dst, edge_image);//mask(edge_image)非零的话拷贝到dst;
imshow("output image", dst);
}