OpenCV C++基本操作入门学习

VS2022,OpenCV4.8.0

OpenCV下载地址:

Releases - OpenCV

用于个人学习记录

学习于B站up主OpenCV学堂

目录

VS2022,OpenCV4.8.0

1.VS环境配置

1.1配置包含目录

1.2配置库目录

1.3配置链接器

1.4配置环境变量

1.5练习使用的图像​编辑

2.图像的读取与显示

2.1加载并显示一张图片

2.2窗口自由调整

2.3图像的读取方式

  加载图像的灰度图

3.图像色彩空间转换

3.1色彩转化

3.2保存图像

3.3提取指定色彩范围区域inrange

4.图像对象Mat

4.1图像和矩阵的存储:

4.2多通道和深度:

4.3构造和初始化:

4.4数据访问:

5.图像像素的读写操作

6.图像的算术操作

7.TrackBar滚动条操作

8.键盘响应

9.颜色表操作

10.图像像素逻辑操作

11.通道分离与合

​编辑

混合图像

12.像素值统计

13.几何形状绘制

14.随机数与随机颜色

15.多边形填充与绘制

16.鼠标操作与响应

17.图像像素类型转化与归一化

18.图像缩放与插值

19.图像翻转

20.图像旋转

21.视频文件/摄像头使用

22.视频处理与保存

23.图像直方图

24.二维直方图

25.直方图均衡化

原理:

步骤:

26.图像卷积操作

原理:

步骤:

27.高斯模糊

高斯模糊的原理:

高斯模糊的步骤:

28.高斯双边模糊

29.实时人脸检测


1.VS环境配置

创建C++空项目,配置OpenCV库

1.1配置包含目录

1.2配置库目录

1.3配置链接器

附加依赖项

在Release下就选择 opencv_world480.lib

在Debug下就选择opencv_world480d.lib

两个不能同时添加

1.4配置环境变量

1.5练习使用的图像

2.图像的读取与显示

2.1加载并显示一张图片

Mat是矩阵,是OpenCV中的基本数据结构,用于存储图像数据,是一个多维数组,可以是一维、二维、三维等,用于存储图像的像素值,图像的宽、高、通道数等信息

#include <opencv2/opencv.hpp>

int main(int argc, char** argv) {

	cv::Mat img = cv::imread("C:/Resources/image/tifa_1.jpg");	// 读取图像
	if (img.empty())
	{
		std::cout << "Could not open or find the image" << std::endl;
		return -1;
	}
	cv::imshow("Image", img);					// 显示图像,窗口名为"Image"
	cv::waitKey(0);								// 等待按键,0表示无限等待
	return 0;
}

2.2窗口自由调整

上面图片受限屏幕大小显示不完全

通过函数 namedWindow 来调整,让窗口大小可以自由调整

#include <opencv2/opencv.hpp>

int main(int argc, char** argv) {

	cv::Mat img = cv::imread("C:/Resources/image/tifa_1.jpg");	// 读取图像
	if (img.empty())
	{
		std::cout << "Could not open or find the image" << std::endl;
		return -1;
	}
	cv::namedWindow("Image", cv::WINDOW_FREERATIO);	// 创建一个窗口,窗口名为"Image",窗口属性为自由比例
	cv::imshow("Image", img);						// 显示图像,显示在"Image"窗口上
	cv::waitKey(0);									// 等待按键,0表示无限等待。参数为等待时间,单位为ms
	cv::destroyAllWindows();						// 销毁所有窗口
	return 0;
}

2.3图像的读取方式

    图像的读取方式
    IMREAD_UNCHANGED:读取原图像,包括alpha通道
    IMREAD_GRAYSCALE:以灰度图像读取
    IMREAD_COLOR:以彩色图像读取
    IMREAD_ANYDEPTH:以原图像深度读取
    IMREAD_ANYCOLOR:以原图像颜色格式读取
    IMREAD_LOAD_GDAL:使用GDAL读取图像
    IMREAD_REDUCED_GRAYSCALE_2:以1/2的灰度图像读取
    IMREAD_REDUCED_COLOR_2:以1/2的彩色图像读取
    IMREAD_REDUCED_GRAYSCALE_4:以1/4的灰度图像读取

  加载图像的灰度图

	cv::Mat img = cv::imread("C:/Resources/image/tifa_1.jpg",cv::IMREAD_GRAYSCALE);	
// 读取图像,参数为图像路径和读取方式

3.图像色彩空间转换

 创建一个TestDemo来管理实现后续的功能

3.1色彩转化

#pragma once
#include<opencv2/opencv.hpp>

using namespace cv;

class TestDemo
{
public:
	TestDemo();
	~TestDemo();
	void colorSpace_demo(Mat& image);	// 颜色空间转换,传入图像引用
};
#include "TestDemo.h"

TestDemo::TestDemo()
{
}

TestDemo::~TestDemo()
{
}

void TestDemo::colorSpace_demo(Mat& image)
{
	cv::Mat gray, hsv, ycrcb;  // 定义三个 Mat 类对象

	//创建三个窗口,窗口名分别为"Gray"、"HSV"、"YCrCb",窗口属性为自由比例
	cv::namedWindow("Gray", cv::WINDOW_FREERATIO);
	cv::namedWindow("HSV", cv::WINDOW_FREERATIO);
	cv::namedWindow("YCrCb", cv::WINDOW_FREERATIO);

	//转换图像颜色空间
	cv::cvtColor(image, gray, cv::COLOR_BGR2GRAY);		// 将图像转换为灰度图
	cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);		// 将图像转换为 HSV 图
	cv::cvtColor(image, ycrcb, cv::COLOR_BGR2YCrCb);	// 将图像转换为 YCrCb 图

	// 显示转换后的图像
	imshow("Gray", gray);
	imshow("HSV", hsv);
	imshow("YCrCb", ycrcb);

	// 保存转换后的图像
	cv::imwrite("C:/Resources/image/gray.jpg", gray);
	cv::imwrite("C:/Resources/image/hsv.jpg", hsv);
	cv::imwrite("C:/Resources/image/ycrcb.jpg", ycrcb);

}

#include <iostream>
#include <opencv2/opencv.hpp>
#include "TestDemo.h"

int main(int argc, char** argv) {

	cv::Mat img = cv::imread("C:/Resources/image/tifa_1.jpg");	// 读取图像
	if (img.empty())
	{
		std::cout << "Could not open or find the image" << std::endl;
		return -1;
	}
	cv::namedWindow("Image", cv::WINDOW_FREERATIO);	// 创建一个窗口,窗口名为"Image",窗口属性为自由比例
	cv::imshow("Image", img);						// 显示图像,显示在"Image"窗口上

	TestDemo testDemo;								// 创建一个 TestDemo 类对象
	testDemo.colorSpace_demo(img);					// 调用 TestDemo 类的 colorSpace_demo 函数

	cv::waitKey(0);									// 等待按键,0表示无限等待。参数为等待时间,单位为ms
	cv::destroyAllWindows();						// 销毁所有窗口
	return 0;
}

    gray是灰度图,hsv是HSV图,YCrCb是YUV的变种

    g 0-255, b 0-255, r 0-255, 分别表示灰度、蓝色、绿色、红色
    H 0-180 S 0-255 V 0-255, 分别表示色调、饱和度、亮度
    Y 0-255 Cr 0-255 Cb 0-255, 分别表示亮度、红色色度、蓝色色度

    YCrCb是YUV的变种,YUV是彩色视频信号的编码方式,Y表示亮度,U和V表示色度

3.2保存图像

	// 保存转换后的图像
	cv::imwrite("C:/Resources/image/gray.jpg", gray);
	cv::imwrite("C:/Resources/image/hsv.jpg", hsv);
	cv::imwrite("C:/Resources/image/ycrcb.jpg", ycrcb);

	//imwrite参数为保存路径,保存图像

 

3.3提取指定色彩范围区域inrange

void TestDemo::inrange_colorSpace_demo(Mat& image)
{
	cv::Mat hsv;
	cv::cvtColor(image, hsv, cv::COLOR_BGR2HSV);		// 将图像转换为 HSV 图
	namedWindow("hsv", WINDOW_FREERATIO);
	imshow("hsv", hsv);

	cv::Mat mask;
	//提取偏红色区域
	inRange(hsv, cv::Scalar(0, 43, 46), cv::Scalar(10, 255, 255), mask);
	// 提取指定色彩范围的区域,参数为输入图像、颜色下限、颜色上限、输出图像


	cv::namedWindow("mask", cv::WINDOW_FREERATIO);
	cv::imshow("mask", mask);
}

4.图像对象Mat

在 OpenCV 中,cv::Mat 是一个核心数据结构,用于表示图像和矩阵。Mat 是 "Matrix" 的缩写。它是一个多维矩阵类,用于存储图像像素值或任何其他多维数值数据。

​​​​

4.1图像和矩阵的存储:

cv::Mat 可以用于存储图像的像素值,也可以用于存储任何数值数据的多维矩阵。图像的每个像素通常由一个或多个数值表示,例如灰度图像中的一个数值表示灰度级别,而彩色图像中的一个像素可能由三个数值表示(红、绿、蓝通道)。

4.2多通道和深度:

cv::Mat 可以是单通道或多通道的,也可以具有不同的数据深度。通道数表示数据的维度,而深度表示每个通道中数值的类型(例如,8位无符号整数、32位浮点数等)。

4.3构造和初始化:

cv::Mat 可以通过不同的构造函数进行初始化,可以通过加载图像文件、从其他数据结构复制数据、手动分配内存等方式创建。

4.4数据访问:

通过 cv::Mat 提供的方法访问和修改数据,例如使用 (i, j) 访问像素值,使用 at 方法,或者直接访问 data 指针。

void TestDemo::mat_demo()
{
	Mat m1 = Mat::zeros(3, 3, CV_8UC3);		// 创建一个 3x3 的 3 通道图像,像素值为 0
	//输出行数、列数、通道数
	std::cout << "m1:\n" << m1 << std::endl;
	std::cout << "m1.rows: " << m1.rows << std::endl;
	std::cout << "m1.cols: " << m1.cols << std::endl;
	std::cout << "m1.channels: " << m1.channels() << std::endl;

}

用Mat创建一个底色为白色图像,通道为RGB

	//通过scalar创建一个 255x255 的 3 通道图像,像素值为 255
	Mat m3 = Mat(255, 255, CV_8UC3, Scalar(255, 255, 255));
	std::cout << "m3:\n" << m3 << std::endl;
	imshow("m3", m3);
	cv::waitKey(0);
	cv::destroyAllWindows();

5.图像像素的读写操作

void TestDemo::pixel_read_write(Mat& image)
{
	int width = image.cols;		// 获取图像宽度
	int height = image.rows;	// 获取图像高度
	int channels = image.channels();	// 获取图像通道数

	//for (int row = 0; row < height; row++)
	//{
	//	for (int col = 0; col < width; col++)
	//	{
	//		if (channels == 1)	//单通道,图像为灰度
	//		{
	//			int pv = image.at<uchar>(row, col);	// 获取像素值,at<uchar>表示获取灰度图像的像素值,取值范围为0-255
	//			image.at<uchar>(row, col) = 255 - pv;	// 修改像素值,取反
	//		}
	//		if (channels == 3) //三通道图像,彩色图像
	//		{
	//			Vec3b pv_bgr = image.at<Vec3b>(row, col);	// 获取像素值,at<Vec3b>表示获取彩色图像的像素值,bgr通道
	//			image.at<Vec3b>(row, col)[0] = 255 - pv_bgr[0];	// 修改像素值,取反,Vec3b[0]表示B通道
	//			image.at<Vec3b>(row, col)[1] = 255 - pv_bgr[1];	// 修改像素值,取反,G通道
	//			image.at<Vec3b>(row, col)[2] = 255 - pv_bgr[2];	// 修改像素值,取反,R通道
	//		}

	//	}
	//}

	//通过指针访问像素
	//指针访问像素
	for (int row = 0; row < height; row++)
	{
		uchar* data = image.ptr<uchar>(row);	// 获取图像第 row 行的指针
		for (int col = 0; col < width; col++)
		{
			if (channels == 1)	//单通道,图像为灰度
			{
				*data++ = 255 - *data;	// 修改像素值,取反
			}
			if (channels == 3) //三通道图像,彩色图像
			{
				*data++ = 255 - *data;	// 修改像素值,取反,B通道
				*data++ = 255 - *data;	// 修改像素值,取反,G通道
				*data++ = 255 - *data;	// 修改像素值,取反,R通道
			}
		}
	}


	namedWindow("pixel_read_write", WINDOW_FREERATIO);
	imshow("pixel_read_write", image);


}

6.图像的算术操作

图像加减法操作

void TestDemo::arithmetic_demo(Mat& image)
{
	Mat m1;
	Mat m2;
	m1 = image - Scalar(100, 100, 100);	// 图像减法
	m2 = image + Scalar(100, 100, 100);	// 图像加法

	namedWindow("arithmetic_demo_m1", WINDOW_FREERATIO);
	imshow("arithmetic_demo_m1", m1);
	namedWindow("arithmetic_demo_m2", WINDOW_FREERATIO);
	imshow("arithmetic_demo_m2", m2);
}

当进行像素值操作后,有些值超过了255(对于8位图像,像素值的范围是0到255)时,可以选择进行饱和操作(saturate),将超过范围的值强制截断到合法范围内。OpenCV 中的 cv::saturate_cast 函数可以完成这个任务

   // 进行一些操作,可能导致像素值超过255
    img = img * 2;

    // 将图像像素值饱和到0到255的范围
    cv::Mat saturated_img;
    cv::saturate_cast<uchar>(img, saturated_img);

    // 显示原图和处理后的图像
    cv::imshow("Original Image", img);
    cv::imshow("Saturated Image", saturated_img);
    cv::waitKey(0);

7.TrackBar滚动条操作

void TestDemo::create_trackbar_demo(cv::Mat& image)
{
	cv::namedWindow("create_trackbar_demo 亮度调整", cv::WINDOW_FREERATIO);
	int max_val = 100;
	int lightness = 40;
	cv::createTrackbar("light adjustment", "create_trackbar_demo 亮度调整", &lightness, max_val, on_trackBar_change, (void*)(&image));
	on_trackBar_change(lightness, (void*)(&image));
}

void TestDemo::on_trackBar_change(int pos, void* userdata)
{
	Mat image = *(Mat*)userdata;
	Mat dst = Mat::zeros(image.size(), image.type());
	image.convertTo(dst, -1, 1, pos - 50);
	imshow("create_trackbar_demo 亮度调整", dst);

}

8.键盘响应


