1.原理
个人觉得和Sobel算子差不多,不过其对高低阈值又进行了一个控制,下面介绍。
2.相关API
Canny(InputArray src,OutputArray edges,double threshold1,double threshold2,int aptertureSize,bool L2gradient )
参数1:8-bit的输入图像
参数2:输出边缘图像, 一般都是二值图像,背景是黑色
参数3:低阈值
参数4:高阈值(为低阈值2到3倍)
参数5:Soble算子的size,通常3x3,取值3
参数6:归一化方法,一般用L1取绝对值
参数3和4的解释:T1, T2为高低阈值,凡是高于T2的都保留,凡是小于T1都丢弃,从高于T2的像素出发,凡是大于T1而且相互连接的,都保留。最终得到一个输出二值图像。
3.代码实现
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
#include <math.h>
using namespace std;
using namespace cv;
Mat src, dst,srcGray,result;
char inputName[] = "input name";
char outputName[] = "output name";
int t1Value = 50;
int maxValue = 255;
void CannyDemo(int, void*);
int main()
{
src = imread("D:/demo.jpg");
if (src.empty())
{
cout << "找不到图像" << endl;
return -1;
}
namedWindow(inputName, CV_WINDOW_AUTOSIZE);
imshow(inputName, src);
namedWindow(outputName, CV_WINDOW_AUTOSIZE);
GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, srcGray, CV_BGR2GRAY);
createTrackbar("Threshold T1 Value", outputName, &t1Value, maxValue, CannyDemo);
CannyDemo(0, 0);
waitKey(0);
return 0;
}
void CannyDemo(int, void*)
{
Mat final;
Canny(srcGray, result, t1Value, t1Value * 3, 3, false);
final.create(src.size(), src.type());
src.copyTo(final, result);//A.copyTo(B, mask),如果在某个像素点(i, j)其值为1(只看第一通道,所以mask单通道即可),则把A.at(i, j)处的值直接赋给B.at(i, j),如果其值为0则B.at(i, j)处保留其原始像素值。这样能够使得图标边缘的颜色和原图保持一致。
imshow(outputName, final);
}
4.运行结果
当低阈值较低时候保留的细节越多,所以轮廓越明显。低阈值高的时候如下: