C/C++ vs2017 OpenCV简单入门

Posted cpp_learners

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++ vs2017 OpenCV简单入门相关的知识,希望对你有一定的参考价值。

 离职之际,自学一下图像相关的知识点,只是简单学了一点皮毛!


目录

一、 OpenCV环境搭建

二、使用opencv

常用接口说明

使用案例

1. 图像色彩空间转换

2. Mat对象的创建与赋值

3. 图像像素的读写操作

4. 图像像素的算术操作

5. 滚动条操作演示

6. 键盘响应操作

7. OpenCV自带颜色表操作

8. 图像像素的逻辑操作

9. 通道分离与合并

10. 图像色彩空间转换

11. 图像像素值统计 

12. 图像几何形状绘制

13. 随机数与随机颜色 

14. 多边形填充与绘制

15. 鼠标操作与响应

16. 图像像素类型转换与归一化

17. 图像缩放与插值

18. 图像翻转

19. 图像旋转

20. 视频文件摄像头使用

21. 图像卷积操作

22. 高斯模糊 

23. 高斯双边模糊

三、键盘操作小demo

1. 键盘小demo

2. 旋转、缩放、裁剪、平移案例

3. 往图片中写入中文文字

四、总结


一、 OpenCV环境搭建

官网下载链接:Releases - OpenCV

 下载后双击开始解压安装

 

解压完毕 

 进入路径 D:\\opencv\\opencv\\build\\x64\\vc14\\bin

 vs2019及其以上的版本可以选择vc15那个文件夹

 拷贝该路径,设置环境变量

在路径D:\\opencv\\opencv\\build\\x64\\vc14\\lib 会有项目中需要使用到的lib

新建一个VS工程,

右键 属性 - VC++目录 - 包含库目录,添加头文件路径进来

 右键 属性 - VC++目录 - 库目录,添加lib文件路径进行

 右键 属性 - 链接器 - 输入 - 附加依赖项,将opencv_world460d.lib添加进来,如果是release项目,那么就添加opencv_world460.lib

 注意,属性中的“配置”和“平台”需要和界面的保持一致

当然,上面添加目录和库目录的操作,可以将相应的头文件和库拷贝到项目路径,再添加项目路径进来即可!

编写如下代码测试环境:

#include <opencv2/opencv.hpp>

#include <iostream>
#include <stdio.h>


using namespace cv;


void int test1(Mat src) 

    // 设置新的窗体标题,参数一窗体标题,参数二窗体随图片大小
	namedWindow("opencv窗口2", WINDOW_AUTOSIZE);

	Mat output_image;
	/* 设置图片颜色 */
	cvtColor(src, output_image, COLOR_BGRA2RGB);
	imshow("opencv窗口2", output_image);

	/* 保存图片到本地 */
	imwrite("D:/new.png", output_image);

    // 等待
	waitKey(0);



int main(void) 

	// 正常:IMREAD_COLOR
	// 灰度:IMREAD_GRAYSCALE
	Mat image = imread("图.jpeg", IMREAD_COLOR);    // 读取一张图片
	if (image.empty())         // 判断图片是否读取成功
		printf("path image NULL!\\n");
		return -1;
	

    // 显示图片    参数一是窗体标题,参数二图片对象
	imshow("原图", image);


	test1(image);

    return 0;

编译运行,不出意外的话,就会显示两张我们指定路径读取的图片

 左边那一种是修改颜色后的图片,右边是原图!

至此,环境搭建完毕!


二、使用opencv

常用接口说明

1. imread

Mat image = imread("图.jpeg", IMREAD_COLOR);

        解析:读取一张图片。

2. image.empty()

        解析:判断文件是否读取成功,ture表示不成功,false表示成功。

3. imshow

imshow("opencv窗口2", output_image);

        解析:显示一张图片,参数一是窗体名字,参数二是图片对象,也就是Mat对象

4. imwrite

imwrite("D:/new.png", output_image);

        解析:将图像保存到本地。参数一是文件路径名,参数二是图片对象。

5. waitKey

int waitKey(int delay = 0);

        解析:等待,相当于c/c++中的system("pause"); 参数为0,表示一直等待,其他大于零的数,则表示等待对应的秒数。
        

6. destroyAllWindows

void destroyAllWindows();

        解析:销毁所有打开的窗体。

7. cvtColor

void cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 );

        解析:设置图像的颜色。参数一是输入图像对象,参数二是设置好输出的图像对象,参数三是设置图像颜色枚举(enum ColorConversionCodes)

8. clone

Mat src = image.clone()

        解析:将图像对象克隆赋值,需要另一个Mat对象去接收,相当于深拷贝。

8. copyTo

Mat m2;
image.copyTo(m2)

        解析:将图像对象拷贝给另一个图像对象,相当于深拷贝。

9. zeros

Mat m4 = Mat::zeros(Size(128, 128), CV_8UC3);

        解析:创建空白图像。参数一是图像大小,参数二表示通道数。

10. Scalar

m4 = Scalar(255, 255, 0);

        解析:给图像设置颜色。因为是给三个通道的图像设置颜色,所以这里使用三个参数;如果是给单通道设置颜色,则设置一个参数即可。