void TestDemo::keyboard_demo(Mat& image)
{
	namedWindow("keyboard_demo 键盘响应", WINDOW_FREERATIO);
	imshow("keyboard_demo 键盘响应", image);
	while (1)
	{
		int key = waitKey(0);	// 等待按键,0表示无限等待。参数为等待时间,单位为ms
		if (key == 27)	// 按下 ESC 键
		{
			break;
		}
		if (key == 's')	// 按下 s 键
		{
			imwrite(image_path + "/keyboard_demo.jpg", image);	// 保存图像
			std::cout << "image saved" << std::endl;
		}
		if (key == '0')	//恢复原始图像
		{
			imshow("keyboard_demo 键盘响应", image);
		}
		if (key == '1') //将当前图像转换为灰度图
		{
			Mat gray;
			cvtColor(image, gray, COLOR_BGR2GRAY);
			imshow("keyboard_demo 键盘响应", gray);
		}
		if (key == '2') //将当前图像转换为HSV图
		{
			Mat hsv;
			cvtColor(image, hsv, COLOR_BGR2HSV);
			imshow("keyboard_demo 键盘响应", hsv);
		}
	}
}

9.颜色表操作

void TestDemo::colorMap_demo(Mat& image)
{
	Mat gray;
	int colorMap[] = {
	COLORMAP_AUTUMN, COLORMAP_BONE,
	COLORMAP_JET, COLORMAP_WINTER,
	COLORMAP_RAINBOW, COLORMAP_OCEAN,
	COLORMAP_SUMMER, COLORMAP_SPRING,
	COLORMAP_COOL, COLORMAP_HSV,
	COLORMAP_PINK, COLORMAP_HOT
	};

	Mat dst;
	int index = 0;
	while (true)
	{
		int c = waitKey(2000);
		if ((char)c == '0')
		{
			break;
		}
		applyColorMap(image, dst, colorMap[index % 19]);
		index++;
		namedWindow("colorMap_demo", WINDOW_FREERATIO);
		imshow("colorMap_demo", dst);
	}
}

10.图像像素逻辑操作

画两个矩形进行位操作

void TestDemo::bitwise_demo(Mat& image1, Mat& image2)
{
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);

	//创建矩形
	//线宽-1表示填充,线宽>0表示边框宽度
	rectangle(m1, Rect(100, 100, 80, 80), Scalar(255, 255, 0), -1, LINE_8, 0);
	// 矩形填充,颜色为黄色,线宽为-1,表示填充,线型为8连通,矩形左上角坐标为(100,100),宽高为80

	rectangle(m2, Rect(150, 150, 80, 80), Scalar(0, 255, 255), -1, LINE_8, 0);
	// 矩形填充,颜色为青色,线宽为-1,表示填充,线型为8连通,矩形左上角坐标为(150,150),宽高为80

	imshow("m1", m1);
	imshow("m2", m2);

	Mat dst_and, dst_or, dst_not, dst_xor;
	bitwise_and(m1, m2, dst_and);	// 与操作
	bitwise_or(m1, m2, dst_or);		// 或操作
	bitwise_not(m1, dst_not);		// 非操作
	bitwise_xor(m1, m2, dst_xor);	// 异或操作

	imshow("dst_and", dst_and);
	imshow("dst_or", dst_or);
	imshow("dst_not", dst_not);
	imshow("dst_xor", dst_xor);

}

11.通道分离与合

void TestDemo::channel_demo(Mat& image)
{
	Mat bgr[3];
	split(image, bgr);	// 通道分离
	namedWindow("B", WINDOW_FREERATIO);
	namedWindow("G", WINDOW_FREERATIO);
	namedWindow("R", WINDOW_FREERATIO);
	imshow("B", bgr[0]);
	imshow("G", bgr[1]);
	imshow("R", bgr[2]);

	Mat dst;
	bgr[1] = 0;			// 将 G 通道置为 0
	bgr[2] = 0;			// 将 R 通道置为 0
	merge(bgr, 3, dst);	// 通道合并
	namedWindow("channel_demo", WINDOW_FREERATIO);
	imshow("channel_demo", dst);
}

混合图像

	//混合图像
	Mat src1 = image;
	Mat src2 = dst;
	Mat dst2;
	addWeighted(src1, 0.5, src2, 0.5, 0, dst2);	// 图像混合
	namedWindow("channel_demo2", WINDOW_FREERATIO);
	imshow("channel_demo2", dst2);

12.像素值统计

void TestDemo::pixel_statistics(Mat& image)
{
	double minVal, maxVal;
	Point minLoc, maxLoc;
	std::vector<Mat> mv;
	split(image, mv);	// 通道分离

	for (int i = 0; i < mv.size(); i++)
	{
		minMaxLoc(mv[i], &minVal, &maxVal, &minLoc, &maxLoc);	// 获取最大最小值
		std::cout << "channel " << i << " minVal: " << minVal << " maxVal: " << maxVal << std::endl;
	}

	Mat mean, stddev;
	meanStdDev(image, mean, stddev);	// 获取均值和标准差
	std::cout << "mean: " << mean << std::endl << "stddev: " << stddev << std::endl;
}

13.几何形状绘制


