Opencv基本学习内容 清晰易懂

1、图像读取与显示

#include<opencv2/opencv.hpp>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	Mat src=imread("D:/桌面/my resources/1.png",IMREAD_GRAYSCALE); //读取图片  IMREAD_GRAYSCAL灰度加载

	if (src.empty()) {
		printf("could not load image ...\n");
		return -1;
	}

	namedWindow("输入窗口", WINDOW_FREERATIO);//和第11行代码的名字需要一样 都是输入窗口 先写10行 再写11行
	imshow("输入窗口", src);//展示图片
	waitKey(0); //1000代表停顿1000ms 当为0时代表停顿
	destroyAllWindows();//当执行到这一句 前面的窗口全部消除
	return 0;
}

2、图像色彩空间转换

①cvtcolor()函数

是一个颜色空间转换函数,可以实现RGB颜色向HSV,HSI等颜色空间转换。也可以转换为灰度图。将彩色图像转换为灰度。

cvtColor(Mat src, Mat dst, int code)
src表示来源的矩阵。
dist表示目的地的矩阵。
code表示转换类型的整数代码,例如RGB到灰度
#pragma once

#include<opencv2/opencv.hpp>

using namespace cv;

class QuickDemo {
public:
	void colorSpace_Demo(Mat& image);
};
#include<quickopencv.h>

void QuickDemo::colorSpace_Demo(Mat& image) {
	Mat gray, hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("HSV", hsv);
	imshow("灰度", gray);
	imwrite("D:/hsv.png", hsv); //将图片保存在xxx位置下
	imwrite("D:/gray.png", gray);
}
#include<opencv2/opencv.hpp>
#include<quickopencv.h>
#include<iostream>

using namespace cv;
using namespace std;

int main(int argc, char** argv)
{
	Mat src=imread("D:/桌面/my resources/1.png"); 
	if (src.empty()) {
		printf("could not load image ...\n");
		return -1;
	}

	namedWindow("输入窗口", WINDOW_FREERATIO);
	imshow("输入窗口", src);

	QuickDemo qd;
	qd.colorSpace_Demo(src);

	waitKey(0); //1000代表停顿1000ms 当为0时代表停顿
	destroyAllWindows();//当执行到这一句 前面的窗口全部消除
	return 0;
}

3、图像对象创建与赋值

①Scalar函数

Scalar()函数在OpenCV中是用来设置颜色的。
空白图像的创建: Mat m3 = Mat::zeros(Size(400, 400), CV_8UC3); //8Uc1表示单通道 打印一个数 8×8矩阵 8UC3表示3通道 为8×24 24是列数
还有关于深拷贝浅拷贝的问题

#include<quickopencv.h>

void QuickDemo::mat_creation_demo(Mat& image) {
	Mat m1, m2;
	//用以下两种方式才可以开辟新区,用直接赋值的方式,两者内容都会改变,就相当于指针
	m1 = image.clone();
	image.copyTo(m2);

	//创建空白图像
	//Mat m3 = Mat::ones(Size(8, 8), CV_8UC3); //3是像素点的
	Mat m3 = Mat::zeros(Size(400, 400), CV_8UC3); //8Uc1表示单通道 打印一个数 8×8矩阵 8UC3表示3通道 为8×24 24是列数

	m3 = Scalar(255,0,0); //Scalar()函数在OpenCV中是用来设置颜色的。
	
	//clos是获取宽度 rows是行数,也就是高度 channels是通道数
	std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: " << m3.channels() << std::endl; 
	
	//std::cout << m3 << std::endl;

	//这种方式打印会出现两种图像
	//Mat m4 = m3.clone();
	//m4 = Scalar(0, 255, 255);
	//imshow("图像", m3);
	//imshow("图像4", m4);

	//如果用以下这种方式 只会出现一种方式m3的图像也被修改了
	Mat m4 = m3;
	m4 = Scalar(0, 255, 255);
	imshow("图像", m3);
	imshow("图像4", m4);

}


4、图像像素的读写操作

if (dims == 1) { // 灰度图像
				int pv = *current_row;
				*current_row++ = 255 - pv;
			}

这段代码是对灰度图像进行反转的操作,即将原图中的每个像素值取反(255减去当前像素值),并将结果存储回原图像中。其中,dims变量用于确定图像的通道数,如果为1,即表示图像为灰度图像。

具体解释如下:

  • image:表示输入的图像,类型为Mat
  • at<uchar>(row, col):表示取出image(row, col)位置上的像素值,使用uchar类型进行存储,即单通道8位无符号整数。
  • pv:表示当前像素值。
  • image.at<uchar>(row, col) = 255 - pv:表示将当前像素值取反,并将结果存储回原图像中。

因此,这段代码的作用是对灰度图像进行反转,将原图中每个像素值取反,并将结果存储回原图像

void QuickDemo::pixel_visit_demo(Mat& image) {
	int w = image.cols;
	int h = image.rows;
	int dims = image.channels();
	/*
	for (int row = 0; row < h; row++) {
		for (int col = 0; col < w; col++) {
			if (dims == 1) { // 灰度图像
				int pv = image.at<uchar>(row, col);
				//对灰度进行反转赋值
				image.at<uchar>(row, col) = 255 - pv;
			}
			if (dims == 3) { // 彩色图像
				Vec3b bgr = image.at<Vec3b>(row, col);
				image.at<Vec3b>(row, col)[0] = 255 - bgr[0];
				image.at<Vec3b>(row, col)[1] = 255 - bgr[1];
				image.at<Vec3b>(row, col)[2] = 255 - bgr[2];
			}
		}
	}
	*/

	//使用指针方式
	for (int row = 0; row < h; row++) {
		uchar* current_row = image.ptr<uchar>(row);
		for (int col = 0; col < w; col++) {
			if (dims == 1) { // 灰度图像
				int pv = *current_row;
				*current_row++ = 255 - pv;
			}
			if (dims == 3) { // 彩色图像
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			}
		}
	}
	imshow("像素读写演示", image);
}

5、图像像素的运算操作

①saturate_cast函数

saturate_cast《uchar》(图像): 用于限制像素颜色范围,如果超过255就限定为255,保证区间在0到255;

void QuickDemo::operators_demo(Mat& image) {
	Mat dst;

	//对于像素的运算操作
 /* dst = image + Scalar(50, 50, 50);
	dst = image - Scalar(50, 50, 50);
	dst = image / Scalar(2, 2, 2);*/

	//但是对于乘法运算有专门的方式 	dst = image * Scalar(2, 2, 2)是错误的
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(2, 2, 2);

	//指针方式
	/*
	int w = image.cols;
	int h = image.rows;
	int dims = image.channels();
	for (int row = 0; row < h; row++) {
		for (int col = 0; col < w; col++) {
			Vec3b p1 = image.at<Vec3b>(row, col);
			Vec3b p2 = m.at<Vec3b>(row, col);
			dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
			dst.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
			dst.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
		}
	}
	*/


	multiply(image, m, dst);
	//divide(image, m, dst);
	imshow("加法操作",dst);
}