11. cols

int width = m4.cols;

        解析:获取图像的宽度。

12. rows

int height = m4.rows;

        解析:获取图像的高度。

13. channels

int channels = m4.channels();

        解析:获取通向的通道数。单通道表示灰色图像,三通道表示彩色图像。

14. add

add(image, m1, dst1);

        解析:图像的像素相加。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相加后输出到参数三。

15. subtract

subtract(image, m2, dst2);

        解析:图像的像素相减。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相减后输出到参数三。

16. multiply

multiply(image, m3, dst3);

        解析:图像的像素相乘。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相乘后输出到参数三。

17. divide

divide(image, m4, dst4);

         解析:图像的像素相除。参数一和参数二是输入图像,参数三是输出图像。也就是将参数一和参数二的像素相除后输出到参数三。

18. waitKey

 int c = waitKey(100);

        解析:等待键盘输入,如果参数设置的毫秒数结束后还没有键盘输入,则默认输入-1,结束等待。

19. applyColorMap 

applyColorMap(image, dst, COLORMAP_COOL);

        解析:设置图像彩色映射。参数一是输入图像,参数二是输出图像,参数三是映射的颜色类型,他是枚举enum ColormapTypes。

        

20. bitwise_and  

bitwise_and(m1, m2, dst1);

        解析:图像像素逻辑操作。参数一和参数二是输入图像,参数三是输出图像。

21. bitwise_or

bitwise_or(m1, m2, dst2);

        解析:图像像素逻辑操作。参数一和参数二是输入图像,参数三是输出图像。

22. bitwise_not

bitwise_not(image, dst3);

        解析:图像像素取反操作。参数一是输入图像,参数二是输出图像。

23. bitwise_xor

bitwise_xor(m1, m2, dst4);

        解析:图像像素逻辑异或操作。参数一和参数二是输入图像,参数三是输出图像。

24. split

std::vector<Mat> mv;
split(image, mv);

        解析:通道分离。

25. rectangle

rectangle(dst1, rect, Scalar(0, 255, 255), 2, 8, 0);

        解析:绘制一个矩形。参数一是输出图像,参数二是矩形对象,参数三是颜色,参数四是边框厚度,参数五是反锯齿(可以使用LINE_AA效果更加),参数六不清楚。

        如果是需要填充,则将参数四传入-1。

26. circle

circle(dst1, Point(300, 400), 30, Scalar(255, 0, 255), 2, 8, 0);

        解析:绘制一个圆形。参数一是输出图像,参数二是圆的中心位置,参数三是圆的半径,参数四是颜色,参数五是边框厚度,参数六是反锯齿(可以使用LINE_AA效果更加),参数七不清楚。

        如果是需要填充,则将参数五传入-1。

27. line

line(dst5, Point(100, 130), Point(300, 400), Scalar(255, 0, 0), 2, 8, 0);

        解析:绘制一条线。参数一是输入输出图像, 参数二是第一个点位置,参数三是第二个点位置,参数四是颜色,参数五是线的宽度,参数六是反锯齿,参数七不清楚。

28. RNG

RNG rng((unsigned)time(NULL));    // 用系统时间作为种子初始化rng,要用到time.h库
int b = rng.uniform(0, 255);    // 随机生成 0 - 255

        解析:opencv的随机函数。

29. drawContours

drawContours(canvas, contours, 0, Scalar(255, 0, 0), -1);

        解析:绘制多边形或者填充多边形。参数一是输入输出图像,参数二是std::vector<std::vector<Point>>类型对象,参数三指定绘制容器中指定数据的第几个(-1表示全都绘制),最后一个参数为多边形的边框(-1表示填充)

30. resize

resize(image, zoomin, Size(w / 2, h / 2));

        解析:图像缩放。参数一是输入图像,参数二是输出图像,参数三是重新设置的图像大小。

31. flip

// 上下翻转
flip(image, dst, 0);

// 左右翻转
flip(image, dst, 1);

// 先左右翻转再上下翻转
flip(image, dst, -1);

        解析:图像翻转。参数一是输入图像,参数二是输出图像,参数三0表示上下翻转,1表示左右翻转,-1表示先左右翻转再上下翻转。

使用案例

以下函数的参数都基于此读取的图像对象:

int main(void) 

	// 正常:IMREAD_COLOR
	// 灰度:IMREAD_GRAYSCALE
	Mat image = imread("图.jpeg", IMREAD_COLOR);
	if (image.empty()) 
		printf("path image NULL!\\n");
		return -1;
	

	imshow("原图", image);

	waitKey(0);
	destroyAllWindows();

	return 0;

1. 图像色彩空间转换

/* 图像色彩空间转换 */
void colorSpace_Demo(Mat &image) 
	Mat gray, hsv;

	cvtColor(image, hsv, COLOR_BGR2HSV);
	cvtColor(image, gray, COLOR_BGR2GRAY);	// 灰度图像
	
	imshow("HSV", hsv);
	imshow("灰度", gray);

	imwrite("HSV.png", hsv);
	imwrite("GRAY.png", gray);

运行截图

2. Mat对象的创建与赋值