void TestDemo::draw_demo()
{
	//创建一个白色底板的图像
	Mat image = Mat::zeros(Size(512, 512), CV_8UC3);
	image = Scalar(255, 255, 255);

	//绘制直线
	line(image, Point(100, 100), Point(200, 200), Scalar(0, 0, 255), 2, LINE_8, 0);
	// 直线绘制,颜色为红色,线宽为2,线型为8连通,起点坐标为(100,100),终点坐标为(200,200)

	//绘制矩形
	rectangle(image, Rect(200, 200, 100, 100), Scalar(0, 255, 0), 2, LINE_8, 0);
	// 矩形绘制,颜色为绿色,线宽为2,线型为8连通,矩形左上角坐标为(200,200),宽高为100

	//绘制圆形
	circle(image, Point(300, 300), 50, Scalar(255, 0, 0), 2, LINE_8, 0);
	// 圆形绘制,颜色为蓝色,线宽为2,线型为8连通,圆心坐标为(300,300),半径为50

	//绘制椭圆
	ellipse(image, Point(400, 400), Size(100, 50), 0, 0, 360, Scalar(255, 255, 0), 2, LINE_8, 0);
	// 椭圆绘制,颜色为黄色,线宽为2,线型为8连通,椭圆中心坐标为(400,400),长轴宽度为100,短轴宽度为50

	//绘制多边形
	std::vector<Point> points;
	points.push_back(Point(100, 400));
	points.push_back(Point(200, 300));
	points.push_back(Point(300, 400));
	points.push_back(Point(400, 300));
	points.push_back(Point(500, 400));
	const Point* ppt[1] = { points.data() };
	int npt[] = { points.size() };
	fillPoly(image, ppt, npt, 1, Scalar(0, 255, 255), LINE_8, 0);

	//显示图像
	namedWindow("draw_demo", WINDOW_FREERATIO);
	imshow("draw_demo", image);
}

在图像上绘制

void TestDemo::draw_demo(Mat& image)
{
	//在图像的人脸上绘制矩形
	Mat img = image.clone();
	rectangle(img, Rect(380, 400, 700, 700), Scalar(0, 255, 0), 3, 0, 0);

	//显示图像
	namedWindow("draw_demo", WINDOW_FREERATIO);
	imshow("draw_demo", img);

	//保存图像
	imwrite(image_path + "/draw_demo.jpg", img);
}

14.随机数与随机颜色


void TestDemo::draw_demo_random_color(Mat& image)
{//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);

	//绘制随机颜色的直线
	RNG rng(12345);
	for (int i = 0; i < 100; i++)
	{
		Point pt1, pt2;
		pt1.x = rng.uniform(0, 512);
		pt1.y = rng.uniform(0, 512);
		pt2.x = rng.uniform(0, 512);
		pt2.y = rng.uniform(0, 512);
		line(img, pt1, pt2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), 2, LINE_8, 0);
	}

	//显示图像
	namedWindow("draw_demo_random_color", WINDOW_FREERATIO);
	imshow("draw_demo_random_color", img);

	//保存图像
	imwrite(image_path + "/draw_demo_random_color.jpg", img);
}

15.多边形填充与绘制


void TestDemo::draw_polyline()
{
	//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);

	//绘制多边形
	std::vector<Point> points;
	points.push_back(Point(100, 400));
	points.push_back(Point(200, 300));
	points.push_back(Point(300, 400));
	points.push_back(Point(400, 300));
	points.push_back(Point(500, 400));
	const Point* ppt[1] = { points.data() };
	int npt[] = { points.size() };
	polylines(img, ppt, npt, 1, true, Scalar(0, 255, 255), 2, LINE_8, 0);

	//显示图像
	namedWindow("draw_polyline", WINDOW_FREERATIO);
	imshow("draw_polyline", img);

}

16.鼠标操作与响应

void TestDemo::mouse_demo(Mat& image)
{
	//检测鼠标所在的位置,在图像右下角显示鼠标所在的位置,以及像素值
	namedWindow("mouse_demo", WINDOW_FREERATIO);
	imshow("mouse_demo", image);
	setMouseCallback("mouse_demo", on_mouse, (void*)(&image));

}

void TestDemo::on_mouse(int event, int x, int y, int flags, void* data)
{
	Mat image = *(Mat*)data;
	std::cout << "x: " << x << " y: " << y << std::endl;
	if (event == EVENT_LBUTTONDOWN)
	{
		std::cout << "Left button of the mouse is clicked - position (" << x << ", " << y << ")" << std::endl;
	}
	if (event == EVENT_RBUTTONDOWN)
	{
		std::cout << "Right button of the mouse is clicked - position (" << x << ", " << y << ")" << std::endl;
	}
}

17.图像像素类型转化与归一化

void TestDemo::pixel_type_conversion(Mat& image)
{
	namedWindow("pixel_type_conversion", WINDOW_FREERATIO);
	namedWindow("pixel_type_conversion_normalize", WINDOW_FREERATIO);
	//图像像素类型转化与归一化
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);	// 将图像转换为灰度图
	imshow("pixel_type_conversion", gray);

	//像素归一化
	Mat dst;
	normalize(gray, dst, 0, 255, NORM_MINMAX, CV_8UC1);
	imshow("pixel_type_conversion_normalize", dst);
}

18.图像缩放与插值

void TestDemo::resize_demo(Mat& image, int x, int y)
{
	Mat dst;
	// 图像缩放,参数为输入图像、输出图像、目标图像大小、x方向缩放因子、y方向缩放因子、插值方式
	resize(image, dst, Size(x, y), 0, 0, INTER_LINEAR);
	//namedWindow("resize_demo", WINDOW_FREERATIO);
	imshow("resize_demo", dst);
}

