什么是Sobel 算子
- 是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度
- Soble算子功能集合高斯平滑和微分求导
- 又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像
水平梯度
垂直梯度
最终图像梯度
求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:
cv::Sobel
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 );
/*******************************************************************
* src: 输入图
* dst: 输出图
* ddepth: 输出图深度 CV_16S/CV_32F/CV_64F等
* dx: x方向上的差分阶数
* dy: y方向上的差分阶数
* ksize: 卷积核大小,一般5*5或3*3
* scale: 计算导数值时可选的缩放因子
* delta: 默认为0
* borderType: 边缘处理模式
*********************************************************************/
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
)
convertScaleAbs 对整个图像数组中的每个元素进行比例缩放和绝对值运算,并将结果存储在输出数组中
void cv::convertScaleAbs
(
cv::InputArray src, // 输入数组
cv::OutputArray dst, // 输出数组
double alpha = 1.0, // 乘数因子
double beta = 0.0 // 偏移量
);
代码演示
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
Mat src, gray_src, dst;
const char* output_title = "final image";
int main()
{
src = imread("test.jpg");//读取图片
if (src.empty())
{
cout << "could not load img...";
return -1;
}
namedWindow(output_title);//设置窗口名称
imshow(output_title, src);
Mat gray_src;
GaussianBlur(src, dst, Size(3, 3), 0, 0);
cvtColor(dst, gray_src, COLOR_BGR2GRAY);
imshow("gray image", gray_src);
Mat xgrad, ygrad; // 定义水平和垂直梯度图像的Mat对象
Scharr(gray_src, xgrad, CV_16S, 1, 0); // 计算灰度图像的水平方向梯度
Scharr(gray_src, ygrad, CV_16S, 0, 1); // 计算灰度图像的垂直方向梯度
convertScaleAbs(xgrad, xgrad); // 将水平梯度图像进行数据类型转换
convertScaleAbs(ygrad, ygrad); // 将垂直梯度图像进行数据类型转换
imshow("xgrad", xgrad); // 在窗口中显示水平梯度图像
imshow("ygrad", ygrad); // 在窗口中显示垂直梯度图像
Mat xygrad = Mat(xgrad.size(), xgrad.type()); // 定义最终的边缘强度图像Mat对象
printf("type : %d\n", xgrad.type()); // 打印图像数据类型
int width = xgrad.cols; // 获取图像宽度
int height = ygrad.rows; // 获取图像高度
for (int row = 0; row < height; row++) {
for (int col = 0; col < width; col++) {
int xg = xgrad.at<uchar>(row, col); // 获取当前位置的水平梯度值
int yg = ygrad.at<uchar>(row, col); // 获取当前位置的垂直梯度值
int xy = xg + yg; // 计算当前位置的边缘强度值
xygrad.at<uchar>(row, col) = saturate_cast<uchar>(xy); // 将边缘强度值限定在0到255之间
}
}
imshow(output_title, xygrad);
waitKey(0);
return 0;
}