/* Mat对象的创建与赋值 */
void mat_creation_demo(Mat &image) 

	Mat m1, m2, m3;
	
	// 克隆
	m1 = image.clone();		// 深拷贝
	// 拷贝
	image.copyTo(m2);		// 深拷贝

	// 赋值
	m3 = image;				// 浅拷贝

	// 创建空白图像
	//Mat m4 = Mat::zeros(Size(8, 8), CV_8UC1);		// 创建一通道
	Mat m4 = Mat::zeros(Size(128, 128), CV_8UC3);	// 最后的数字表示通道数
	// 给通道赋值(相当于设置颜色)
	m4 = Scalar(123, 200, 100);	// 因为是3通道,所以赋三个值;如果是一通道,给一个参数值即可
	//std::cout << m4 << std::endl;

	imshow("m4", m4);

	// 图像的宽
	int width = m4.cols;
	// 图像的高
	int height = m4.rows;
	// 图像的通道数
	int channels = m4.channels();
	printf("width = %d\\theight = %d\\tchannels = %d\\n", width, height, channels);


	// C++11新出的创建空白图像方法
	Mat kernel = (Mat_<char>(3, 3) <<
				  0, -1, 0,
				  -1, 5, -1,
				  0, -1, 0);
	kernel = Scalar(50, 100, 150);
	imshow("kernel", kernel);

运行截图

3. 图像像素的读写操作

/* 图像像素的读写操作 */
void 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 (1 == dims) 
	//			// 获取通道中的值
	//			int pv = image.at<uchar>(row, col);
	//			// 还可以对其进行修改
	//			image.at<uchar>(row, col) = 255 - pv;	// 得确保值在0-255区间

	//		 else if (3 == dims) 	// 三通道 - 彩色图像
	//			// 获取通道中的三个值
	//			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 (1 == dims) 
				*current_row++ = 255 - *current_row;
			
			 else if (3 == dims) 
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			
		
	

	imshow("pixel_visit_demo", image);

运行截图:

4. 图像像素的算术操作

/* 图像像素的算术操作 */
void operators_demo(Mat &image) 

	// 加
	Mat dst1;
	Mat m1 = Mat::zeros(image.size(), image.type());
	m1 = Scalar(100, 100, 100);	// 给通道赋值(相当于设置颜色)
	add(image, m1, dst1);
	imshow("图像像素加法操作", dst1);

	// 减
	Mat dst2;
	Mat m2 = Mat::zeros(image.size(), image.type());
	m2 = Scalar(50, 50, 50);
	subtract(image, m2, dst2);
	imshow("图像像素减法操作", dst2);

	// 乘
	Mat dst3;
	Mat m3 = Mat::zeros(image.size(), image.type());
	m3 = Scalar(2, 2, 2);
	multiply(image, m3, dst3);	// 参数一乘以参数二结果给参数三
	imshow("图像像素乘法操作", dst3);

	// 除
	Mat dst4;
	Mat m4 = Mat::zeros(image.size(), image.type());
	m4 = Scalar(5, 5, 5);
	divide(image, m4, dst4);
	imshow("图像像素除法操作", dst4);


	///* 另外一种方式实现加法操作 */
	//Mat dst5 = Mat::zeros(image.size(), image.type());
	//Mat m5 = Mat::zeros(image.size(), image.type());
	//m5 = Scalar(50, 50, 50);

	//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 (3 == dims) 
	//			Vec3b p1 = image.at<Vec3b>(row, col);
	//			Vec3b p2 = m5.at<Vec3b>(row, col);
	//			// 加减乘除都是一样的
	//			dst5.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0] + p2[0]);
	//			dst5.at<Vec3b>(row, col)[1] = saturate_cast<uchar>(p1[1] + p2[1]);
	//			dst5.at<Vec3b>(row, col)[2] = saturate_cast<uchar>(p1[2] + p2[2]);
	//		
	//		
	//	
	//
	//imshow("图像像素加法操作", dst5);

运行截图

5. 滚动条操作演示

static void on_track(int b, void *userdata) 

	Mat image = *((Mat*)userdata);
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(b, b, b);
	add(image, m, dst);
	imshow("亮度调整", dst);

/* 滚动条操作演示 */
void tracking_bar_demo(Mat &image) 
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	int lightness = 0;
	int max_value = 100;
	// 创建一个滚动条
	createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track, (void*)(&image));
	on_track(lightness, &image);

运行截图

6. 键盘响应操作

/* 键盘响应操作 */
void key_demo(Mat &image) 
	bool flag = true;

	Mat input;
	image.copyTo(input);

	while (flag) 
		int c = waitKey(100);	// 等待键盘输入,等待100ms
		printf("按键:%d\\n", c);

		switch (c) 
			case 27: 			// Esc退出
				flag = false;
			
			break;

			case 52: 			// 4 向左旋转

			
			break;

			case 54: 			// 6 向右旋转

			
			break;

			case 56: 			// 8 放大

			
			break;

			case 50: 			// 2 缩小
	
			
			break;

			case 48: 		// 0 复原

			
			break;

			default:				
				break;
		

		imshow("原图", image);
	