6、滚动条操作演示

①addWeighted()`函数

addWeighted(src1,alpha,src2,beta,gamma,dst)
  • src1:输入第一个矩阵,用于进行亮度和对比度调整;
  • alpha:用于控制对比度的大小;
  • src2:输入第二个矩阵,用于控制亮度大小;
  • beta:用于控制亮度的大小;
  • gamma:一般为标量0,不添加到加权和上的值;
  • dst:输出的矩阵,用于展示亮度和对比度调整后的图像;

②createTrackbar()函数

createTrackbar() 

第一个参数:滚动条的名称。
第二个参数:滚动条所属的窗口名称。
第三个参数:滚动条的当前值,也就是滚动条的初始位置。
第四个参数:滚动条的最大值。
第五个参数:当滚动条的值发生变化时调用的回调函数,可以是上面定义的 on_lightness() 或 on_contrast() 函数。
第六个参数:传递给回调函数的参数,即指向图像的指针。

//亮度调整函数
static void on_lightness(int b, void* userdata) {
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	addWeighted(image, 1.0, m, 0, b, dst);
	imshow("亮度与对比度调整", dst);
}

//对比度调整函数
static void on_contrast(int b, void* userdata) {
	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	double contrast = b / 100.0;
	addWeighted(image, contrast, m, 0.0, 0, dst);
	imshow("亮度与对比度调整", dst);
}


void QuickDemo::tracking_bar_demo(Mat& image) {
	namedWindow("亮度与对比度调整", WINDOW_AUTOSIZE);
	int lightness = 50;
	int max_value = 100;
	int contrast_value = 100;
	createTrackbar("Value Bar:", "亮度与对比度调整", &lightness, max_value, on_lightness, (void*)(&image));
	createTrackbar("Contrast Bar:", "亮度与对比度调整", &contrast_value, 200, on_contrast, (void*)(&image));
	on_lightness(50, &image);
}


7、键盘响应操作

void QuickDemo::key_demo(Mat& image) {

	Mat dst = Mat::zeros(image.size(), image.type());
	while (true) {
		//c是一个字符串
		int c = waitKey(100);
		if (c == 27) { // 退出 esc键代表21
			break;
		}
		if (c == 49) { // Key #1 代表数字1
			cout << "you enter key # 1 " <<endl;
			cvtColor(image, dst, COLOR_BGR2GRAY);
		}
		if (c == 50) { // Key #2
			cout << "you enter key # 2 " << endl;
			cvtColor(image, dst, COLOR_BGR2HSV);
		}
		if (c == 51) { // Key #3
			cout << "you enter key # 3 " << endl;
			dst = Scalar(50, 50, 50);
			add(image, dst, dst);
		}
		imshow("键盘响应", dst);
	}
}

8、自带颜色表操作

①applyColorMap函数

applyColorMap(InputArray src, OutputArray dst, int colormap)

此函数有三个参数,第一个参数代表输入图像,第二个为输出图像,第三个为色调;

void QuickDemo::color_style_demo(Mat &image) {
	int colormap[] = {
		COLORMAP_AUTUMN,
		COLORMAP_BONE,
		COLORMAP_JET,
		COLORMAP_WINTER,
		COLORMAP_RAINBOW,
		COLORMAP_OCEAN,
		COLORMAP_SUMMER,
		COLORMAP_SPRING,
		COLORMAP_COOL,
		COLORMAP_PINK,
		COLORMAP_HOT,
		COLORMAP_PARULA,
		COLORMAP_MAGMA,
		COLORMAP_INFERNO,
		COLORMAP_PLASMA,
		COLORMAP_VIRIDIS,
		COLORMAP_CIVIDIS,
		COLORMAP_TWILIGHT,
		COLORMAP_TWILIGHT_SHIFTED
	};

	Mat dst;
	int index = 0;
	while (true)
	{
		int c = waitKey(100);
		if (c == 27) { // 退出
			break;
		}
		applyColorMap(image, dst, colormap[index % 19]);
		index++;
		imshow("颜色风格", dst);
	}

}

9、图像像素的逻辑操作

①rectangle函数

rectangle(InputOutputArray img, Rect rec,
                          const Scalar& color, int thickness = 1,
                          int lineType = LINE_8, int shift = 0);

前3个函数为必不可少的,后面的几个随意

  • img:输入图像
  • Rect:矩形的绘制函数
  • Scalar:赋予颜色
  • thickness:矩形的边框粗细。类型为 int,默认值为 1。
  • lineType:矩形的边框线型。类型为 int,默认值为 cv::LINE_8。
  • shift:矩形的坐标点小数位数。类型为 int,默认值为 0。
void QuickDemo::bitwise_demo(Mat& image) {
	//创建空白图像
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0),-1,LINE_8,0);
	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255),-1,LINE_8,0);
	imshow("m1", m1);
	imshow("m2", m2);
	Mat dst;
	//bitwise_and(m1, m2, dst); //与操作
	//bitwise_or(m1, m2, dst); //或操作
	//bitwise_not(image, dst); //非操作
	bitwise_xor(m1,m2,dst); //亦或操作

	imshow("像素位操作", dst);
}

10、通道分离与合并

①mixChannels函数

void mixChannels(const Mat* src, int nsrcs, Mat* dst, int ndsts, const int* fromTo, int npairs);

各个参数的含义如下:

  • src:输入图像数组的指针,即源图像数组,类型为 const Mat*。该数组中包含了所有输入图像,其中 nsrcs 参数指定了输入图像的数量。
  • nsrcs:输入图像数组的大小,即源图像的数量,类型为 int。
  • dst:输出图像数组的指针,即目标图像数组,类型为 Mat*。该数组中包含了所有输出图像,其中 ndsts 参数指定了输出图像的数量。
  • ndsts:输出图像数组的大小,即目标图像的数量,类型为 int。
  • fromTo:通道重排列数组,即指定输入通道和输出通道的对应关系,类型为 const int*。该数组的长度应该是 npairs*2,其中 npairs 参数指定了通道的对数。对于每一对通道重排列,都需要指定两个索引,第一个索引是输入通道的索引,第二个索引是输出通道的索引。
  • npairs:通道重排列的对数,即 fromTo 数组中重排列的通道数,类型为 int。
    总体来说,mixChannels 函数的作用是将一个或多个输入图像的通道按照指定的方式进行混合,并将结果输出到一个或多个输出图像中。通过指定 fromTo 数组来控制通道的重排列

Vector容器的作用
因此,vector《Mat》 mv 在这段代码中的意义是用于存储分离后的通道子图像,方便进行后续的像素统计分析。和split搭配使用。

void QuickDemo::channels_demo(Mat& image) {
	/*
	vector是C++标准库中的一种容器类型,可以存储任意类型的元素,
	包括基本类型、自定义类型和标准库类型等。向量容器是其中的一种,
	它可以自动扩展大小以存储任意数量的元素,并提供了许多方便的成员
	函数来操作这些元素。
*/
	vector<Mat> mv;
	split(image, mv);
	imshow("蓝色", mv[0]);
	imshow("绿色", mv[1]);
	imshow("红色", mv[2]);

	Mat dst;
	
	//如果一个mv为0,则另外两个会颜色合并,如果两个mv为0,则通道会呈现不为0的通道的颜色;
	//mv[0] = 0;
	mv[1] = 0;
	//mv[2] = 0;
	merge(mv, dst);
	imshow("红色", dst);

	//通道颜色的混合
	int from_to[] = { 0,2,1,1,2,0 };
	mixChannels(&image,1, &dst,1,from_to ,3);
	imshow("通道的混合", dst);
}

11、图像色彩空间转换

①inRange函数

void inRange(InputArray src, InputArray lowerb,
                          InputArray upperb, OutputArray dst);

inRange函数是OpenCV中用于根据颜色范围在图像中筛选出特定颜色区域的函数。它可以接收三个参数:输入图像、颜色范围的最小值和最大值,并输出二值化的掩膜图像。

在inRange函数中,第一个参数是需要进行颜色筛选的原始图像。第二个参数是最小颜色值,是一个Scalar类型的对象,其中包含了颜色范围的最小值,通常为HSV色彩空间中的最小值。第三个参数是最大颜色值,也是一个Scalar类型的对象,包含了颜色范围的最大值,通常为HSV色彩空间中的最大值。最后,输出参数是一个二值化的掩膜图像,其中目标区域为白色,非目标区域为黑色。

void QuickDemo::inrange_demo(Mat& image) {
	Mat hsv;
	//从RGB图像转到HSV图像,因为这样会更容易识别
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	inRange(hsv, Scalar(35,43,46), Scalar(77,255,255), mask);

	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);
	/*
	由于掩膜是二值图像,其中白色像素表示目标物体,
	黑色像素表示背景,因此使用"bitwise_not"函数将白色
	像素转换为黑色像素,黑色像素转换为白色像素,
	从而得到背景区域的掩膜。
	*/
	bitwise_not(mask, mask);
	
	imshow("mask", mask);

	/*
	将掩膜应用到输入图像上,将目标区域提取出来并用红色背
	景填充。使用"copyTo"函数将原始图像复制到红色背景图像
	上,但只在掩膜区域内复制*/
	image.copyTo(redback, mask);
	imshow("roi区域提取", redback);
}

在这里插入图片描述


12、图像像素值统计

①minMaxLoc函数

minMaxLoc(mv[i], &min, &max, &minLoc, &maxLoc, Mat()) 
是一个 OpenCV 函数,用于在单通道的图像中找到最小值和最大值及其对应位置。

其中,各个参数的含义如下:

  • mv[i]:要查找最小值和最大值的单通道图像。
  • &min:指向变量 min 的指针,用于存储最小值。
  • &max:指向变量 max 的指针,用于存储最大值。
  • &minLoc:指向变量 minLoc 的指针,用于存储最小值的位置。
  • &maxLoc:指向变量 maxLoc 的指针,用于存储最大值的位置。
  • Mat():可选参数,指定掩码图像,表示只在掩码区域内查找最小值和最大值,如果没有指定掩码图像,则查找整个图像中的最小值和最大值。

此函数的返回值为最小值,也就是参数 min 的值。在这个特定的代码中,minMaxLoc() 函数被用于查找每个通道图像中的最小值和最大值,分别存储在 min 和 max 变量中,并记录它们的位置,存储在 minLoc 和 maxLoc 变量中。这些信息可以用于后续的图像处理和分析,例如对比度调整、直方图均衡化等。

②meanStdDev函数

void meanStdDev(InputArray src, OutputArray mean, OutputArray stddev, InputArray mask=noArray());

其中,各个参数的含义如下:

  • src:输入图像,可以是任何维度、任何通道数的图像。
  • mean:输出参数,用于存储计算得到的均值。
  • stddev:输出参数,用于存储计算得到的标准差。
  • mask:可选参数,指定掩码图像,表示只在掩码区域内计算均值和标准差,如果没有指定掩码图像,则计算整个图像的均值和标准差。

此函数没有返回值,而是把计算得到的均值和标准差分别存储在 mean 和 stddev 参数中。

在这个特定的代码中,meanStdDev() 函数被用于计算输入图像 image 的均值和标准差,并将结果存储在 mean 和 stddev 变量中。这些信息可以用于后续的图像处理和分析,例如对比度调整、二值化、边缘检测等。

void QuickDemo::pixel_statistic_demo(Mat& image) {
	double min, max;
	Point minLoc, maxLoc;
	vector<Mat> mv;
	
	split(image, mv);
	for (int i = 0; i < mv.size(); i++) {
		minMaxLoc(mv[i], &min, &max, &minLoc, &maxLoc);
		std::cout << "No. channels:" << i << " min value:" << min << " max value:" << max << std::endl;
	}

	Mat mean, stddev;
	meanStdDev(image, mean, stddev);
	cout << "means:" << mean << "stddev:" <<stddev<< endl;
}

13、图像几何形状绘制

①circle等绘制函数的内容

void cv::circle(InputOutputArray img, Point center, int radius, const Scalar& color, int thickness = 1, int lineType = LINE_8, int shift = 0)

其中各个参数的含义如下:

  • img:输入/输出图像矩阵。函数将在该图像上绘制圆形。
  • center:圆心的坐标,类型为 Point。在这里,Point(350, 400) 表示圆心的横坐标为 350,纵坐标为 400。
  • radius:圆的半径,类型为 int。在这里,15 表示圆的半径为 15 个像素。
  • color:圆的颜色,类型为 Scalar。在这里,Scalar(255, 0, 0) 表示圆的颜色为蓝
  • Scalar 类型是 OpenCV 中的一个数据类型,用于表示一个包含多个通道的颜色值。在这里,我们使用了一个三通道的 Scalar 对象,表示 RGB 颜色空间中的蓝色。
  • thickness:圆的边框宽度,类型为 int。在这里,2 表示圆的边框宽度为 2 个像素
  • lineType:线条的类型,类型为 int。默认值为 LINE_8,表示 8 连通线。在这里,我们没有指定该参数,因此默认使用 8 连通线。
  • shift:坐标点小数点位数,类型为 int。在这里,0 表示坐标点没有小数位。

综上所述,这行代码的作用是:在 image 图像矩阵上绘制一个以点 (350, 400) 为圆心,半径为 15 个像素的蓝色圆,边框宽度为 2 个像素。

void QuickDemo::drawing_demo(Mat& image) {
	Rect rect; //定义矩形
	rect.x = 100;
	rect.y = 100;
	rect.width = 200;
	rect.height = 100;
	Mat bg = Mat::zeros(image.size(), image.type());
	//矩形的绘制
	rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);
	//圆的绘制
	circle(bg, Point(200, 150), 15, Scalar(255, 0, 0), -1, 8, 0);
	//线的绘制
	line(bg, Point(100, 100), Point(350, 400), Scalar(0, 255, 0), 2, 8, 0);
	//椭圆绘制
	RotatedRect rrt;
	rrt.center = Point(200, 200);
	rrt.size = Size(100, 200);
	rrt.angle = 0.0;
	ellipse(bg, rrt, Scalar(0, 255, 255), 2, 8);
	/*Mat dst;
	addWeighted(image, 0.1, bg, 0.3, 0, dst);*/
	imshow("绘制演示", bg);
}

14、随机数与随机颜色图像绘制

void QuickDemo::random_drawing() {
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	int w = canvas.cols;
	int h = canvas.rows;
	RNG rng(12345);
	while (true)
	{
		int c = waitKey(100);
		if (c == 27) {
			break;
		}
		int x1 = rng.uniform(0, w);
		int y1 = rng.uniform(0, h);
		int x2 = rng.uniform(0, w);
		int y2 = rng.uniform(0, h);
		int b = rng.uniform(0, 255);
		int g = rng.uniform(0, 255);
		int r = rng.uniform(0, 255);
		line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b,g,r), 1, LINE_AA, 0);
		imshow("随机绘制演示", canvas);
	}
}

15、多边形的填充与绘制

①polylines函数

void polylines(InputOutputArray img, InputArrayOfArrays pts,
                            bool isClosed, const Scalar& color,
                            int thickness = 1, int lineType = LINE_8, int shift = 0 );

polylines() 函数是 OpenCV 中用于绘制多边形的函数。它的作用是在给定的图像上绘制一系列连接在一起的线段,形成一个闭合的多边形。以下是该函数中各个参数的意义:

  • img:需要绘制多边形的图像
  • pts:存储多边形各个顶点坐标的向量
  • isClosed:是否闭合多边形
  • color:绘制多边形的颜色
  • thickness:绘制多边形线条的粗细程度
  • lineType:绘制多边形的线条类型
  • shift:坐标点小数点位移
    其中,img 和 pts 是必填参数,isClosed 默认为 false,color 默认为白色,thickness 默认为 1,lineType 默认为 8,shift 默认为 0。调用该函数后,它将在给定的图像上绘制指定的多边形。

②fillPoly函数

fillPoly(InputOutputArray img, InputArrayOfArrays pts,
                           const Scalar& color, int lineType = LINE_8, int shift = 0,
                           Point offset = Point() );

fillPoly() 函数是 OpenCV 中用于填充多边形的函数。它的作用是在给定的图像上填充一个或多个多边形。以下是该函数中各个参数的意义:

  • img:需要填充多边形的图像
  • pts:存储多边形各个顶点坐标的向量
  • color:填充多边形的颜色
  • lineType:绘制多边形的线条类型
  • offset:坐标点偏移量

其中,img 和 pts 是必填参数,color 默认为白色,lineType 默认为 8,offset 默认为 (0,0)。调用该函数后,它将在给定的图像上填。

③drawContours函数(将前两个综合起来用)

void drawContours( InputOutputArray image, InputArrayOfArrays contours,
                              int contourIdx, const Scalar& color,
                              int thickness = 1, int lineType = LINE_8,
                              InputArray hierarchy = noArray(),
                              int maxLevel = INT_MAX, Point offset = Point() );

使用 drawContours() 函数。该函数将一个或多个轮廓绘制在给定的画布上,并且可以选择填充轮廓内部。以下是该函数中各个参数的意义:

  • image: 需要绘制轮廓的图像
  • contours: 存储轮廓点的向量,可以是一个或多个轮廓
  • contourIdx: 轮廓的索引,如果值为 -1,则绘制所有轮廓
  • color: 绘制轮廓的颜色
  • thickness: 绘制轮廓线条的粗细程度,如果值为 -1,则填充轮廓内部
  • lineType: 绘制轮廓的线条类型
  • hierarchy: 轮廓的层级结构

其中,image、contours、contourIdx 和 color 是必填参数,而其他参数是可选的。调用该函数后,它将在画布上绘制指定的轮廓。

void QuickDemo::polyline_drawing_demo() {
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	Point p1(100, 100);
	Point p2(350, 100);
	Point p3(450, 280);
	Point p4(320, 450);
	Point p5(80, 400);

	/*
	在第一行代码中,我们创建了一个空的 vector<Point> 对象
	,这个对象将用于存储我们的点。然后,我们使用 push_back() 
	函数将五个点依次添加到向量中,这些点最终将用于创建一个多边形*/
	vector<Point> pts;
	pts.push_back(p1);
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);
	//填充多边形不可以用-1来进行填充
	//polylines(canvas, pts, true, Scalar(0, 0, 255), 2, LINE_AA, 0);
	//多边形填充函数
	//fillPoly(canvas, pts, Scalar(255, 255, 0), 8, 0);

	vector<vector<Point>> contours;
	contours.push_back(pts);
	//第三个参数为-1则是代表全部,最后一个参数为-1则是填充
	drawContours(canvas, contours,-1,Scalar(255,0,0),-1);
	imshow("多边形绘制", canvas);
}

16、鼠标操作与响应

①setMouseCallback函数

void setMouseCallback(const string& winname, MouseCallback onMouse, void* userdata = 0);

参数的意义如下:

  • winname:指定窗口的名称。
  • onMouse:指定的回调函数。此函数将在鼠标事件发生时被调用。回调函数应该有以下形式:
  • userdata:传递给回调函数的可选用户数据指针,默认为0。
//设置为-1,-1为默认写法
Point sp(-1, -1);
Point ep(-1, -1);
Mat temp;
static void on_draw(int event, int x, int y, int flags, void* userdata) {
	Mat image = *((Mat*)userdata);
	if (event == EVENT_LBUTTONDOWN) {
		sp.x = x;
		sp.y = y;
		std::cout << "start point:" << sp << std::endl;
	}
	else if (event == EVENT_LBUTTONUP) {
		ep.x = x;
		ep.y = y;
		int dx = ep.x - sp.x;
		int dy = ep.y - sp.y;
		if (dx > 0 && dy > 0) {
			Rect box(sp.x, sp.y, dx, dy);
			temp.copyTo(image);
			//绘制出roi区域
			imshow("ROI区域", image(box));
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			imshow("鼠标绘制", image);
			// ready for next drawing
			sp.x = -1;
			sp.y = -1;
		}
	}
	else if (event == EVENT_MOUSEMOVE) {
		if (sp.x > 0 && sp.y > 0) {
			ep.x = x;
			ep.y = y;
			int dx = ep.x - sp.x;
			int dy = ep.y - sp.y;
			if (dx > 0 && dy > 0) {
				Rect box(sp.x, sp.y, dx, dy);
				//把原图重新赋值给image
				temp.copyTo(image);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
			}
		}
	}
}


void QuickDemo::mouse_drawing_demo(Mat& image) {
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
	imshow("鼠标绘制", image);
	//原图保存在这
	temp = image.clone();
}

17、图像像素类型转换与归一化

①什么是归一化?归一化有什么作用?

归一化是一种常见的图像预处理方法,用于将图像的像素值映射到一个特定的范围内,以便更好地进行后续处理和分析。

归一化的作用有以下几个方面:

提高图像质量:通过归一化,可以将图像的动态范围映射到一个固定的范围内,这样可以避免图像中像素值过大或过小的情况,从而提高图像的质量。

方便图像处理:归一化后,图像的像素值范围被限制在一个固定的范围内,可以使后续的图像处理算法更加方便和稳定。

减少数据量:在一些图像处理算法中,像素值的范围可能对算法的性能和效率产生影响。通过归一化,可以将像素值范围缩小,从而减少数据量,提高算法的处理速度和效率。

统一数据格式:在一些场合下,不同的图像数据来源可能有不同的像素值范围和数据格式。通过归一化,可以将不同的数据格式和范围统一为相同的格式和范围,从而方便进行数据的整合和处理。

总之,归一化是一种重要的图像预处理方法,可以提高图像质量,方便图像处理,减少数据量,并统一数据格式。它在计算机视觉、图像处理和机器学习等领域中被广泛应用。

②image.convertTo函数

image.convertTo(dst, CV_32F)是将image转换为CV_32F类型的矩阵,并将结果存储在dst中。这里的CV_32F表示32位浮点数类型,因此转换后的矩阵的每个元素都是浮点数类型。这个过程也称为类型转换或数据类型转换。

转换后的矩阵dst是原始矩阵image的副本,因此原始矩阵image不会改变。

这个过程的目的通常是进行后续处理,例如使用某些OpenCV函数需要输入特定的矩阵类型,或者在图像处理中将像素值转换为浮点数类型进行处理等。

③normalize函数

normalize( InputArray src, InputOutputArray dst, double alpha = 1, double beta = 0,
                             int norm_type = NORM_L2, int dtype = -1, InputArray mask = noArray());

其中,各参数的含义如下:

  • src:输入的数据矩阵,可以是 Mat 或 InputArray 类型的对象。
  • dst:输出的矩阵,可以是 Mat 或 OutputArray 类型的对象,需要与输入矩阵的大小相同。
  • alpha:归一化范围的下限值。
  • beta:归一化范围的上限值。
  • norm_type:归一化的类型,可取的值包括 NORM_INF、NORM_L1、NORM_L2、NORM_MINMAX 等,具体含义可参考 OpenCV 文档。
  • dtype:输出矩阵的数据类型,可选的值包括 CV_8U、CV_16U、CV_32F 等。
  • mask:掩码矩阵,用于指定要归一化的像素点,可选参数。
void QuickDemo::norm_demo(Mat& image) {
	Mat dst;
	cout << image.type() << endl;
	image.convertTo(dst,CV_32F);
	cout << image.type() << endl;
	normalize(image, dst, 1.0, 0, NORM_MINMAX);

	cout << dst.type() << endl;
	imshow("图像归一化", dst);
}

18、图像放缩与插值

①resize函数

resize( InputArray src, OutputArray dst,
                          Size dsize, double fx = 0, double fy = 0,
                          int interpolation = INTER_LINEAR );

其中各个参数的含义如下:

  • src:输入图像,可以是Mat类型的矩阵或者其他支持的数据类型。
  • dst:输出图像,也是Mat类型的矩阵,用于存储调整大小后的图像。
  • dsize:输出图像的大小,可以指定为Size类型的对象,表示输出图像的宽度和高度。当dsize为0时,输出图像的大小将根据fx和fy参数自动计算。
  • fx:输出图像在水平方向上的缩放因子,当dsize为0时,fx将会被用来计算输出图像的宽度。
  • fy:输出图像在垂直方向上的缩放因子,当dsize为0时,fy将会被用来计算输出图像的高度。
  • interpolation:插值方法,用于确定像素值的计算方法,常用的有INTER_NEAREST、INTER_LINEAR、INTER_CUBIC、INTER_AREA等。

注:fx和fy参数只有一个可以为0,当两个参数都为0时,输出图像的大小将与原始图像保持一致。

void QuickDemo::resize_demo(Mat& image) {
	Mat zoomin, zoomout;
	int h = image.rows;
	int w = image.cols;
	//缩小到1/4
	resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);
	imshow("zoomin", zoomin);
	//扩大到4倍
	resize(image, zoomout, Size(w * 2, h * 2), 0, 0, INTER_LINEAR);
	imshow("zoomout", zoomout);
}


19、图像翻转

①flip函数

flip(InputArray src, OutputArray dst, int flipCode);
  • src:输入图像;
  • dst:输出图像;
  • flipCode:翻转参数,0代表上下,1代表左右,-1代表对角线翻转;
void QuickDemo::flip_demo(Mat& image) {
	Mat dst;
	//flip(image, dst, 0); //上下翻转
	//flip(image, dst, 1); //左右翻转
	flip(image, dst, -1); //对角线翻转
	imshow("图像翻转", dst);
}

20、图像旋转

①at方法的使用

Mat::at<T>(int row, int col)

at 是 OpenCV 库中的一个函数,用于访问矩阵(Mat)中的元素。它的语法如下:

其中,T 是表示矩阵中元素的数据类型(例如 double、float、int 等),row 是要访问的元素的行索引,col 是要访问的元素的列索引。at 函数返回指定行列位置的矩阵元素的引用,可以用于读取和修改矩阵中的元素值。

在上面提供的代码中,M.at(0, 0) 和 M.at(0, 1) 分别用于访问旋转矩阵 M 中的第一行第一列和第一行第二列的元素值,返回的是 double 类型的值,用于计算旋转后图像的新宽度和新高度。M.at(0, 2) 和 M.at(1, 2) 则分别用于访问旋转矩阵 M 中的第一行第三列和第二行第三列的元素值,表示平移参数,用于调整旋转后图像的位置。

②getRotationMatrix2D函数

Mat getRotationMatrix2D(Point2f center, double angle, double scale)

该函数接受三个参数:

  • center:旋转的中心点,类型为 Point2f,即二维平面上的点,通常表示为 (x, y)。
  • angle:旋转角度,以度为单位,可以是正值或负值,表示顺时针或逆时针旋转。
  • scale:缩放因子,表示旋转后的图像的缩放比例,可以是任意正实数。

该函数返回一个 cv::Mat 类型的矩阵,即旋转矩阵,可以通过矩阵乘法将其应用到原始图像上,从而实现图像的旋转。

旋转矩阵是一个 2x3 的矩阵,形如:

| cos(theta)  -sin(theta)  tx |
| sin(theta)   cos(theta)  ty |

M的矩阵形式
其中 theta 表示旋转角度,tx 和 ty 表示平移量。cos(theta) 和 sin(theta) 分别表示旋转角度的余弦值和正弦值。

getRotationMatrix2D 函数根据传入的中心点、旋转角度和缩放因子生成一个旋转矩阵,并返回该矩阵。在你提供的代码中,getRotationMatrix2D 函数使用了图像的中心点 (w / 2, h / 2),旋转角度 45 度,和缩放因子 1.0,生成了一个旋转矩阵 M。接下来的代码使用该旋转矩阵 M 对图像进行旋转操作,并将结果保存到 dst 中。

③warpAffine函数

void warpAffine(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags = INTER_LINEAR, int borderMode = BORDER_CONSTANT, const Scalar& borderValue = Scalar())

cv::warpAffine 是 OpenCV 库中的一个函数,用于对图像进行仿射变换(Affine Transformation)。

该函数接受七个参数:

  • src:输入图像,类型为 InputArray,可以是单通道或多通道图像。
  • dst:输出图像,类型为 OutputArray,与输入图像有相同的尺寸和数据类型。
  • M:仿射变换矩阵,类型为 InputArray,可以通过调用 cv::getRotationMatrix2D 函数生成。它是一个 2x3 的矩阵,用于定义图像的仿射变换操作。
  • dsize:输出图像的大小,类型为 Size,表示输出图像的宽度和高度。
  • flags:插值方法,用于确定输出图像中像素的值。默认值为 INTER_LINEAR,表示使用线性插值。
  • borderMode:边界模式,用于处理输出图像中位于边界外的像素。默认值为 BORDER_CONSTANT,表示使用常数填充边界。可以选择其他的边界模式,如 BORDER_REPLICATE、BORDER_REFLECT 等。
  • borderValue:边界值,当 borderMode 参数为 BORDER_CONSTANT 时,用于指定边界填充的常数值。默认值为 Scalar(),表示使用零值填充边界。

cv::warpAffine 函数将输入图像 src 根据传入的仿射变换矩阵 M 进行变换,并将结果保存到输出图像 dst 中。仿射变换可以实现平移、旋转、缩放和剪切等操作,是一种二维几何变换,可以对图像进行各种形式的扭曲。在你提供的代码中,warpAffine 函数使用了生成的旋转矩阵 M 进行图像的旋转操作,并将结果保存到 dst 中。

void QuickDemo::rotate_demo(Mat& image) {
	Mat dst, M;
	int w = image.cols;
	int h = image.rows;
	//M是一个旋转矩阵
	M = getRotationMatrix2D(Point(w / 2, h / 2), 75, 1.0);
	double cos = abs(M.at<double>(0, 0));//M的第0,0个元素就是cos的值
	double sin = abs(M.at<double>(0, 1));//M的第0,1个元素就是sin的值
	int nw = cos * w + sin * h;
	int nh = sin * w + cos * h;
	//M的第一行第三列的数据,和第二行第三列的数据代表偏移量
	M.at<double>(0, 2) += (nw / 2- w / 2);
	M.at<double>(1, 2) += (nh / 2 - h / 2);
	warpAffine(image, dst, M, Size(nw,nh), INTER_LINEAR, 0, Scalar(255, 0, 0));
	imshow("旋转演示", dst);
}

求旋转后图像的新的大小


21、视频文件摄像头的使用

VideoCapture 用于创建操作视频对象;
read用于读取每一帧存入Mat中;

void QuickDemo::video_demo(Mat& image) {
	//创建视频帧对象
	VideoCapture capture("D:/桌面/my resources/1.mp4");//括号中写视频的地址可以读取视频资源
	Mat frame;
	while (true)
	{
		//从 "capture" 对象(即 "VideoCapture" 类型对象)中读
		//取一帧视频,并将该帧存储在名为 "frame" 的 "Mat" 类型对象中。
		capture.read(frame);
		flip(frame, frame, 1);//水平翻转函数
		if (frame.empty())
		{
			break;
		}
		imshow("frame", frame);
		int c = waitKey(50);
		if (c==27)
		{
			break;
		}
	}
	frame.release();
}

22、视频处理与保存

①VideoWriter类

VideoWriter类创建一个视频文件,并初始化一个视频编写器。VideoWriter类提供了一个接口,允许用户将视频帧写入到视频文件中,从而创建一个视频

VideoWriter writer("D:/桌面/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);

这句代码使用OpenCV库中的VideoWriter类来创建一个视频文件,其中各个参数的含义如下:

  • “D:/桌面/test.mp4”:视频文件的路径和名称,这里指定为 D:/桌面 目录下的 test.mp4 文件。
  • capture.get(CAP_PROP_FOURCC):视频编解码器的四字码(FourCC)。四字码是一个标识符,用于标识视频编码格式。CAP_PROP_FOURCC 是一个常量,表示获取当前视频输入设备的四字码。
  • fps:视频的帧率(Frames Per Second),表示每秒显示多少帧图像。这个值可以根据需要自行指定。
  • Size(frame_width, frame_height):视频帧的大小,以像素为单位。frame_width 和 frame_height 分别表示视频帧的宽度和高度。
  • true:可选参数,表示视频编码器是否应该使用压缩。如果设置为 true,则编码器会使用压缩来减小文件大小。如果设置为 false,则编码器会生成一个未压缩的视频文件,这将导致文件较大。
void QuickDemo::video_demo(Mat & image) {
	VideoCapture capture("D:/桌面/my resources/1.mp4");
	int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);
	int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);
	int count = capture.get(CAP_PROP_FRAME_COUNT);
	double fps = capture.get(CAP_PROP_FPS);
	std::cout << "frame width:" << frame_width << std::endl;
	std::cout << "frame height:" << frame_height << std::endl;
	std::cout << "FPS:" << fps << std::endl;
	std::cout << "Number of Frames:" << count << std::endl;
	VideoWriter writer("D:/桌面/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);
	Mat frame;
	while (true) {
		capture.read(frame);
		flip(frame, frame, 1);
		if (frame.empty()) {
			break;
		}
		imshow("frame", frame);
		//colorSpace_Demo(frame);
		writer.write(frame);
		// TODO: do something....
		int c = waitKey(50);
		if (c == 27) { // 退出
			break;
		}
	}

	// release
	capture.release();
	writer.release();
}

23、图像直方图

①calcHist函数

void calcHist(const Mat* images, int nimages, const int* channels, InputArray mask, OutputArray hist, int dims, const int* histSize, const float** ranges, bool uniform = true, bool accumulate = false )

其中各个参数的意义如下:

  • images: 输入图像的指针数组,用来计算多个图像的联合直方图。在这里,我们使用的是单通道图像,因此只需要传入一个指针。
  • nimages: 图像的数量,如果只有一个图像,则为1。
  • channels: 一个整数数组,表示要计算的通道的索引。在这里,我们只需要计算一个通道的直方图,因此我们只需要传递一个包含值0的整数数组。
  • mask: 用于指定要计算直方图的像素区域。如果没有指定,则计算整个图像的直方图。在这里,我们不需要指定掩码,因此传递一个空矩阵(Mat())。
  • hist: 用于存储计算得到的直方图。在这里,我们将会把三个通道的直方图分别存储在三个矩阵中。
  • dims: 直方图的维度数。在这里,我们只需要计算一维直方图,因此设置为1。
  • histSize: 一个整数数组,表示每一维度的直方图条数。在这里,我们只需要计算一个通道的256个灰度级别的直方图,因此传递一个包含值256的整数数组。
  • ranges: 表示每个维度的像素值范围。在这里,我们计算的是灰度直方图,因此传递一个指向大小为2的浮点数数组的指针,表示像素值的范围为0到255。
  • uniform: 如果设置为true,则将直方图归一化到1。
  • accumulate: 如果设置为true,则在计算多张图像的直方图时,不清零输出直方图。

通过调用 calcHist() 函数,我们可以计算出每个通道的直方图数据,然后将其用于绘制直方图。

void QuickDemo::histogram_demo(Mat& image) {
	// 三通道分离
	vector<Mat> bgr_plane;
	split(image, bgr_plane);
	// 定义参数变量
	const int channels[1] = { 0 };
	const int bins[1] = { 256 };
	float hranges[2] = { 0,255 };
	const float* ranges[1] = { hranges };
	Mat b_hist;
	Mat g_hist;
	Mat r_hist;
	// 计算Blue, Green, Red通道的直方图
	calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
	calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
	calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);

	// 显示直方图
	int hist_w = 512;
	int hist_h = 400;
	//cvRound作用:对计算结果进行四舍五入
	int bin_w = cvRound((double)hist_w / bins[0]);
	Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3);
	// 归一化直方图数据
	normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, g_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(r_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	// 绘制直方图曲线
	for (int i = 1; i < bins[0]; i++) {
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(b_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(g_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), 2, 8, 0);
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(r_hist.at<float>(i - 1))),
			Point(bin_w * (i), hist_h - cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), 2, 8, 0);
	}
	// 显示直方图
	namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
	imshow("Histogram Demo", histImage);
}

24、二维直方图

①applyColorMap函数

void applyColorMap(InputArray src, OutputArray dst, int colormap);

将灰度图像转换为彩色图像,使用指定的颜色映射类型。该函数有三个参数,分别是源图像、输出图像和颜色映射类型。

在这段代码中,applyColorMap函数将hist2d_image作为源图像,并将结果存储回hist2d_image,因此原始图像被覆盖。COLORMAP_JET是颜色映射类型,它是OpenCV提供的一种流行的颜色映射类型,它使用蓝色、绿色、黄色和红色的不同强度来表示灰度图像中的不同值,从而使图像更加饱满和易于解释。

void QuickDemo::histogram_2d_demo(Mat& image) {
	// 2D 直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	//二维行列
	int hbins = 30, sbins = 32;
	int hist_bins[] = { hbins, sbins };
	float h_range[] = { 0, 180 };
	float s_range[] = { 0, 256 };
	const float* hs_ranges[] = { h_range, s_range };
	int hs_channels[] = { 0, 1 };
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_ranges, true, false);
	double maxVal = 0;
	minMaxLoc(hs_hist, 0, &maxVal, 0, 0);
	int scale = 10;
	Mat hist2d_image = Mat::zeros(sbins * scale, hbins * scale, CV_8UC3);
	for (int h = 0; h < hbins; h++) {
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hs_hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(hist2d_image, Point(h * scale, s * scale),
				Point((h + 1) * scale - 1, (s + 1) * scale - 1),
				Scalar::all(intensity),
				-1);
		}
	}
	applyColorMap(hist2d_image, hist2d_image, COLORMAP_JET);
	imshow("H-S Histogram", hist2d_image);
	//imwrite("D:/hist_2d.png", hist2d_image);
}

25、直方图均衡化

①equalizeHist函数

equalizeHist( InputArray src, OutputArray dst );

直方图均衡化是一种用于改善图像对比度的技术,其主要作用是使图像的对比度更加均匀,从而使得图像更加清晰、易于分析和处理。

在图像处理中,直方图是描述图像中像素值分布的一种方法。一幅图像的直方图可以帮助我们了解图像中像素值的分布情况,从而对图像进行分析、处理和应用。

而直方图均衡化的作用就是改善图像的对比度,使得图像中的像素值更加均匀分布。通过增加图像中较暗的像素值的亮度,减少较亮的像素值的亮度,直方图均衡化可以使图像中更多的细节变得更加明显。这种处理方法通常能够改善图像的质量,使得更多的细节可以被看清楚,并且能够更好地进行后续的处理。

void QuickDemo::histogram_eq_demo(Mat& image) {
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	imshow("灰度图像", gray);
	Mat dst;
	equalizeHist(gray, dst);
	imshow("直方图均衡化演示", dst);
}

26、图像卷积操作

①blur函数

void blur(InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT);

其中各个参数的含义如下:

  • src:输入图像,即待处理的原始图像。
  • dst:输出图像,即经过滤波处理后的图像。
  • ksize:核的大小,即滤波器的大小,一般为一个正奇数,例如 (3,3)、(5,5) 等。
  • anchor:核的锚点位置,默认为 (-1,-1),表示核的中心位置。
  • borderType:像素扩展方式,用于处理边缘像素。可以是常量 BORDER_CONSTANT、BORDER_REPLICATE、BORDER_REFLECT、BORDER_WRAP、BORDER_REFLECT_101、BORDER_TRANSPARENT 等。

通过调用 blur 函数,可以对图像进行平滑处理,从而去除图像中的噪声,并使图像更加平滑和连续。其中核的大小和锚点位置可以根据具体应用场景进行调整。

②卷积操作

卷积操作详解

void QuickDemo::blur_demo(Mat& image) {
	Mat dst;
	blur(image, dst, Size(3, 3), Point(-1, -1));
	imshow("图像模糊", dst);
}


27、高斯模糊

①GaussianBlur函数

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
                                double sigmaX, double sigmaY = 0,
                                int borderType = BORDER_DEFAULT );

cv2.GaussianBlur() 函数是 OpenCV 库中的一个图像处理函数,用于对输入图像进行高斯模糊(Gaussian Blur)操作,也称为高斯滤波。下面是函数的详细参数解释:

  • src:输入图像,可以是单通道(灰度图像)或多通道(彩色图像)。数据类型为
  • InputArray,可以传递一个表示图像的 Mat 对象或者其他支持的输入数组。
  • dst:输出图像,用于存储高斯模糊的结果。数据类型为 OutputArray,可以传递一个 Mat 对象或者其他支持的输出数组。输出图像的尺寸和类型会自动根据输入图像的尺寸和类型确定。
  • ksize:高斯核的尺寸,用于控制高斯模糊的程度。ksize 是一个 Size 类型的参数,可以通过指定 Size(width, height) 来设置高斯核的宽度和高度。ksize.width 和 ksize.height 必须为正奇数,通常在 x 方向和 y 方向上设置相同的值。例如,设置为 Size(5, 5) 表示在 x 方向和 y 方向上都使用 5x5 的高斯核。
  • sigmaX:X 方向上的高斯核标准差,用于控制高斯模糊的程度。sigmaX 是一个 double 类型的参数,表示 X 方向上的标准差。如果设置为 0,则根据 ksize 自动计算 sigmaX 的值。当 sigmaX 越大时,模糊效果越明显。
  • sigmaY:Y 方向上的高斯核标准差,用于控制高斯模糊的程度。sigmaY 是一个 double 类型的参数,表示 Y 方向上的标准差。如果不指定,默认值为 0,表示与 sigmaX 相同。通常情况下,只需指定 sigmaX,而将 sigmaY 设置为 0。
  • borderType:边界处理方式,用于处理图像边缘的情况。borderType 是一个 int 类型的参数,可以设置以下几种边界处理方式:
    cv2.BORDER_DEFAULT:使用默认的边界处理方式,通常为零边界扩展。
    cv2.BORDER_CONSTANT:使用常数值填充边界,需要指定 borderValue 参数。
    cv2.BORDER_REPLICATE:使用边界像素的值复制边界。
    cv2.BORDER_WRAP:使用包装模式复制边界。
    cv2.BORDER_REFLECT:使用镜像模式复制边界。
    cv2.BORDER_REFLECT_101:使用镜像模式复制边界,但边界像素的复制方式不同。
    cv2.BORDER_ISOLATED:不做任何边界处理。

这个函数通过应用高斯核对输入图像进行卷积操作,从而实现图像的模糊效果。高斯模糊是一种常用的图像处理技术,可以用于去噪、平滑图像、模糊边缘等应用。通过调整 ksize、sigmaX 和 sigmaY 参数的值,可以控制高斯模糊的效果。

void QuickDemo::gussian_blur_demo(Mat& image) {
	Mat dst;
	GaussianBlur(image, dst, Size(5, 5), 15);
	imshow("高斯模糊", dst);
}

28、高斯双边模糊

高斯双边模糊(Gaussian Bilateral Blur)是一种图像处理技术,它是高斯滤波和双边滤波的结合体,用于对图像进行平滑处理,同时保留图像中的边缘信息。

在传统的高斯滤波中,图像中的每个像素都被处理成与其周围像素的平均值相等的像素。这种处理方式可以去除噪声,但同时也会破坏图像中的边缘信息,导致图像看起来模糊不清。

而在双边滤波中,像素值的平滑处理是在两个方向上进行的,即颜色空间和空间距离。在双边滤波中,像素之间的相似度由像素值的相似度和它们之间的距离决定。这意味着相邻像素之间的差异较大时,它们的平均值不会对图像产生影响,从而保留了边缘信息。

高斯双边模糊结合了这两种方法,使用高斯函数和双边函数进行图像的平滑处理。它通过加权处理的方式对邻域内的像素进行平滑,并根据像素之间的距离和像素值的相似度进行加权,从而保留了边缘信息,同时去除了噪声。

高斯双边模糊广泛应用于图像处理中,特别是在计算机视觉和图形学中。它可以用于去除图像中的噪声、平滑图像、增强图像细节、图像分割等。需要注意的是,在实际使用时需要根据具体应用场景和需要进行调整,以达到最佳的效果。

①bilateralFilter函数

bilateralFilter( InputArray src, OutputArray dst, int d,
                                   double sigmaColor, double sigmaSpace,
                                   int borderType = BORDER_DEFAULT );

其中各个参数的含义如下:

  • src:输入图像,可以是单通道或多通道图像,数据类型可以为 CV_8U、CV_16U、CV_32F 等。
  • dst:输出图像,与输入图像大小和类型相同。
  • d:邻域直径,用于控制像素距离的范围。通常使用 5、7、9 或 11。
  • sigmaColor:颜色空间标准差,用于控制像素值的相似性。较大的值表示更广泛的颜色范围。
  • sigmaSpace:空间域标准差,用于控制像素距离的相似性。较大的值表示更广泛的距离范围。
  • borderType:边界填充方式,用于处理图像边界。默认值为 BORDER_DEFAULT,表示使用默认方式进行边界填充。

bilateralFilter() 函数利用高斯函数来对图像进行平滑处理,并在此基础上加入双边滤波的处理,从而保留图像的边缘信息。其中,高斯函数的参数由 sigmaColor 和 sigmaSpace 控制,双边滤波的参数由 d 控制。在使用该函数时,需要根据具体应用场景来调整这些参数,以达到最佳的效果。

//类似于美艳的磨皮
void QuickDemo::bifliter_demo(Mat& image) {
	Mat dst;
	bilateralFilter(image, dst, 0, 100, 10);
	imshow("高斯双边模糊", dst);
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值