【OpenCV】Sobel算子

卷积应用-图像边缘提取
在这里插入图片描述
边缘是什么 – 是像素值发生阶跃变化的地方,是图像的显著特征之一,在图像特征提取、对象检测、模式识别等方面都有重要的作用。
如何捕捉/提取边缘 – 对图像求它的一阶导数
delta = f(x) – f(x-1), delta越大,说明像素在X方向变化越大,边缘信号越强
Sobel算子
是离散微分算子(discrete differentiation operator),用来计算图像灰度的近似梯度
Soble算子功能集合高斯平滑和微分求导
又被称为一阶微分算子,求导算子,在水平和垂直两个方向上求导,得到图像X方法与Y方向梯度图像
水平梯度
在这里插入图片描述
垂直梯度

在这里插入图片描述
最终图像梯度

在这里插入图片描述
求取导数的近似值,kernel=3时不是很准确,OpenCV使用改进版本Scharr函数,算子如下:
在这里插入图片描述
相关APIcv::Sobel

cv::Sobel (
InputArray Src // 输入图像
OutputArray dst// 输出图像,大小与输入图像一致
int depth // 输出图像深度. 
Int dx.  // X方向,几阶导数
int dy // Y方向,几阶导数. 
int ksize, SOBEL算子kernel大小,必须是1357double scale  = 1
double delta = 0
int borderType = BORDER_DEFAULT
)

在这里插入图片描述

相关APIcv::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
)
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

在这里插入图片描述
代码实现

#include<opencv2/opencv.hpp>
#include<iostream>
#include<math.h>
using namespace std;
using namespace cv;

int main(int argc, char**argv)
{
	Mat src, gray_src, dst,dst2;
	src = imread("1.jpg");
	if (!src.data) {
		printf("can naot load the image ...\n");
		return -1;
	}
	char input_title[] = "input";
	char output_title[] = "sobel demo2";
	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

	GaussianBlur(src, dst, Size(3, 3),0,0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);

	Mat xgrad, ygrad;
	Sobel(gray_src, xgrad, CV_32F, 1, 0);
	Sobel(gray_src, ygrad, CV_32F, 0, 1);
	
	Mat xygrad_1;
	addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad_1, -1);
	imshow("sobel demo1", xygrad_1);
	imwrite("sobel_demo1.jpg", xygrad_1);

//手动实现融合
	convertScaleAbs(xgrad, xgrad);//取绝对值
	convertScaleAbs(ygrad, ygrad);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);
	Mat xygrad_2 = Mat(xgrad.size(), 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_2.at<uchar>(row, col) = saturate_cast<uchar>(xy);
		}
	}
	imshow(output_title, xygrad_2);
	imwrite("sobel_demo2.jpg", xygrad_2);
 
	Mat xgrad_1, ygrad_1;
	Scharr(gray_src, xgrad_1, CV_32F, 1, 0);
	Scharr(gray_src, ygrad_1, CV_32F, 0, 1);
	addWeighted(xgrad_1, 0.5, ygrad_1, 0.5, 0, dst2, -1);
	imshow("scharr_demo", dst2);
	imwrite("scharr_demo.jpg", dst2);



	waitKey(0);
	return 0;
}
}

手动融合后,相比API,效果更佳

实验结果
在这里插入图片描述
手动将X与Y方向图像融合
在这里插入图片描述
addweighted API 融合效果
在这里插入图片描述
scharr算子+addweighted融合
在这里插入图片描述

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