这个键盘响应,我用来写了一个小demo,通过键盘按键来对图片进行旋转、缩放、平移、翻转和裁剪的操作。

7. OpenCV自带颜色表操作

/* OpenCV自带颜色表操作 */
void color_style_demo(Mat &image) 

	int colorMap[] = 
		COLORMAP_AUTUMN,
		COLORMAP_BONE,
		COLORMAP_CIVIDIS,
		COLORMAP_COOL,
		COLORMAP_DEEPGREEN,
		COLORMAP_HOT,
		COLORMAP_HSV,
		COLORMAP_INFERNO,
		COLORMAP_JET,
		COLORMAP_MAGMA,
		COLORMAP_OCEAN,
		COLORMAP_PARULA,
		COLORMAP_PINK,
		COLORMAP_PLASMA,
		COLORMAP_RAINBOW,
		COLORMAP_SPRING,
		COLORMAP_SUMMER,
		COLORMAP_TURBO,
		COLORMAP_TWILIGHT,
		COLORMAP_TWILIGHT_SHIFTED,
		COLORMAP_VIRIDIS,
		COLORMAP_WINTER,
		DECOMP_NORMAL
	;

	Mat dst;
	int index = 0;

	while (1) 
		int c = waitKey(1000);
		if (27 == c) 
			break;
		

		applyColorMap(image, dst, colorMap[index % 19]);
		index++;

		imshow("Opencv自带颜色表", dst);
	

数组colorMap中存储的,都是enum ColormapTypes枚举中的数据。

运行截图

8. 图像像素的逻辑操作

/* 图像像素的逻辑操作 */
void 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 dst1;
	bitwise_and(m1, m2, dst1);
	imshow("逻辑与", dst1);

	// 逻辑或
	Mat dst2;
	bitwise_or(m1, m2, dst2);
	imshow("逻辑或", dst2);

	// 逻辑非
	Mat dst3;
	bitwise_not(image, dst3);
	imshow("逻辑非", dst3);

	// 逻辑异或
	Mat dst4;
	bitwise_xor(m1, m2, dst4);
	imshow("逻辑异或", dst4);

运行截图

9. 通道分离与合并

/* 通道分离与合并 */
void channels_demo(Mat &image) 
	std::vector<Mat> mv;
	// 将一个多通道数组划分为多个单通道数组
	split(image, mv);
	imshow("blue", mv.at(0));
	imshow("green", mv.at(1));
	imshow("red", mv.at(2));


	Mat dst;
	//mv.at(1) = 0;
	mv.at(2) = 0;
	// 通道合并
	merge(mv, dst);
	imshow("合并通道颜色", dst);


	int from_to[] =  0, 2, 1, 1, 2, 0 ;	// 将0 和 2通道交换
	// 通道混合
	mixChannels(&image, 1, &dst, 1, from_to, 3);
	imshow("通道混合", dst);

运行截图

10. 图像色彩空间转换

/* 图像色彩空间转换 */
void inrange_demo(Mat &image) 
	Mat hsv;
	// 转换位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(mask, mask);		// 逻辑非
	imshow("mask", mask);
	image.copyTo(redback, mask);	// 将原图草莓图中按照mask里白色区域拷贝到参数一中
	imshow("roi区域提取", redback);

运行截图

11. 图像像素值统计 

/* 图像像素值统计 */
void pixel_statistic_demo(Mat &image) 
	double minv, maxv;
	Point minLoc, maxLoc;
	std::vector<Mat> mv;

	split(image, mv);	// 通道分离

	for (int i = 0; i < mv.size(); i++) 
		// 找出通道中的最大值和最小值
		minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
		printf("No.channels:%d\\tminvalue:%f\\tmaxvalue:%f\\n", i, minv, maxv);
	

	Mat mean, stddev;
	// 计算矩阵的均值和标准偏差
	meanStdDev(image, mean, stddev);
	std::cout << "means: " << mean << std::endl;
	std::cout << "stddev:" << stddev << std::endl;

运行截图

12. 图像几何形状绘制

/* 图像几何形状绘制 */
void drawing_demo(Mat &image) 
	Rect rect;
	rect.x = 100;
	rect.y = 130;
	rect.width = 200;
	rect.height = 270;


	Mat dst1 = image.clone();
	Mat dst2 = image.clone();

	// 绘制一个矩形
	rectangle(dst1, rect, Scalar(0, 255, 255), 2, 8, 0);
	// 绘制一个圆形
	circle(dst1, Point(300, 400), 30, Scalar(255, 0, 255), 2, 8, 0);
	imshow("绘制演示", dst1);

	// 填充一个矩形
	rectangle(dst2, rect, Scalar(255, 255, 0), -1, 8, 0);
	// 填充一个圆形
	circle(dst2, Point(100, 400), 30, Scalar(0, 255, 0), -1, 8, 0);
	imshow("填充演示", dst2);

	Mat dst5 = image.clone();
	// 绘制线
	line(dst5, Point(100, 130), Point(300, 400), Scalar(255, 0, 0), 2, 8, 0);
	// 绘制椭圆
	RotatedRect rrt;
	rrt.center = Point(200, 200);
	rrt.size = Size(100, 200);
	rrt.angle = 90.0;
	ellipse(dst5, rrt, Scalar(0, 0, 255), 2, 8);	// 如果需要填充,第四个参数传-1
	imshow("线和椭圆", dst5);


	Mat dst3, dst4;
	dst3 = Mat::zeros(image.size(), image.type());
	dst3 = Scalar(100, 180, 200);
	imshow("dst3", dst3);
	// 将两张相同大小,相同类型的图片融合的函数
	addWeighted(image, 0.7, dst3, 0.5, 1, dst4);
	imshow("两种图片融合", dst4);

