//Sobel算子边缘检测
void photoSobel(const cv::Mat src, cv::Mat& dst)
{
/**
* Sobel Sobel算子边缘检测器
* src 原始图
* dst 目标图
* ddepth 目标图像的所需深度,包括CV_16S/CV_32F/CV_64F等
* ksize 滤波器大小,通常可选为(5,5)或(3,3),或直接使用缺省
* 第四个参数,int类型dx,x 方向上的差分阶数。
* 第五个参数,int类型dy,y方向上的差分阶数。
* 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
* 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
* 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
* 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。
**/
CV_EXPORTS_W void Sobel( InputArray src, OutputArray dst, int ddepth,
int dx, int dy, int ksize = 3,
double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT );
//求 X方向梯度
cv::Mat grad_x, grad_y, abs_grad_x, abs_grad_y;
cv::Sobel(src, grad_x, CV_16S, 1, 0);
cv::convertScaleAbs(grad_x, grad_x);//使用线性变换转换输入数组元素成8位无符号整型
//求 Y方向梯度
cv::Sobel(src, grad_y, CV_16S, 0, 1);
cv::convertScaleAbs(grad_y, grad_y);//使用线性变换转换输入数组元素成8位无符号整型
//将图片转化成为8位图形进行显示
//合并梯度(近似)
cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
}
//Laplacian边缘检测
void photoLaplacian(const cv::Mat src, cv::Mat& dst)
{
/**
* Laplacian Laplacian边缘检测器
* src 原始图
* dst 目标图
* ddepth 目标图像的所需深度,包括CV_16S/CV_32F/CV_64F等
* ksize 滤波器大小,通常可选为(5,5)或(3,3),或直接使用缺省
**/
CV_EXPORTS_W void Laplacian( InputArray src, OutputArray dst, int ddepth,
int ksize = 1, double scale = 1, double delta = 0,
int borderType = BORDER_DEFAULT );
cv::Laplacian(src, dst, CV_16S);
//将图片转化成为8位图形进行显示
cv::convertScaleAbs(dst, dst);
}
Canny算子核心优点:边缘可自动连通
算法步骤:
//Canny边缘检测
void photoCanny(const cv::Mat src, cv::Mat& dst)
{
/**
* Canny Canny边缘检测器
* image 源图像,灰度
* detected_edges 检测器的输出(可以与输入相同)
* threshold1 阈值1
* threshold2 阈值2
* apertureSize Sobel算子大小
* canny边缘检测算法:
1.两个阈值是有区别的,高的那个阈值是将要提取轮廓的物体与背景区分开来,就像阈值分割的参数一样,高的阈值是决定目标与背景对比度的;低的阈值是用来平滑边缘的轮廓,有时高的阈值设置太大了,可能边缘轮廓不连续或者不够平滑,通过低阈值来平滑轮廓线,或者使不连续的部分连接起来。
2.两个阈值:T1,T2。大于T1的称为强边界。T1和T2之间的为弱边界。
如果只有强边界,那么边界可能断断续续。而且会少分割。所以弱边界的作用就是解决上面这个问题。如果强边界点的8连通区域内有弱边界点,那么认为该弱边界点为强边界。
**/
CV_EXPORTS_W void Canny( InputArray image, OutputArray edges,
double threshold1, double threshold2,
int apertureSize = 3, bool L2gradient = false );
cv::Canny(src, dst, 50, 150);
}
/**
* 边缘检测Demo
* Sobel算子、Laplacian、Canny
* 1、边缘检测即图像差分
* 2、常见边缘检测算子包括Robert算子, Sobel算子, LoG算子等, 其中Sobel算子最为常用, LoG 是先进行高斯滤波再进行Laplacian
* 3、二维图像的边缘具有强度和方向两个性质
* 4、Canny算子的基本优点在于检测准确、 对噪声稳健,在实际中广泛应用
**/
#include
#include
//Sobel算子边缘检测
//Sobel算子边缘检测
void photoSobel(const cv::Mat src, cv::Mat& dst)
{
/**
* Sobel Sobel算子边缘检测器
* src 原始图
* dst 目标图
* ddepth 目标图像的所需深度,包括CV_16S/CV_32F/CV_64F等
* ksize 滤波器大小,通常可选为(5,5)或(3,3),或直接使用缺省
* 第四个参数,int类型dx,x 方向上的差分阶数。
* 第五个参数,int类型dy,y方向上的差分阶数。
* 第六个参数,int类型ksize,有默认值3,表示Sobel核的大小;必须取1,3,5或7。
* 第七个参数,double类型的scale,计算导数值时可选的缩放因子,默认值是1,表示默认情况下是没有应用缩放的。我们可以在文档中查阅getDerivKernels的相关介绍,来得到这个参数的更多信息。
* 第八个参数,double类型的delta,表示在结果存入目标图(第二个参数dst)之前可选的delta值,有默认值0。
* 第九个参数, int类型的borderType,我们的老朋友了(万年是最后一个参数),边界模式,默认值为BORDER_DEFAULT。这个参数可以在官方文档中borderInterpolate处得到更详细的信息。
**/
//求 X方向梯度
cv::Mat grad_x, grad_y, abs_grad_x, abs_grad_y;
cv::Sobel(src, grad_x, CV_16S, 1, 0);
cv::convertScaleAbs(grad_x, grad_x);//使用线性变换转换输入数组元素成8位无符号整型
//求 Y方向梯度
cv::Sobel(src, grad_y, CV_16S, 0, 1);
cv::convertScaleAbs(grad_y, grad_y);//使用线性变换转换输入数组元素成8位无符号整型
//将图片转化成为8位图形进行显示
//合并梯度(近似)
cv::addWeighted(abs_grad_x, 0.5, abs_grad_y, 0.5, 0, dst);
}
//Laplacian边缘检测
void photoLaplacian(const cv::Mat src, cv::Mat& dst)
{
/**
* Laplacian Laplacian边缘检测器
* src 原始图
* dst 目标图
* ddepth 目标图像的所需深度,包括CV_16S/CV_32F/CV_64F等
* ksize 滤波器大小,通常可选为(5,5)或(3,3),或直接使用缺省
**/
cv::Laplacian(src, dst, CV_16S);
//将图片转化成为8位图形进行显示
cv::convertScaleAbs(dst, dst);
}
//Canny边缘检测
void photoCanny(const cv::Mat src, cv::Mat& dst)
{
/**
* Canny Canny边缘检测器
* image 源图像,灰度
* detected_edges 检测器的输出(可以与输入相同)
* threshold1 阈值1
* threshold2 阈值2
* apertureSize Sobel算子大小
**/
cv::Canny(src, dst, 50, 150);
}
int main()
{
// 读取图片
std::string imagename = "Standard_image/lena.jpg";
cv::Mat img = cv::imread(imagename, cv::IMREAD_GRAYSCALE);
// 判断载入图片是否成功
if (img.empty())
{
std::cout << "miss the image file : " + imagename << std::endl;
return -1;
}
cv::Mat SobelImg, LaplacianImg, CannyImg;
photoSobel(img, SobelImg);
photoLaplacian(img, LaplacianImg);
photoCanny(img, CannyImg);
cv::imshow("原图", img);
cv::imshow("Sobel", SobelImg);
cv::imshow("Laplacian", LaplacianImg);
cv::imshow("Canny", CannyImg);
cv::waitKey();
return 0;
}