19.图像翻转

void TestDemo::flip_demo(Mat& image, int flipCode)
{
	Mat dst;
	// 图像翻转,参数为输入图像、输出图像、翻转方式
	//flipCode=0表示绕x轴翻转,flipCode>0表示绕y轴翻转,flipCode<0表示绕x轴和y轴同时翻转
	flip(image, dst, flipCode);
	namedWindow("flip_demo", WINDOW_FREERATIO);
	imshow("flip_demo", dst);
}

绕x轴翻转

 绕y翻转

同时绕x,y翻转

20.图像旋转

void TestDemo::rotate_demo(Mat& image, double angle, double scale)
{
	/*
	参数angle表示旋转角度,正值表示逆时针旋转,负值表示顺时针旋转
	参数scale表示缩放因子,大于1表示放大,小于1表示缩小
	*/
	Mat dst, M;
	int w = image.cols;
	int h = image.rows;

	M = getRotationMatrix2D(Point(w / 2, h / 2), angle, scale);	// 获取旋转矩阵

	double cos = abs(M.at<double>(0, 0));
	double sin = abs(M.at<double>(0, 1));

	int nw = cos * w + sin * h;
	int nh = sin * w + cos * h;

	M.at<double>(0, 2) += (nw - w) / 2;
	M.at<double>(1, 2) += (nh - h) / 2;

	warpAffine(image, dst, M, Size(nw, nh));	// 图像旋转
	namedWindow("rotate_demo", WINDOW_FREERATIO);
	imshow("rotate_demo", dst);
}

21.视频文件/摄像头使用

void TestDemo::video_demo()
{
	VideoCapture capture(0);	// 打开摄像头
	if (!capture.isOpened())	// 摄像头打开失败
	{
		std::cout << "摄像头打开失败" << std::endl;
		return;
	}

	Mat frame;
	while (1)
	{
		capture >> frame;	// 读取摄像头图像
		//翻转摄像头显示
		flip_demo(frame, 1);
		imshow("video_demo", frame);	// 显示摄像头图像
		if (waitKey(30) == 27)	// 按下 ESC 键
		{
			break;
		}
	}
	capture.release();	// 释放摄像头
	destroyAllWindows();	// 销毁所有窗口
}

22.视频处理与保存

	//保存视频
	VideoWriter writer;
	writer.open(image_path + "/video_demo.avi", VideoWriter::fourcc('M', 'J', 'P', 'G'), 25, Size(frame.cols, frame.rows));
	while (1)
	{
		capture >> frame;	// 读取摄像头图像
		writer.write(frame);	// 写入视频
		imshow("video_demo", frame);	// 显示摄像头图像
		if (waitKey(30) == 27)	// 按下 ESC 键
		{
			break;
		}
	}
	writer.release();	// 释放视频

23.图像直方图

直方图(Histogram)是图像处理中常用的工具,它表示图像中每个像素强度值的分布情况。在OpenCV中,可以使用 cv::calcHist 函数来计算图像的直方图。

图像直方图是一种展示图像像素强度分布的统计图表。它显示了图像中每个像素强度值的频率,有助于分析图像的亮度、对比度和色调等特征。以下是图像直方图的一些主要作用:

  1. 亮度和对比度分析: 直方图可以用于分析图像的整体亮度和对比度。通过观察直方图的形状,可以了解图像中亮度的分布情况,从而调整图像的亮度和对比度,使其更符合需求。

  2. 图像增强: 直方图均衡化是一种常见的图像增强方法,通过调整图像的直方图,使其更均匀地分布在整个灰度范围内,从而增强图像的细节和对比度。

  3. 颜色分析: 对于彩色图像,可以对每个颜色通道分别绘制直方图,以了解图像中各个颜色通道的分布情况。这对于颜色校正和调整非常有帮助。

  4. 阈值选择: 直方图可以帮助选择图像的二值化阈值。通过观察直方图的波峰和波谷,可以找到合适的阈值,将图像转换为二值图像。

  5. 检测图像质量问题: 异常的直方图形状可能指示图像质量问题,例如曝光不足或曝光过度。通过检查直方图,可以识别并纠正这些问题。

void TestDemo::histogram_demo(Mat& image)
{
	//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);

	//绘制直方图
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);	// 将图像转换为灰度图
	int histSize = 256;	// 直方图尺寸
	float range[] = { 0, 256 };	// 像素值范围
	const float* histRange = { range };
	Mat hist;
	calcHist(&gray, 1, 0, Mat(), hist, 1, &histSize, &histRange, true, false);	// 计算直方图
	int hist_w = 512;	// 直方图宽度
	int hist_h = 400;	// 直方图高度
	int bin_w = cvRound((double)hist_w / histSize);	// 直方图每个条的宽度
	Mat histImage(hist_h, hist_w, CV_8UC3, Scalar(255, 255, 255));	// 创建直方图图像
	normalize(hist, hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());	// 直方图归一化
	for (int i = 1; i < histSize; i++)
	{
		line(histImage, Point(bin_w * (i - 1), hist_h - cvRound(hist.at<float>(i - 1))), Point(bin_w * (i), hist_h - cvRound(hist.at<float>(i))), Scalar(0, 0, 0), 2, 8, 0);	// 绘制直方图
	}
	namedWindow("histogram_demo", WINDOW_FREERATIO);
	imshow("histogram_demo", histImage);
}