运行截图

13. 随机数与随机颜色 

/* 随机数与随机颜色 */
void random_drawing_demo() 
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	int w = canvas.cols;
	int h = canvas.rows;
	RNG rng((unsigned)time(NULL)); // 用系统时间作为种子初始化rng,要用到time.h库

	while (1) 
		int c = waitKey(10);
		if (27 == c) 
			break;
		

		canvas = Scalar(0, 0, 0);

		// 获得随机值
		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);
	

运行截图

14. 多边形填充与绘制

/* 多边形填充与绘制 */
void polyline_drawing_demo() 
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	Point p1(100, 100);
	Point p2(350, 120);
	Point p3(300, 350);
	Point p4(450, 500);
	Point p5(50, 200);
	std::vector<Point> pts;
	pts.emplace_back(p1);
	pts.emplace_back(p2);
	pts.emplace_back(p3);
	pts.emplace_back(p4);
	pts.emplace_back(p5);
	// 填充一个多边形
	//fillPoly(canvas, pts, Scalar(255, 0, 255), 8, 0);
	// 绘制一个多边形
	//polylines(canvas, pts, true, Scalar(0, 0, 255), 2, LINE_AA, 0);

	std::vector<std::vector<Point>> contours;
	contours.push_back(pts);
	// 绘制多边形或者填充多边形,参数三指定绘制容器中指定数据的第几个(-1表示全都绘制),最后一个参数为多边形的边框(-1表示填充)
	drawContours(canvas, contours, 0, Scalar(255, 0, 0), -1);
	imshow("多边形填充与绘制",  canvas);

运行截图

15. 鼠标操作与响应

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 && ep.y < image.size().height && ep.x < image.size().width) 
			Rect box(sp.x, sp.y, dx, dy);
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);	// 绘制矩形
			imshow("鼠标绘制", image);
			imshow("ROI区域提取", temp(box));	// 提取矩形中的图像
			
		 else 
			temp.copyTo(image);
			imshow("鼠标绘制", image);
		
		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) 
				temp.copyTo(image);
				Rect box(sp.x, sp.y, dx, dy);
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
			
		
	

/* 鼠标操作与响应 */
void mouse_drawing_demo(Mat &image) 
	namedWindow("鼠标绘制", WINDOW_AUTOSIZE);
	// 设置鼠标回调
	setMouseCallback("鼠标绘制", on_draw, (void*)(&image));
	imshow("鼠标绘制", image);
	temp = image.clone();

运行截图

16. 图像像素类型转换与归一化

/* 图像像素类型转换与归一化 */
void norm_demo(Mat &image) 
	Mat dst;
	std::cout << image.type() << std::endl;
	image.convertTo(image, CV_32F);
	std::cout << image.type() << std::endl;
	normalize(image, dst, 1.0, 0, NORM_MINMAX);
	std::cout << dst.type() << std::endl;
	imshow("图像数据归一化", dst);

运行截图

17. 图像缩放与插值

/* 图像缩放与插值 */
void resize_demo(Mat &image) 
	Mat zoomin, zoomout;
	int h = image.rows;
	int w = image.cols;
	resize(image, zoomin, Size(w / 2, h / 2), 0, 0, INTER_LINEAR);
	imshow("zoomin", zoomin);
	resize(image, zoomout, Size(w*1.5, h*1.5), 0, 0, INTER_LINEAR);
	imshow("zoomout", zoomout);

运行截图

18. 图像翻转

/* 图像翻转 */
void flip_demo(Mat &image) 
	Mat dst;

	// 上下翻转
	flip(image, dst, 0);

	// 左右翻转
	//flip(image, dst, 1);

	// 先左右翻转再上下翻转
	//flip(image, dst, -1);

	imshow("图像翻转", dst);

运行截图

19. 图像旋转

/* 图像旋转 */
void rotate_demo(Mat &image) 
	Mat dst, M;

	int w = image.cols;
	int h = image.rows;
	M = getRotationMatrix2D(Point2f(w / 2, h / 2), -45, 1.0);

	// 计算旋转后需要多大的窗体才能完全装下旋转后的图像
	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 / 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);

运行截图

20. 视频文件摄像头使用

