OpenCV基础知识

下载安装

参考链接 VS2017配置opencv教程(超详细!!!)_Chosen One-CSDN博客_opencv

注意:后面的课程环境配置可能需要自己稍微改改,上面的配置教程可能学习到VS环境配置的基础知识,配一次大概就懂了

第一课 图像读取与显示

1、这里踩了一个坑,如果openCV下载的是releases版本的,那么imread()无法在VS的Debug模式下读取图片,后面的所有运行都是在VS releases模式下执行。

#include 
#include 
#include 

using namespace cv;
using namespace std;

int main(int argc, char** argv) {
	Mat src = imread("E:/fig/input.jpg"); //B, G, R  openCV导入图片是BGR
	//Mat src = imread("E:/1/2.jfif", IMREAD_GRAYSCALE);//加载灰度图片
	if (src.empty()) {
		printf("could not load image....\n");
		return -1;
	}
	
	//namedWindow("输入窗口", WINDOW_FREERATIO);
	imshow("输入窗口", src);

	waitKey(0);
	destroyAllWindows();
	return 0;
}

第二课 图像色彩空间转换

1、色彩空间转换函数 cvtColor
2、图像的保存

void QuickDemo::colorSpace_Demo(Mat &image) {
	Mat gray, hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);//转hsv
	// H (0 ~ 180), S, V (三通道)
	// H (饱和度),S(),V(亮度)。调颜色可以改H,S。
	cvtColor(image, gray, COLOR_BGR2GRAY);//转灰度
	imshow("HSV", hsv);
	imshow("灰度", gray);
	//imwrite("E:/fig/hsv.png", hsv);
	//imwrite("E:/fig/gray.png", gray);
}

第三课 图像对象的创建与赋值

1、怎么操作mat
2、怎么访问每一个像素点
3、怎么创建一个空图或者mat

Mat的基本结构:头部加数据部分,在进行赋值操作是,是指针会指向同一块Data Block。如果要完全复制一个Mat对象需要使用克隆或者拷贝方法。

OpenCV基础知识_第1张图片

复制,克隆的具体实现。

OpenCV基础知识_第2张图片

void QuickDemo::mat_creation_demo(Mat &image) {
	Mat m1, m2;
	m1 = image.clone();
	image.copyTo(m2);

	// 创建空白图像
	Mat m3 = Mat::zeros(Size(8, 8), CV_8UC1);//CV_8UC1 单通道   CV_8UC3 三通道
	std::cout << m3 << std::endl;

	m3 = Mat::zeros(Size(8, 8), CV_8UC3);//CV_8UC1 单通道   CV_8UC3 三通道
	std::cout << m3 << std::endl;
}

void QuickDemo::mat_creation_demo1() {
	// 创建空白图像
	Mat m3 = Mat::zeros(Size(8, 8), CV_8UC3);//zeros
	std::cout << "width: " << m3.cols << " height: " << m3.rows << " channels: "<channels()<< std::endl;
	std::cout << m3 << std::endl;
	m3 = 127;//只会赋值第一个通道
	std::cout << m3 << std::endl;

	m3 = Scalar(0, 127, 127);//可以指定通道赋值
	std::cout << m3 << std::endl;

	Mat m3_1 = Mat::ones(Size(8, 8), CV_8UC3);//ones只会初始化每个像素点的第一个通道
	std::cout << "width: " << m3_1.cols << " height: " << m3_1.rows << " channels: " << m3_1.channels() << std::endl;
	std::cout << m3_1 << std::endl;
}

void QuickDemo::mat_creation_demo2() {
	// 创建空白图像
	Mat m3 = Mat::zeros(Size(400, 400), CV_8UC3);//单通道
	m3 = Scalar(0, 0, 255);
	imshow("图像1", m3);//纯红色图
	Mat m4 = m3;
	m4 = Scalar(255, 0, 0);
	imshow("图像2", m3);//指向同一个地方,m3变成了蓝色
}

void QuickDemo::mat_creation_demo3() {
	// 创建空白图像
	Mat m3 = Mat::zeros(Size(400, 400), CV_8UC3);//单通道
	m3 = Scalar(0, 0, 255);
	imshow("图像1", m3);//纯红色图
	Mat m4 = m3.clone();
	/*
	Mat m4;
	m3.copyTo(m4);
	*/
	m4 = Scalar(255, 0, 0);
	imshow("图像2", m3);
	imshow("图像3", m4);
}

第四课 图像像素的读写操作