24.二维直方图

二维直方图是在图像处理中用于描述两个变量(通常是图像的两个通道)之间关系的直方图。在图像处理中,最常见的是彩色图像的二维直方图,其中横轴和纵轴分别表示两个颜色通道。

以下是二维直方图的一些主要特点和应用:

  1. 颜色分布: 对于彩色图像,二维直方图可以显示不同颜色通道之间的关系。例如,对于RGB图像,横轴和纵轴可以分别表示红色和绿色通道,通过颜色在直方图中的分布,可以了解图像中不同颜色的占比。

  2. 色调相关性: 二维直方图可以用于分析图像中颜色通道之间的相关性。通过观察直方图的形状,可以了解图像中颜色的相关性,从而更好地理解图像的色调。

  3. 色彩校正: 通过分析二维直方图,可以识别和调整图像中不同通道的色彩偏差。这对于颜色校正非常有帮助,确保图像的颜色表现准确。

  4. 图像分割: 二维直方图在图像分割中有广泛的应用。通过选择合适的阈值,可以将图像分割成不同的区域,从而实现物体的检测和识别。

  5. 通道选择: 通过分析二维直方图,可以确定哪些颜色通道对于特定任务最为重要。这对于图像特征提取和图像识别非常有帮助。

void TestDemo::histogram_2d_demo(Mat& image)
{
	//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);

	//绘制二维直方图
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);	// 将图像转换为 HSV 图
	int hbins = 30, sbins = 32;	// H、S 通道直方图尺寸
	int histSize[] = { hbins, sbins };
	float hranges[] = { 0, 180 };	// H 通道像素值范围
	float sranges[] = { 0, 256 };	// S 通道像素值范围
	const float* ranges[] = { hranges, sranges };
	MatND hist;
	int channels[] = { 0, 1 };
	calcHist(&hsv, 1, channels, Mat(), hist, 2, histSize, ranges, true, false);	// 计算二维直方图
	double maxVal = 0;
	minMaxLoc(hist, 0, &maxVal, 0, 0);
	int scale = 10;
	Mat histImg = Mat::zeros(sbins * scale, hbins * 10, CV_8UC3);

	for (int h = 0; h < hbins; h++)
	{
		for (int s = 0; s < sbins; s++)
		{
			float binVal = hist.at<float>(h, s);
			int intensity = cvRound(binVal * 255 / maxVal);
			rectangle(histImg, Point(h * scale, s * scale), Point((h + 1) * scale - 1, (s + 1) * scale - 1), Scalar::all(intensity), FILLED);
		}
	}
	namedWindow("histogram_2d_demo", WINDOW_FREERATIO);
	imshow("histogram_2d_demo", histImg);

}

25.直方图均衡化

图像直方图均衡化是一种用于增强图像对比度的方法,通过调整图像的灰度分布,使得各个灰度级均匀分布,从而提高图像的视觉效果。下面详细讲解一下图像直方图均衡化的原理和步骤:

原理:

  1. 灰度直方图: 图像的灰度直方图表示了图像中各个灰度级的分布情况,即每个灰度级的像素数量。

  2. 累积分布函数(CDF): CDF 是灰度直方图的累积形式,表示每个灰度级以下的像素累积数量。

  3. 均衡化变换: 均衡化变换的目标是将图像的灰度分布映射到均匀分布,即让 CDF 尽可能平滑。

步骤:

  1. 计算灰度直方图: 对图像进行灰度化,统计各个灰度级的像素数量。

  2. 计算累积分布函数(CDF): 利用灰度直方图计算各个灰度级的累积概率。

  3. 均衡化变换: 利用均衡化变换公式,对每个灰度级进行映射。

  4. 生成均衡化后的图像: 根据均衡化变换,生成均衡化后的图像。

26.图像卷积操作

图像卷积是图像处理中的一种基本操作,它通过在图像上滑动一个卷积核(也称为滤波器或窗口),对图像的每个像素进行加权和的操作。这一过程可以用来实现一系列的图像处理任务,如模糊、锐化、边缘检测等。下面是图像卷积的基本原理和步骤:

原理:

  1. 卷积核: 卷积核是一个小矩阵,包含了一组权重值。卷积操作时,卷积核在图像上滑动,与图像中的每个像素进行加权和的计算。

  2. 加权和计算: 对于图像中的每个像素,卷积核与图像的对应区域进行逐元素相乘,然后将所有乘积结果相加,得到最终的加权和。

  3. 滑动操作: 卷积核在图像上滑动,对每个像素都进行加权和的计算,得到新的图像。

步骤:

  1. 定义卷积核: 确定卷积核的大小和权重。

  2. 图像填充: 可选的步骤,对图像进行填充,以保留边缘信息。

  3. 卷积操作: 卷积核在图像上滑动,对每个像素进行加权和的计算。

  4. 输出结果: 得到卷积后的图像,即输出结果。