/* 视频文件摄像头使用 */
void video_demo() 
	// VideoCapture capture(0);		// 参数是0,就是读取电脑摄像头
	VideoCapture capture("E:\\\\Code\\\\vs2017Code\\\\OpencvTest2\\\\OpencvTest2\\\\win10.mp4");	
	
	// 视频宽
	int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);
	// 视频高
	int frame_hegiht = capture.get(CAP_PROP_FRAME_HEIGHT);
	// 视频总帧率
	int count = capture.get(CAP_PROP_FRAME_COUNT);
	// 视频每秒多少fps(每秒多少帧)
	double fps = capture.get(CAP_PROP_FPS);
	std::cout << "froma_width:" << frame_width << std::endl;
	std::cout << "frame_hegiht:" << frame_hegiht << std::endl;
	std::cout << "count:" << count << std::endl;
	std::cout << "fps:" << fps << std::endl;

	// 定义视频保存对象
	VideoWriter writer("D://test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_hegiht), true);
	
	Mat frame;
	while (1) 
		capture.read(frame);	// 读取画面
		//flip(frame, frame, 1);	// 左右翻转,读取电脑摄像头时需要翻转,视频不用
		if (frame.empty()) 
			break;
		
		imshow("frame", frame);

		// 保存视频
		writer.write(frame);

		int c = waitKey(10);
		if (27 == c) 
			break;
		
	

	// 释放
	capture.release();
	writer.release();

运行截图

21. 图像卷积操作

/* 图像卷积操作 */
void blur_demo(Mat &image) 
	Mat dst;
	blur(image, dst, Size(1, 1), Point(-1, -1));    // // 设置参数三的数值即可
	imshow("图像模糊", dst);    

运行截图

22. 高斯模糊 

/* 高斯模糊 */
void gaussian_blur_demo(Mat &image) 
	Mat dst;
	GaussianBlur(image, dst, Size(0, 0), 5);	// 参数三默认0即可,设置参数四实现模糊
	imshow("高斯模糊", dst);

运行截图

23. 高斯双边模糊

/* 高斯双边模糊 */
void bifilter_demo(Mat &image) 
	Mat dst;
	bilateralFilter(image, dst, 0, 100, 10);
	imshow("双边模糊", dst);

运行截图


三、键盘操作小demo

1. 键盘小demo

对图片操作,旋转,缩放,平移,翻转,裁剪的操作。

#include <opencv2/opencv.hpp>

using namespace cv;


void imageOperate1(Mat &image, Mat input, double angle, double scale, int xOffset, int yOffset, int startRow, int &endRow, int startCol, int &endCol, bool up_down, bool left_right) 

	input.copyTo(image);


	// 图像平移
	Size dst_sz = image.size();
	//定义平移矩阵
	Mat t_mat = Mat::zeros(2, 3, CV_32FC1);
	t_mat.at<float>(0, 0) = 1;
	t_mat.at<float>(0, 2) = xOffset; //水平平移量
	t_mat.at<float>(1, 1) = 1;
	t_mat.at<float>(1, 2) = yOffset; //竖直平移量
	//根据平移矩阵进行仿射变换
	warpAffine(image, image, t_mat, dst_sz);

	// 旋转图像
	Point2f center((image.cols - 1) / 2.0, (image.rows - 1) / 2.0);	// 图像中心位置
	Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0);
	warpAffine(image, image, rotation_matix, image.size());

	// 缩放图像
	int width = int(input.cols * scale);
	int height = int(input.rows * scale);
	resize(image, image, cv::Size(width, height), 0, 0, INTER_LINEAR);


	if (0 == endRow) 		// 发生了缩放操作
		endRow = height;
		endCol = width;
	
	// 裁剪图像	
	image = image(Range(startRow, endRow), Range(startCol, endCol));

	// 上下翻转
	if (up_down) flip(image, image, 0);

	// 左右翻转
	if (left_right) flip(image, image, 1);