如何遍历和修改每个像素点的数值,分为单通道和多通道。访问模式模式也有两种。第一种是数组访问模式,用最常规的数组下标访问像素值。第二种是指针访问模式,指定一个指针为图片的首地址,通过循环遍历,指针++,一次往后推。

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(row, col);//返回一个int
				image.at(row, col) = 255 - pv;//rgb值取反,改写
			}
			if (dims == 3) { // 彩色图像
				Vec3b bgr = image.at(row, col);//返回一个Vec3b
				image.at(row, col)[0] = 255 - bgr[0];
				image.at(row, col)[1] = 255 - bgr[1];
				image.at(row, col)[2] = 255 - bgr[2];
			}
		}
	}
	
	imshow("像素读写演示", image);
}

void QuickDemo::pixel_visit_demo1(Mat &image) {
	int w = image.cols;
	int h = image.rows;
	int dims = image.channels();

	for (int row = 0; row < h; row++) {
		uchar* current_row = image.ptr(row);//获取指针,字符数组
		for (int col = 0; col < w; col++) {//遍历字符数组,赋值
			if (dims == 1) { // 灰度图像
				int pv = *current_row;
				*current_row++ = 255 - pv;
			}
			if (dims == 3) { // 彩色图像  其实数组长就是3*col,每一个col遍历三次
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
				*current_row++ = 255 - *current_row;
			}
		}
	}
	imshow("像素读写演示", image);
}

第五课  图像像素的算术操作

1、对图像的各个像素点实现加减乘除的操作

void QuickDemo::operators_demo(Mat &image) {
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(5, 5, 5);
	Mat temp;
	multiply(image,Scalar(2,2,2),temp);
	imshow("乘法", temp);

	//add(image,m,dst);
	//divide(image,m,dst);
	//subtract(image, m, dst);
	//imshow("操作", dst);
}

void QuickDemo::operators_demo1(Mat &image) {//自己实现一个加法
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	m = Scalar(5, 5, 5);

	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(row, col);
			Vec3b p2 = m.at(row, col);
			dst.at(row, col)[0] = saturate_cast(p1[0] + p2[0]);
			dst.at(row, col)[1] = saturate_cast(p1[1] + p2[1]);
			dst.at(row, col)[2] = saturate_cast(p1[2] + p2[2]);
		}
	}

	imshow("加法操作", dst);
}

第六课第七课 滚动条操作演示-调整图片亮度&参数传递度

1、实现了图片亮度调节,对比度调节,并加上了进度条。


static void on_track_add(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);
}

static void on_track_sub(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);
	subtract(image, m, dst);
	imshow("亮度调整", dst);
}

void QuickDemo::tracking_bar_demo1(Mat &image) {
	namedWindow("亮度调整", WINDOW_AUTOSIZE);
	int lightness = 50;
	int max_value = 100;
	//createTrackbar("Value Bar:", "亮度调整", &bar_lightness, max_value, on_track_sub);
	//on_track_sub(50,0);
	createTrackbar("Value Bar:", "亮度调整", &lightness, max_value, on_track_add, (void*)(&image));;
	on_track_add(50, &image);
}

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());
	//image第一个原始图片,1.0第一个元素图片的权重,m第二个原始图片,0第二个原始图片的权重,b两个权重之和,dst输出图片
	addWeighted(image, 1.0, m, 0.0, b, dst);//改变gamma(b)
	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);//grmma=0,只调对比度,。   改变alpha(contrast)
	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);
}

第八课 键盘响应操作

1、实现通过键入IO输入控制图片的响应

2、通过键盘输入,在终端得到响应,输入不同的键值,得到不一样的结果。

void QuickDemo::key_demo(Mat &image) {
	Mat dst = Mat::zeros(image.size(), image.type());
	while (true) {
		int c = waitKey(100);
		if (c == 27) { // 退出
			break;
		}
		if (c == 49) { // Key #1 变成灰度  输入1   waitKey返回的就是49
			std::cout << "you enter key # 1 "<< std::endl;
			cvtColor(image, dst, COLOR_BGR2GRAY);
		}
		if (c == 50) { // Key #2 
			std::cout << "you enter key # 2 " << std::endl;
			cvtColor(image, dst, COLOR_BGR2HSV);
		}
		if (c == 51) { // Key #3   加亮度
			std::cout << "you enter key # 3 " << std::endl;
			dst = Scalar(50, 50, 50);
			add(image, dst, dst);
		}
		imshow("键盘响应", dst);
	}
}

