1. 卷积应用——图像边缘提取
- 边缘是什么 – 是像素值发生跃迁的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
- 如何捕捉(提取边缘) —— 对图像求它的一阶导数
delta = f(x) – f(x-1), delta越大,说明像素在X方向变化越大,边缘信号越强。
- 用Sobel算子,卷积操作。
2.Soble算子
- Soble算子是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度
- Soble算子功能集合高斯平滑和微分求导,又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方向与Y方向梯度图像
- 求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:
3. 相关API
3.1 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
)
- 输出深度须大于或等于输入深度。
- 以下为用cv::Sobel()输出的结果。其中dst1是用addWeighted()融合出来的结果,dst是采用各像素值相加融合出来的结果,符合公式。
3.2 cv::Scharr()
- 为cv::Sobel()的改进版,处理后的边缘更明显,用法与cv::Sobel()一致。
cv::Scharr (
InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度.
Int dx. // X方向,几阶导数
int dy // Y方向,几阶导数.
double scale = 1
double delta = 0
int borderType = BORDER_DEFAULT
)
- 以下为用cv::Scharr()输出的结果。其中dst1是用addWeighted()融合出来的结果,dst是采用各像素值相加融合出来的结果,符合公式。
3.3 其他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
4.边缘提取步骤
- 输入图像imread();
- 高斯模糊滤波GaussianBlur();
- 转化为灰度图像cvtColor();
- 分别提取水平和竖直边缘Sobel()或Scharr();
- 融合addWeighted()或各个像素值相加。
5.例程
#include<opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
int main() {
Mat src, dst;
src = imread("D:/resource/images/face.jpg");
if (src.empty()) {
printf("The image could not be loaded....");
return -1;
}
imshow("input image", src);
Mat blur_image, gray_image, SobelX_image, SobelY_image;
GaussianBlur(src, blur_image, Size(3, 3), 0);
cvtColor(blur_image, gray_image, COLOR_BGR2GRAY);
//Scharr(gray_image, SobelX_image, CV_16S, 1, 0);
//Scharr(gray_image, SobelY_image, CV_16S, 0, 1);
Sobel(gray_image, SobelX_image, CV_16S, 1, 0);
Sobel(gray_image, SobelY_image, CV_16S, 0, 1);
convertScaleAbs(SobelX_image, SobelX_image);
convertScaleAbs(SobelY_image, SobelY_image);
imshow("Sobel水平梯度", SobelX_image);
imshow("Sobel竖直梯度", SobelY_image);
Mat dst1;
addWeighted(SobelX_image, 0.5, SobelY_image, 0.5, 0, dst1);
imshow("dst1", dst1);
dst = Mat(SobelX_image.size(), SobelX_image.type());
std::cout << src.type();
for (int row = 0; row < SobelY_image.rows; row++)
{
for (int col = 0; col < SobelX_image.cols; col++)
{
int xg = SobelX_image.at<uchar>(row, col);
int yg = SobelY_image.at<uchar>(row, col);
int xy = xg + yg;
dst.at<uchar>(row, col) = saturate_cast<uchar>(xy);
}
}
imshow("dst", dst);
waitKey(0);
return 0;
}