OpenCV-图像处理(17、Sobel算子)
卷积应用-图像边缘提取
卷积应用-图像边缘提取
- 边缘是什么 – 是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
- 如何捕捉/提取边缘 – 对图像求它的一阶导数
delta = f(x) – f(x-1), delta越大,说明像素在X方向变化越大,边缘信号越强, - 我已经忘记啦,不要担心,用Sobel算子就好!卷积操作!
Sobel算子
-
是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度
-
Soble算子功能集合高斯平滑和微分求导
-
又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像
-
求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本 Scharr 函数,算子如下:
API说明cv::Sobel
cv::Sobel (
InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度.
Int dx. // X方向,几阶导数
int dy // Y方向,几阶导数.
int ksize, SOBEL算子kernel大小,必须是1、3、5、7、… …
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT
)
API说明cv::Scharr
cv::Scharr (
InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度.
Int dx. // X方向,几阶导数
int dy // Y方向,几阶导数.
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT
)
其它API
- GaussianBlur( src, dst, Size(3,3), 0, 0, BORDER_DEFAULT );
- cvtColor( src, gray, COLOR_RGB2GRAY );
- addWeighted( A, 0.5,B, 0.5, 0, AB);
- convertScaleAbs(A, B)// 计算图像A的像素绝对值,输出到图像B
处理流程
- 高斯模糊 – 去噪声GaussianBlur()
- 转换为灰度图像cvtColor()
- Sobel /Scharr – 一阶导数计算Sobel ()、Scharr ()
- 取绝对值convertScaleAbs()
- 图像按权值合成addWeighted()
- 显示结果
代码示例
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace cv;
Mat src, src_gray;
const char* window_name1 = "Sobel Demo - Simple Edge Detector";
const char* window_name2 = "Scharr Demo - Simple Edge Detector";
void Sobel_Demo();
void Scharr_Demo();
int main( int, char** argv )
{
// 1.加载源图像src
src = imread("E:/Experiment/OpenCV/Pictures/girl.jpg");
if( src.empty()){ //检测图片
printf("could not load image...");
return -1;
}
namedWindow( window_name1, WINDOW_AUTOSIZE );
namedWindow( window_name2, WINDOW_AUTOSIZE );
namedWindow("input",CV_WINDOW_AUTOSIZE);
imshow("input",src);//输出图像
// 2. 先模糊,为了去噪声。将cv :: GaussianBlur应用于我们的图像以减少噪音(内核大小= 3)
GaussianBlur( src, src, Size(3,3), 0, 0, BORDER_DEFAULT );
// 3. 将滤波后的图像转换为灰度图像:
cvtColor( src, src_gray, COLOR_RGB2GRAY );
// 4.分别用 Sobel 算子和 Scharr 算子进行图像边缘化处理
Sobel_Demo();
Scharr_Demo();
waitKey(0);
return 0;
}
void Sobel_Demo(){
// 4.1. 计算x和y方向的导数。 为此,我们使用函数cv :: Sobel
Mat sobelX, sobelY;
int scale = 1;
int delta = 0;
int ddepth = CV_16S; // 输出图像使用 CV_16S 相比输出深度为原图的 CV_8U ,输出的图像梯度更明显
Sobel( src_gray, sobelX, ddepth, 1, 0, 3, scale, delta, BORDER_DEFAULT ); //Sobel X 方向求导,求梯度,输出的图像是二值图
Sobel( src_gray, sobelY, ddepth, 0, 1, 3, scale, delta, BORDER_DEFAULT ); //Sobel Y 方向求导,求梯度
// 4.2. 将部分结果转换回CV_8U:
Mat abs_sobelX, abs_sobelY;
convertScaleAbs( sobelX, abs_sobelX );//convertScaleAbs函数将颜色数据取绝对值,否则图像可能无法显示
convertScaleAbs( sobelY, abs_sobelY );
imshow("SobelX",abs_sobelX);
imshow("SobelY",abs_sobelY);
// 4.3. 通过添加两个方向渐变来近似渐变
Mat dst;
addWeighted( abs_sobelX, 0.5, abs_sobelY, 0.5, 0, dst );//振幅图像,图像合成
// 4.4. 输出结果
imshow( window_name1, dst );
}
void Scharr_Demo(){//Scharr 将梯度更加的放大,相比于 sobel ,非常的不怕干扰
// 4.1. 计算x和y方向的导数。 为此,我们使用函数cv :: Sobel
Mat scharrX, scharrY;
int scale = 1;
int delta = 0;
int ddepth = CV_16S; // 输出图像使用 CV_16S 相比输出深度为原图的 CV_8U ,输出的图像梯度更明显
Scharr( src_gray, scharrX, ddepth, 1, 0, scale, delta, BORDER_DEFAULT );
Scharr( src_gray, scharrY, ddepth, 0, 1, scale, delta, BORDER_DEFAULT );
// 4.2. 将部分结果转换回CV_8U:
Mat abs_scharrX, abs_scharrY;
convertScaleAbs( scharrX, abs_scharrX );//convertScaleAbs函数将颜色数据取绝对值,否则图像可能无法显示
convertScaleAbs( scharrY, abs_scharrY );
imshow("ScharrX",abs_scharrX);
imshow("ScharrY",abs_scharrY);
// 4.3. 通过添加两个方向渐变来近似渐变
Mat dst;
addWeighted( abs_scharrX, 0.5, abs_scharrY, 0.5, 0, dst );//振幅图像,图像合成
// 4.4. 输出结果
imshow( window_name2, dst );
}
运行截图
- 原图
- Sobel 算子
- Scharr 算子