第九课 OpenCV自带颜色表操作

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(500);
		if (c == 27) { // 退出
			break;
		}
		applyColorMap(image, dst, colormap[index%19]);
		index++;
		imshow("颜色风格", dst);
	}
}

第十课 图像像素的逻辑操作

1、本节介绍如何对图像的像素进行操作,包括与、或、非、异或,矩形在图像中的绘制。

rectangle(m1,Rect(100,100,80,80),Scalar(255,255,0),-1,LINE_8,0);
这个函数参数1是图片名称,参数2是矩形的起始&末尾位置,参数3 Scalar表示将要绘制图像的颜色,参数4表示小于0表示填充,大于0表示绘制,参数5表示四邻域或者八邻域的绘制,参数6表示中心坐标或者半径坐标的小数位数。

void QuickDemo::bitwise_demo(Mat &image) {
	Mat m1 = Mat::zeros(Size(256, 256), CV_8UC3);
	Mat m2 = Mat::zeros(Size(256, 256), CV_8UC3);
	//thinkness  -1 是填充,大于0是绘制  Scalar 填充的颜色   Rect 图片位置
	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_xor(m1, m2, dst);
	//bitwise_not(m2, dst);
	
	//dst = ~m2;//可读性差
	imshow("像素位操作", dst);
}

第十一课 通道分离与合并

1、本节介绍如何把不同的通道给分离,归并,使得能显现出来不同的通道颜色。

2、M[0],M[1],M[2]分别代表BGR个不同的通道。要开启某个通道只需要关闭另外的一个通道即可。
第二个内容为通道的合并,将不同通道的像素值进行转换操作,使图片呈现出不同的效果。

void QuickDemo::channels_demo(Mat &image) {
	std::vector mv;
	split(image, mv);//分离通道
	//单通道灰图
	imshow("蓝色B", mv[0]);
	imshow("绿色G", mv[1]);
	imshow("红色R", mv[2]);

	Mat dst;
	mv[0] = 0;//第一个通道置为0,蓝色,不展显
	mv[2] = 0;//第三个通道置为0,红色,不展示
	merge(mv, dst);//合并通道
	imshow("绿色", dst);

	int from_to[] = { 0, 2, 1, 1, 2, 0 };//0-2; 1-1; 2-0
	mixChannels(&image, 1, &dst, 1, from_to, 3);//通道转换

	imshow("通道混合", dst);
}

第十二课 图像色彩空间转换

1、本节内容实现任务是提取任务的轮廓,首先把RGB色彩空间的图片转换到HSV空间中,其次,提取图片的mask,通过使用inrangle提取hsv色彩空间的颜色。

2、HSV色彩空间的颜色

OpenCV基础知识_第3张图片

void QuickDemo::inrange_demo(Mat &image) {
	//注意,请使用001.jpg图片
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	//imshow("HSV", hsv);
	//cout << hsv << endl;
	inRange(hsv, Scalar(0, 43, 46), Scalar(180, 255, 255), mask);//蓝色最小值HSV=(100,43,46),最大值HSV=(124,255,255)
	imshow("mask", mask);
}

void QuickDemo::inrange_demo1(Mat &image) {
	//注意,请使用001.jpg图片
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	/*
	OpenCV中的inRange()函数可实现二值化功能(这点类似threshold()函数),
	更关键的是可以同时针对多通道进行操作,使用起来非常方便!
	主要是将在两个阈值内的像素值设置为白色(255),
	而不在阈值区间内的像素值设置为黑色(0),该功能类似于之间所讲的双阈值化操作。
	*/
	inRange(hsv, Scalar(100, 43, 46), Scalar(124, 255, 255), mask);//

	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);//创建一个红色幕
	imshow("幕布", redback);
	imshow("mask1", mask);
	bitwise_not(mask, mask);//取反,黑变成白,白变成黑
	imshow("mask2", mask);
	image.copyTo(redback, mask);//mask中像素不为0(黑色)的点才会copy到redback上,(所以之前要取个反,因为头像部分是黑色)
	imshow("roi区域提取", redback);
}

第十三课 图像像素值统计

1、分别定义双精度型变量 minv和maxv。指针变量minLoc,maxLoc;
2、因为这图片是多通道的,所以使用一个容器装取数值,并且用split分离图片到MV中,通过for循环操作,遍历图片信息,并且打印信息到终端。图像信息包括,方差,均值,大小。