void TestDemo::convolution_demo(Mat& image)
{
	//创建一个白色底板的图像
	Mat img = Mat::zeros(Size(512, 512), CV_8UC3);
	img = Scalar(255, 255, 255);

	//图像卷积操作
	Mat kernel = (Mat_<float>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);	// 创建卷积核
	Mat dst;
	filter2D(image, dst, -1, kernel);	// 图像卷积
	namedWindow("convolution_demo", WINDOW_FREERATIO);
	imshow("convolution_demo", dst);
}

27.高斯模糊

高斯模糊(Gaussian Blur)是一种常用的图像模糊技术,它使用高斯函数对图像进行卷积,从而实现图像平滑处理。高斯模糊的主要目的是去除图像中的高频噪声,使图像更加平滑,减少细节信息,常用于图像预处理、边缘检测前的图像平滑等任务。

高斯模糊的原理:

  1. 高斯函数: 高斯函数是一种数学函数,通常用于表示正态分布。在图像处理中,高斯函数用于生成一个二维的高斯核(卷积核)。

  2. 卷积操作: 高斯核在图像上滑动,对图像中的每个像素进行加权和的计算。不同位置的像素受到的权重由高斯函数的形状决定,距离中心越远的像素权重越小。

  3. 权重计算: 高斯函数的形状由标准差(σ)决定,标准差越大,权重分布越广。权重计算采用二维高斯函数的值,将其归一化,得到最终的权重。

高斯模糊的步骤:

  1. 定义高斯核: 定义一个二维高斯核,指定标准差。

  2. 图像卷积: 将高斯核与图像进行卷积操作。

  3. 输出结果: 得到经过高斯模糊处理后的图像。

void TestDemo::gaussian_blur_demo(Mat& image)
{
	// 定义高斯核大小和标准差
	int kernel_size = 35;
	double sigma = 35;

	// 高斯模糊
	Mat dst;
	GaussianBlur(image, dst, Size(kernel_size, kernel_size), sigma);
	//GaussianBlur参数为输入图像、输出图像、高斯核大小、标准差

	namedWindow("gaussian_blur_demo", WINDOW_FREERATIO);
	imshow("gaussian_blur_demo", dst);

}

28.高斯双边模糊

高斯双边滤波是一种保留边缘信息的模糊技术,它在模糊图像的同时保持图像的边缘细节。与简单的高斯模糊不同,高斯双边滤波考虑像素之间的空间距离和像素值之间的差异。

void TestDemo::bilateral_filter_demo(Mat& image)
{
	// 定义参数
	int diameter = 20;  // 直径
	double sigma_color = 175.0;  // 颜色空间标准差
	double sigma_space = 175.0;  // 空间空间标准差

	// 高斯双边滤波
	Mat dst;
	bilateralFilter(image, dst, diameter, sigma_color, sigma_space);

	// 显示结果
	namedWindow("bilateral_filter_demo", WINDOW_FREERATIO);
	imshow("bilateral_filter_demo", dst);
}

diameter表示像素领域的直径,sigma_color表示颜色空间的标准差,sigma_space表示空间空间的标准差。调整这些参数可以影响滤波效果。

与高斯模糊不同,高斯双边滤波在模糊图像的同时会保留边缘信息,适用于需要模糊但又不希望失去图像边缘细节的场景。

29.实时人脸检测

void TestDemo::face_detect_demo()
{
	// 加载人脸检测器模型
	cv::CascadeClassifier face_cascade;
	if (!face_cascade.load("C:/tools/OpenCV/opencv/build/etc/haarcascades/haarcascade_frontalface_default.xml"))
	{
		std::cerr << "Error loading face cascade model!" << std::endl;
		return;
	}

	// 在这里添加进行人脸检测的代码

	// 例如,可以在摄像头捕获的每一帧上运行人脸检测
	cv::VideoCapture capture(0);  // 打开默认摄像头
	if (!capture.isOpened())
	{
		std::cerr << "Error opening camera!" << std::endl;
		return;
	}

	cv::Mat frame;
	while (capture.read(frame))
	{
		// 转换图像为灰度图
		cv::Mat gray;
		cv::cvtColor(frame, gray, cv::COLOR_BGR2GRAY);
		cv::equalizeHist(gray, gray);  // 直方图均衡化提高对比度

		//进行双边滤波
		cv::Mat dst;
		cv::bilateralFilter(gray, dst, 20, 150, 150);

		// 进行人脸检测
		std::vector<cv::Rect> faces;
		face_cascade.detectMultiScale(dst, faces, 1.1, 3, 0, cv::Size(30, 30));

		// 在图像上标记检测到的人脸
		for (const auto& face : faces)
		{
			cv::rectangle(frame, face, cv::Scalar(255, 0, 0), 2);  // 用蓝色矩形标记人脸
		}

		// 显示结果
		cv::imshow("Face Detection Demo", frame);

		// 检测按键,按下ESC键退出循环
		if (cv::waitKey(30) == 27)
		{
			break;
		}
	}
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值