/* 键盘响应操作 */
void key_demo1(Mat &image) 
	bool flag = true;
	double scale = 1.0;		// 缩放比例
	double angle = 0;		// 旋转角度
	int xOffset = 0;		// 水平平移量
	int yOffset = 0;		// 竖直平移量
	int startRow = 0;					// 裁剪起始行
	int endRow = image.size().height;	// 裁剪结束行
	int startCol = 0;					// 裁剪起始列
	int endCol = image.size().width;	// 才接结束列
	bool up_down = false;				// 上下翻转
	bool left_right = false;			// 左右翻转

	Mat input;
	image.copyTo(input);

	while (flag) 
		int c = waitKey(100);	// 等待键盘输入,等待100ms
		printf("按键:%d\\n", c);

		switch (c) 
			case 27:
						// Esc退出
				flag = false;
			
			break;

			case 52:
						// 4 向左旋转
				angle += 5;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 54:
						// 6 向右旋转
				angle -= 5;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 56:
						// 8 放大

				scale += 0.1;
				if (scale <= 2.05) 	// 设置最大放大是2
					endRow = 0;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					scale = 2.0;
				

			
			break;

			case 50:
						// 2 缩小

				scale -= 0.1;
				if (scale >= 0.15) 	// 最小缩小是0.2
					endRow = 0;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					scale = 0.2;
				

			
			break;

			case 87:
			case 119:
					// wW 图片上移

				yOffset -= 2;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 83:
			case 115:
					// sS 图片下移

				yOffset += 2;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 65:
			case 97:
					// aA 图片左移
				xOffset -= 2;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 68:
			case 100:
					// dD 图片右移
				xOffset += 2;

				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 73:
					// I 图片上边复原
				if (startRow > 0) 
					startRow -= 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					startRow = 0;
				

			
			break;

			case 105:
					// i 图片上边裁剪

				if (startRow < endRow - 1) 
					startRow += 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					startRow = endRow - 1;
				
			
			break;

			case 75:
					// K 图片下边复原
				if (endRow < input.size().height) 
					endRow += 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					endRow = input.size().height;
				
			
			break;

			case 107:
					// k 图片下边裁剪
				if (endRow > startRow + 1) 
					endRow -= 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					endRow = startRow + 1;
				
			
			break;

			case 74:
					// J 图片左边恢复
				if (startCol > 0) 
					startCol -= 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					startCol = 0;
				
			
			break;

			case 106:
					// j 图片左边裁剪
				if (startCol < endCol - 1) 
					startCol += 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					startCol = endCol - 1;
				
			
			break;

			case 76:
					// L 图片右边复原
				if (endCol < input.size().width) 
					endCol += 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					endCol = input.size().width;
				
			
			break;

			case 108:
					// l 图片右边裁剪
				if (endCol > startCol + 1) 
					endCol -= 1;

					imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);

				 else 
					endCol = startCol + 1;
				
			
			break;

			case 43:
					// + 上下翻转
				up_down = !up_down;
				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 45:
					//  - 左右翻转
				left_right = !left_right;
				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			case 48:
					// 0 复原
				scale = 1.0;					// 缩放比例
				angle = 0;						// 旋转角度
				xOffset = 0;					// 水平平移量
				yOffset = 0;					// 竖直平移量
				startRow = 0;					// 裁剪起始行
				endRow = input.size().height;	// 裁剪结束行
				startCol = 0;					// 裁剪起始列
				endCol = input.size().width;	// 才接结束列
				up_down = false;				// 上下翻转
				left_right = false;				// 左右翻转
				imageOperate1(image, input, angle, scale, xOffset, yOffset, startRow, endRow, startCol, endCol, up_down, left_right);
			
			break;

			default:
			break;
		

		imshow("原图", image);
	



int main(void) 

	Mat image = imread("图.jpeg", IMREAD_COLOR);
	if (image.empty()) 
		printf("path image NULL!\\n");
		return -1;
	

	imshow("原图", image);

	key_demo1(image);

	waitKey(0);
	destroyAllWindows();

	return 0;

运行截图

2. 旋转、缩放、裁剪、平移案例

#include <stdio.h>
#include <Windows.h>
#include "opencv2/opencv.hpp"

using namespace cv;


// 图片旋转
Mat imageRotate(Mat input, double angle) 
	angle *= -1;

	// get the center coordinates of the image to create the 2D rotation matrix
	Point2f center((input.cols - 1) / 2.0, (input.rows - 1) / 2.0);
	// using getRotationMatrix2D() to get the rotation matrix
	Mat rotation_matix = getRotationMatrix2D(center, angle, 1.0);

	Mat newImage;
	warpAffine(input, newImage, rotation_matix, input.size());
	//namedWindow("测试图片旋转", WINDOW_FREERATIO);
	//imshow("测试图片旋转", newImage);
	imshow("测试显示图片", newImage);

	return newImage;



// 图片缩放
Mat imageZoom(Mat input, float scaleW, float scaleH) 

	//float scaleW = 0.5; // 定义新图像的大小,宽度缩小到80%
	//float scaleH = 0.5;  //定义新图像的大小,高度缩小到80%
	int width = int(input.cols * scaleW);
	//定义想要扩大或者缩小后的宽度,src.cols为原图像的宽度,乘以80%则得到想要的大小,并强制转换成int型
	int height = int(input.rows * scaleH);
	//定义想要扩大或者缩小后的高度,src.cols为原图像的高度,乘以80%则得到想要的大小,并强制转换成int型
	cv::Mat dst;
	resize(input, dst, cv::Size(width, height));//缩放图像

	//namedWindow("测试图片缩放", WINDOW_FREERATIO);
	//imshow("测试图片缩放", dst);
	imshow("测试显示图片", dst);

	return dst;



// 图片裁剪
Mat imageCut(Mat input, int startRow, int endRow, int startCol, int endCol) 

	Mat cropped_image = input(Range(startRow, endRow), Range(startCol, endCol));
	//namedWindow("测试裁剪图片", WINDOW_FREERATIO);
	//imshow("测试裁剪图片", cropped_image);
	imshow("测试显示图片", cropped_image);

	return cropped_image;



// 图像平移
Mat imageTranslation(Mat srcImage, int xOffset, int yOffset)

	Size dst_sz = srcImage.size();
	//定义平移矩阵
	Mat t_mat = Mat::zeros(2, 3, CV_32FC1);
	t_mat.at<float>(0, 0) = 1;
	t_mat.at<float>(0, 2) = xOffset; //水平平移量
	t_mat.at<float>(1, 1) = 1;
	t_mat.at<float>(1, 2) = yOffset; //竖直平移量
	//根据平移矩阵进行仿射变换
	Mat TranslationMat;
	warpAffine(srcImage, TranslationMat, t_mat, dst_sz);

	//namedWindow("测试平移图片", WINDOW_FREERATIO);
	//imshow("测试平移图片", TranslationMat);
	imshow("测试显示图片", TranslationMat);

	return TranslationMat;