void QuickDemo::pixel_statistic_demo(Mat &image) {
	double minv, maxv;
	Point minLoc, maxLoc;
	std::vector mv;
	split(image, mv);
	for (int i = 0; i < mv.size(); i++) {
		minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());
		std::cout <<"No. channels:"<< i << " min value:" << minv << " max value:" << maxv << std::endl;
	}
	Mat mean, stddev;
	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);
	meanStdDev(redback, mean, stddev);//求均值和方差
	imshow("redback", redback);
	std::cout << "means:" << mean << std::endl;
	std::cout<< " stddev:" << stddev << std::endl;
}

第十四课 图像几何形状绘制

1、介绍如何绘制椭圆,矩形,直线,圆等

void QuickDemo::drawing_demo(Mat &image) {//bgr
	//Rect rect(100, 100, 250, 300);

	Rect rect;
	//位置
	rect.x = 100;
	rect.y = 100;
	//大小
	rect.width = 250;
	rect.height = 300;

	Mat bg = Mat::zeros(image.size(), image.type());
	//矩形
	rectangle(bg, rect, Scalar(0, 0, 255), -1, 8, 0);//thinkness 线宽,如果是负数,那就是填充了
	//圆
	circle(bg, Point(350, 400), 15, Scalar(255, 0, 0), -1, 8, 0);
	//线
	line(bg, Point(100, 100), Point(350, 400), Scalar(0, 255, 0), 4, LINE_AA, 0);//参数2,3,就是对角线的坐标
	
	RotatedRect rrt;//椭圆的规格
	rrt.center = Point(200, 200);//中心位置
	rrt.size = Size(100, 200);
	rrt.angle = 90.0;
	//椭圆
	ellipse(bg, rrt, Scalar(0, 255, 255), 2, 8);
	Mat dst;
	//加起来,按权重加起来
	addWeighted(image, 0.7, bg, 0.3, 0, dst);
	imshow("绘制演示", bg);
}

第十五课 随机数与随机颜色

1、介绍如何能产生一个随机数字和随机颜色,并且用线条的方式显示出来。

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(10);
		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);
		//canvas = Scalar(0, 0, 0);//把之前的清掉
		//随机绘制矩形,圆,椭圆都可以
		line(canvas, Point(x1, y1), Point(x2, y2), Scalar(b, g, r), 1, LINE_AA, 0);
		imshow("随机绘制演示", canvas);
	}
}

第十六课 多边形填充与绘制

1、介绍了2种多边形绘制的实现方式。

2、第一种方式,通过标记各个点,然后存储到容器中,之后对容器中的点进行操作。填充多边形调用fillPoly,绘制多边形调用polylines。第二种方式,使用一个API接口绘制。通过一个容器中的存储的点组成的另一个容器。

void QuickDemo::polyline_drawing_demo() {
	Mat canvas = Mat::zeros(Size(512, 512), CV_8UC3);
	int w = canvas.cols;
	int h = canvas.rows;
	Point p1(100, 100);
	Point p2(300, 150);
	Point p3(300, 350);
	Point p4(250, 450);
	Point p5(50, 450);
	std::vector pts;
	pts.push_back(p1);
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);

	//polylines(canvas, pts, true, Scalar(0, 255, 0), 2, 8, 0);//相当于画折线图
	//fillPoly(canvas, pts, Scalar(255, 0, 255), 8, 0);//填充

	std::vector> contours;
	contours.push_back(pts);//push一个,只有一个多边形
	drawContours(canvas, contours, 0, Scalar(0, 0, 255), -1, 8);

	imshow("绘制多边形", canvas);
}

第十七课 鼠标操作与响应

Point sp(-1, -1);//初始化起始点,(-1,-1)
Point ep(-1, -1);//初始化终结点,(-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);//Rect 类有是个成员变量,这个是直接实例化一个rect类
				temp.copyTo(image);//temp里面保存的最开始的image,每次绘画前,都将temp赋值给image
				Mat roi = image(box);
				imshow("ROI区域", roi);//截取一块ROI区域,新生成
				rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
				imshow("鼠标绘制", image);
				// ready for next drawing
				sp.x = -1;
				sp.y = -1;
				//roi = Scalar(0, 0, 0);
		}
	}
	else if (event == EVENT_MOUSEMOVE) {//鼠标移动。把绘画过程展示出来
		if (sp.x > 0 && sp.y > 0) {//必须是鼠标按下之后(sp.x,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);
				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();
}

第十八课 图像像素类型转换与归一化

OpenCV基础知识_第4张图片

void QuickDemo::norm_demo(Mat &image) {
	Mat dst;
	std::cout << image.type() << std::endl;//16 CV_8UC3  八位3通道
	image.convertTo(image, CV_32F);//转化成CV_32FC3类型   单通道,每通道都是32位浮点数
	std::cout << image.type() << std::endl;//21 
	normalize(image, dst, 1.0, 0, NORM_MINMAX);//变成浮点数类型后,一定要归一化,不然显示有问题

	//转回去,乘以255,就行,然后转CV_8UC3

	std::cout << dst.type() << std::endl;//21
	imshow("图像数据归一化", dst);
	// CV_8UC3, CV_32FC3
}

第十九课 图像放缩与插值

void QuickDemo::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);
}

