OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)

一、处理边缘

代码:

#include 
#include 
#include 

using namespace cv;
int main(int argc, char** argv) {
	Mat src, dst;
	src = imread("C:\\Users\\Administrator\\Desktop\\test.png");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char INPUT_WIN[] = "input image";
	char OUTPUT_WIN[] = "Border Demo";
	namedWindow(INPUT_WIN, CV_WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_WIN, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_WIN, src);
	
	int top = (int)(0.05*src.rows);
	int bottom = (int)(0.05*src.rows);
	int left = (int)(0.05*src.cols);
	int right = (int)(0.05*src.cols);
	RNG rng(12345);
	int borderType = BORDER_DEFAULT;

	int c = 0;
	while (true) {
		c = waitKey(500);
		// ESC
		if ((char)c == 27) {
			break;
		}
		if ((char)c == 'r') {
			borderType = BORDER_REPLICATE;
		} else if((char)c == 'w') {
			borderType = BORDER_WRAP;
		} else if((char)c == 'c') {
			borderType = BORDER_CONSTANT;
		}
		Scalar color = Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
		copyMakeBorder(src, dst, top, bottom, left, right, borderType, color);//这儿
		imshow(OUTPUT_WIN, dst);
	}
	waitKey(0);
	return 0;
}

首先,为什么要做边缘处理。我们在做卷积计算时,图像卷积的时候边界像素,不能被卷积操作,原因在于边界像素没有完全跟kernel重叠,所以当3x3滤波时候有1个像素的边缘没有被处理,5x5滤波的时候有2个像素的边缘没有被处理。所以要在图像卷积前加入固定宽度的边缘。

以上代码中主要的几个知识点解释下:

1.copyMakeBorder(src, dst, top, bottom, left, right, borderType, color);

borderType是该边缘的类型

(1)BORDER_DEFAULT

默认的,如下图,观察这个女的肩膀,自己理解

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第1张图片

(2)BORDER_REPLICATE

填充边缘像素用已知的边缘像素值,如下图。

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第2张图片

(3)BORDER_WRAP

用另外一边的像素来补偿填充。

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第3张图片

(4)BORDER_CONSTANT

填充边缘用指定像素值

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第4张图片

二、Sobel算子

代码:

#include 
#include 
#include 

using namespace cv;
int main(int argc, char** argv) {
	Mat src, dst;
	src = imread("C:\\Users\\Administrator\\Desktop\\test.png");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char INPUT_TITLE[] = "input image";
	char OUTPUT_TITLE[] = "sobel-demo";
	namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_TITLE, src);

	Mat gray_src;
	GaussianBlur(src, dst, Size(3, 3), 0, 0);
	cvtColor(dst, gray_src, CV_BGR2GRAY);
	imshow("gray image", gray_src);

	Mat xgrad, ygrad;
	//Scharr(gray_src, xgrad, CV_16S, 1, 0);
	//Scharr(gray_src, ygrad, CV_16S, 0, 1);

	 Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);
	 Sobel(gray_src, ygrad, CV_16S, 0, 1, 3);
	convertScaleAbs(xgrad, xgrad);
	convertScaleAbs(ygrad, ygrad);
	imshow("xgrad", xgrad);
	imshow("ygrad", ygrad);

	Mat xygrad = Mat(xgrad.size(), xgrad.type());
	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(row, col);
			int yg = ygrad.at(row, col);
			int xy = xg + yg;
			xygrad.at(row, col) = saturate_cast(xy);
		}
	}
	//addWeighted(xgrad, 0.5, ygrad, 0.5, 0, xygrad);
	imshow(OUTPUT_TITLE, xygrad);

	waitKey(0);
	return 0;
}

Sobel算子其实就是一个边缘计算的计算方法,如何判断是边缘呢,例如当相邻像素点颜色变化程度突变大,到一个临界值,说明这个是边缘,如下图,这是高中的斜率知识,就是一阶导数

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第5张图片

以上代码中主要的几个知识点解释下:

1.Sobel(gray_src, xgrad, CV_16S, 1, 0, 3);

Sobel算子的主要方法。gray_src是输入图像。xgrad是输出图像。CV_16S是图像深度,有CV_8U、CV_16U、CV_32F、CV_64F。1是x方向几阶导数,就是斜率。0是y方向几阶导数。3是算子kernel,必须是1、3、5、7

2.convertScaleAbs(xgrad, xgrad);

计算图像的绝对像素值,意思就是负数取正。

三、Laplance算子

代码:

#include 
#include 
#include 

using namespace cv;
int main(int argc, char** argv) {
	Mat src, dst;
	src = imread("C:\\Users\\Administrator\\Desktop\\test.png");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char input_title[] = "input image";
	char output_title[] = "Laplaiance Result";
	namedWindow(input_title, CV_WINDOW_AUTOSIZE);
	imshow(input_title, src);

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

	Laplacian(gray_src, edge_image, CV_16S, 3);
	convertScaleAbs(edge_image, edge_image);

	threshold(edge_image, edge_image, 0, 255, THRESH_OTSU | THRESH_BINARY);
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	imshow(output_title, edge_image);

	waitKey(0);
	return 0;
}

与上面啊类似,也是计算边缘的算法,这里是二阶导数,如下图。

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第6张图片

以上代码中主要的几个知识点解释下:

1.Laplacian(gray_src, edge_image, CV_16S, 3);

Laplacian算子的主要方法,3是算子kernel,必须是1、3、5、7。

2.convertScaleAbs(edge_image, edge_image);

计算绝对值。

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第7张图片

四、Canny边缘检测

代码:

#include 
#include 
#include 

using namespace cv;
Mat src, gray_src, dst;
int t1_value = 50;
int max_value = 255;
const char* OUTPUT_TITLE = "Canny Result";
void Canny_Demo(int, void*);
int main(int argc, char** argv) {
	src = imread("C:\\Users\\Administrator\\Desktop\\test.png");
	if (!src.data) {
		printf("could not load image...\n");
		return -1;
	}

	char INPUT_TITLE[] = "input image";
	namedWindow(INPUT_TITLE, CV_WINDOW_AUTOSIZE);
	namedWindow(OUTPUT_TITLE, CV_WINDOW_AUTOSIZE);
	imshow(INPUT_TITLE, src);

	cvtColor(src, gray_src, CV_BGR2GRAY);
	createTrackbar("Threshold Value:", OUTPUT_TITLE, &t1_value, max_value, Canny_Demo);
	Canny_Demo(0, 0);

	waitKey(0);
	return 0;
}

void Canny_Demo(int, void*) {
	Mat edge_output;
	blur(gray_src, gray_src, Size(3, 3), Point(-1, -1), BORDER_DEFAULT);
	Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);//这儿

	//dst.create(src.size(), src.type());
	//src.copyTo(dst, edge_output);
	// (edge_output, edge_output);
	imshow(OUTPUT_TITLE, ~edge_output);
}

输出结果一般都是二值图像。背景是黑色。

以上代码中主要的几个知识点解释下:

1.Canny(gray_src, edge_output, t1_value, t1_value * 2, 3, false);

Canny边缘获取的主要方法。gray_src是输入图像。edge_output是输出图像。t1_value是低阀值,是高阀值的二分之一或者三分之一。t1_value*2是高阀值。3是算子的size。

OpenCV C++开发 第二节:图像处理(八、处理边缘、Sobel算子、Laplance算子、Canny边缘检测)_第8张图片

你可能感兴趣的:(OpenCV,C++)