int main(void) 

	Mat image =imread("123.png");
	//namedWindow("测试显示图片", WINDOW_FREERATIO);	// WINDOW_FREERATIO:可以手动调节大小
	//imshow("测试显示图片", image);
	//waitKey(0);
	

	double angle = 120;
	Mat imgRotate = imageRotate(image, angle);

	waitKey(0);

	float scale = 0.5;
	Mat imgZoom = imageZoom(imgRotate, scale, scale);

	waitKey(0);

	Mat imgCut = imageCut(imgZoom, 50, 80, 200, 300);

	waitKey(0);

	imageTranslation(imgCut, 10, 20);

	waitKey(0);
	destroyAllWindows();

	return 0;

3. 往图片中写入中文文字

记录一个类型转换:

    // char* 转 wchar_t*
    wchar_t wcha[255] = 0 ;
    MultiByteToWideChar(CP_ACP, 0, text, strlen(text), wcha, 255);

putTextCN.h

#pragma once
#include <windows.h>
#include <string>
#include <opencv2/opencv.hpp>

using namespace cv;

// 内部调用
static void GetStringSize(HDC hDC, const char* str, int* w, int* h);
// 内部调用
static void putTextZH(Mat dst, const char* str, Point org, Scalar color, int fontSize,
			   const char *fn, bool italic, bool underline, bool lfWeight);

// 外部调用,往图片中写入文字
extern void putTextZh(InputOutputArray     img,
			   const char *text,
			   Point     org,
			   int     fontSize,
			   Scalar     color,
			   const char *font = "Arial",
			   bool italic = false,
			   bool underline = false,
			   bool lfWeight = false);

putTextCN.cpp

#include "putTextCN.h"

static void GetStringSize(HDC hDC, const char* str, int* w, int* h) 
	SIZE size;
	GetTextExtentPoint32A(hDC, str, strlen(str), &size);
	if (w != 0) *w = size.cx;
	if (h != 0) *h = size.cy;


static void putTextZH(Mat dst, const char* str, Point org, Scalar color, int fontSize, const char* fn, bool italic, bool underline, bool lfWeight) 
	CV_Assert(dst.data != 0 && (dst.channels() == 1 || dst.channels() == 3));

	int x, y, r, b;
	if (org.x > dst.cols || org.y > dst.rows) return;
	x = org.x < 0 ? -org.x : 0;
	y = org.y < 0 ? -org.y : 0;

	LOGFONTA lf;
	lf.lfHeight = -fontSize;
	lf.lfWidth = 0;
	lf.lfEscapement = 0;
	lf.lfOrientation = 0;
	if (true == lfWeight)     // 粗体
		lf.lfWeight = 700;
	 else 
		lf.lfWeight = 400;
		
	lf.lfItalic = italic;       // 斜体
	lf.lfUnderline = underline; // 下划线
	lf.lfStrikeOut = 0;
	lf.lfCharSet = DEFAULT_CHARSET;
	lf.lfOutPrecision = 0;
	lf.lfClipPrecision = 0;
	lf.lfQuality = PROOF_QUALITY;
	lf.lfPitchAndFamily = 0;
	strcpy_s(lf.lfFaceName, fn);

	HFONT hf = CreateFontIndirectA(&lf);
	HDC hDC = CreateCompatibleDC(0);
	HFONT hOldFont = (HFONT)SelectObject(hDC, hf);

	int strBaseW = 0, strBaseH = 0;
	int singleRow = 0;
	char buf[1 << 12];
	strcpy_s(buf, str);
	char *bufT[1 << 12];  // 这个用于分隔字符串后剩余的字符,可能会超出。
	//处理多行
	
		int nnh = 0;
		int cw, ch;

		const char* ln = strtok_s(buf, "\\n", bufT);
		while (ln != 0) 
			GetStringSize(hDC, ln, &cw, &ch);
			strBaseW = max(strBaseW, cw);
			strBaseH = max(strBaseH, ch);

			ln = strtok_s(0, "\\n", bufT);
			nnh++;
		
		singleRow = strBaseH;
		strBaseH *= nnh;
	

	if (org.x + strBaseW < 0 || org.y + strBaseH < 0) 
		SelectObject(hDC, hOldFont);
		DeleteObject(hf);
		DeleteObject(hDC);
		return;
	

	r = org.x + strBaseW > dst.cols ? dst.cols - org.x - 1 : strBaseW - 1;
	b = org.y + strBaseH > dst.rows ? dst.rows - org.y - 1 : strBaseH - 1;
	org.x = org.x < 

以上是关于C/C++ vs2017 OpenCV简单入门的主要内容,如果未能解决你的问题,请参考以下文章

图像识别入门 VS2017+Opencv的安装

vs2017编译并配置libcurl入门教程

如何在vs2017中进行64位汇编的配置

OpenCV+VS2013 属性表配置

[OpenCV笔记]简介和入门

OpenCV3编程入门-读书笔记3-滤波