第二十课 图像翻转

void QuickDemo::flip_demo(Mat &image) {
	Mat dst;
	// flip(image, dst, 0); // 上下翻转 0 
	// flip(image, dst, 1); // 左右翻转 1
	flip(image, dst, -1); // 180°旋转  -1
	imshow("图像翻转", dst);
}

第二十一课 图像旋转

1、本节课主要介绍了翻转图像的指定角度,之后,确定得到新的图像信息,长宽也发生改变。

2、 图片旋转函数warpAffine()。

M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);//得到旋转矩阵M(如下图)。

图中:cos = M(0,0),sin = M(0,1)。图片中心点:(M(0,2),M(1,2)) 

旋转后的长宽:(w*cos+h*sin,  w*sin+h*cos)

OpenCV基础知识_第5张图片

void QuickDemo::rotate_demo(Mat &image) {
	Mat dst, M;
	int w = image.cols;
	int h = image.rows;
	//w/2, h/2 得到中心点
	M = getRotationMatrix2D(Point2f(w / 2, h / 2), 45, 1.0);//得到旋转矩阵M
	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, 255, 0));
	imshow("旋转演示", dst);
}

第二十二课和第二十三课 视频文件摄像头使用 & 视频处理与保存

1、介绍了如何读取一个视频,以及调用电脑的摄像头。并且对读取到的视频进行操作。

void QuickDemo::video_demo1(Mat &image) {
	VideoCapture capture("C:/Users/WS/Videos/Captures/001.mp4");
	Mat frame;
	while (true) {
		capture.read(frame);
		//flip(frame, frame, 1);//图片翻转
		if (frame.empty()) {
			break;
		}
		//namedWindow("frame", WINDOW_FREERATIO);
		colorSpace_Demo(frame);
		imshow("frame", frame);
		int c = waitKey(1);
		if (c == 27) {
			break;
		}
	}
	capture.release();
}

void QuickDemo::video_demo(Mat &image) {
	VideoCapture capture("C:/Users/WS/Videos/Captures/001.mp4");
	// frame 一针
	int frame_width = capture.get(CAP_PROP_FRAME_WIDTH);//frame的宽度
	int frame_height = capture.get(CAP_PROP_FRAME_HEIGHT);//高度
	int count = capture.get(CAP_PROP_FRAME_COUNT);//总针数   
	double fps = capture.get(CAP_PROP_FPS);//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(1);
		if (c == 27) { // 退出
			break;
		}
	}

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

第二十四课 图像直方图

1、视频的属性,SD(标清),HD(高清),UHD(超清),蓝光。如何读取视频文件,以及读取视频文件的属性,衡量视频处理指标:FPS。保存视频时的编码格式。保存视频的实际size和create的size大小保持一致。

2、横坐标时像素值,纵坐标统计数量,但是直方图丢失了空间信息,只有图像的像素值信息。

OpenCV基础知识_第6张图片

OpenCV基础知识_第7张图片

void QuickDemo::histogram_demo(Mat &image) {
	// 三通道分离
	std::vector 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);//bins表示坐标轴上面,直方图数组size,换句话说就是横坐标上面有bins个刻度
	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;//纵坐标总长度
	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++) {
		//幕布上起始点Point(bin_w*(i - 1), hist_h - cvRound(b_hist.at(i - 1)))
		//bin_w*(i - 1) 起始点x     (i-1)第几个   bin_w:每个多宽, 然后乘起来
		//屏幕左上角是(0,0)。hist_h 减去,得到一个负数,这才是这条线的起始点
		//幕布上终止点Point(bin_w*(i), hist_h - cvRound(b_hist.at(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);
}

第二十五课 二维直方图

1、直方图是图像的统计学特征。表示了图像的各个像素在0-255出现的频率。图像的平移旋转都不会对性质进行改变。缺点:不能表征一张图像。

void QuickDemo::histogram_2d_demo(Mat &image) {
	// 2D 直方图
	Mat hsv, hs_hist;
	cvtColor(image, hsv, COLOR_BGR2HSV);//H:0-180   S:0-255   V:0-255
	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 };//前两个通道
	//二维的,所以hist_bins 也是二维
	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);
}

第二十六课 直方图均衡化

1、用途:用于图像增强,人脸检测,卫星遥感。均衡化的图像只支持单通道。

 2、分为8个级别,将所有像素规约到这8个级别上,规约方式如下图,5,6,7(共有245+122+81个)都被规约到最高级别上去了,均衡化后他们的像素一样。

OpenCV基础知识_第8张图片

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

第二十七课 图像卷积操作

1、卷积的作用,高的往下降,低的往上升。但是会造成信息丢失。产生模糊效果。是一种线性操作,点乘,之后相加。

线性卷积:(12*1+12*1+14*1+2*1+4*1+6*1+6*1+8*1+10*1)/9 =(取整)8

 OpenCV基础知识_第9张图片

void QuickDemo::blur_demo(Mat &image) {
	//模糊操作的实现就是通过卷积操作
	Mat dst;
	blur(image, dst, Size(15, 15), Point(-1, -1));//第三个参数就是卷积核的大小
	imshow("图像模糊", dst);
}

第二十八课 高斯模糊

1、高斯卷积数学表达式说明,中心的数值最大,离中心距离越远,数值越小。

OpenCV基础知识_第10张图片

OpenCV基础知识_第11张图片

void QuickDemo::gaussian_blur_demo(Mat &image) {
	Mat dst;
	GaussianBlur(image, dst, Size(0, 0), 5);//size(0,0)  一般最好是基数,设置0就是不设定卷积核大小,通过sigma去控制模糊程度
	imshow("高斯模糊", dst);
}

第二十九课 高斯双边模糊

 1、抑制噪声,差异越大越保留,本来粗糙的就变得圆滑。

OpenCV基础知识_第12张图片

void QuickDemo::bifilter_demo(Mat &image) {
	Mat dst;
	bilateralFilter(image, dst, 0, 100, 10);
	imshow("双边模糊", dst);
}

第三十课 实时人脸检测

openCV中自带人脸检测模型,去OpenCV安装路径下比如:D:/opencv/sources/samples/dnn/face_detector下查看是否有opencv_face_detector_uint8.pb和root_dir+"opencv_face_detector.pbtxt文件,如果没有可以去下载。

资源文件下载

void QuickDemo::face_detection_demo() {
	std::string root_dir = "D:/opencv/sources/samples/dnn/face_detector/face_download/";
	dnn::Net net = dnn::readNetFromTensorflow(root_dir+ "opencv_face_detector_uint8.pb", root_dir+"opencv_face_detector.pbtxt");
	VideoCapture capture("C:/Users/WS/Videos/Captures/002.mp4");
	Mat frame;
	while (true) {
		capture.read(frame);
		if (frame.empty()) {
			break;
		}
		Mat blob = dnn::blobFromImage(frame, 1.0, Size(300, 300), Scalar(104, 177, 123), false, false);
		net.setInput(blob);// N C H W 数量,通道数,高度,宽度
		Mat probs = net.forward(); // 
		Mat detectionMat(probs.size[2], probs.size[3], CV_32F, probs.ptr<float>());
		// 解析结果
		for (int i = 0; i < detectionMat.rows; i++) {
			float confidence = detectionMat.at<float>(i, 2);
			if (confidence > 0.5) {//大于0.5 说明是人脸
				//找到矩形的四个点
				int x1 = static_cast<int>(detectionMat.at<float>(i, 3)*frame.cols);
				int y1 = static_cast<int>(detectionMat.at<float>(i, 4)*frame.rows);
				int x2 = static_cast<int>(detectionMat.at<float>(i, 5)*frame.cols);
				int y2 = static_cast<int>(detectionMat.at<float>(i, 6)*frame.rows);
				Rect box(x1, y1, x2 - x1, y2 - y1);//四个参数分别是  起始点,宽高
				rectangle(frame, box, Scalar(0, 0, 255), 2, 8, 0);//画出来
			}
		}
		imshow("人脸检测演示", frame);
		int c = waitKey(1);
		if (c == 27) { // 退出
			break;
		}
	}
}

你可能感兴趣的:(openCV,c++,opencv)