opencv4.0学习笔记

2023-05-16

目录

课程来源:哔哩哔哩大学.

第一节课

显示第一张图片

环境配置了一个早上,到10.48分配置完毕,有点难受。还好最后显示出第一张图片。

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

using namespace std;
using namespace cv;
int main() 
{

	Mat src = imread("D:/images/011.jpg",IMREAD_GRAYSCALE);//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
	if (src.empty()) 
	{
		printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
	}
	//超过屏幕的图像无法显示时候调用此函数。
	namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat 
	waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
	destroyAllWindows();//销毁前面创建的显示窗口
	return 0;
}

第一节课小结

第一节课介绍了如何读取第一张图片,并且显示出来,通过调用imread函数读取照片,再调用imshow显示图片到窗口。同时,讲述了如何打印灰度图像,图片读取失败的处理方式,代码注释详细介绍了每条语句的意思。

第二节课

显示第一张图片

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

#include<opencv2/opencv.hpp>
using namespace cv;

class QuickDemo //创建一个QuickDemo对象
{
	public:
		void colorSpace_Demo(Mat &imge); //定义一个类,里面包含输入一个图片,对图片操作
};

#include<quickopencv.h>
void QuickDemo::colorSpace_Demo(Mat &image)
{
	Mat gray, hsv;//定义2个矩阵类的图像gray和hsv,
	cvtColor(image,hsv,COLOR_BGR2HSV);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型
	cvtColor(image,gray,COLOR_BGR2GRAY);//图像转换函数,可以把image转成hsv,第三个参数是转成的类型
	imshow("HSV",hsv);
	imshow("灰度",gray);
	imwrite("D:/hsv.jpg",hsv);//保存图片,前面是保存图的地址,后面是保存图的名称
	imwrite("D:/gray.jpg",gray);
}

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

using namespace std;
using namespace cv;
int main() 
{

	Mat src = imread("D:/images/1.jpg",IMREAD_ANYCOLOR);//B,G,R实际上0-255三色。3通道
	//读取进来的数据以矩阵的形势,第二个参数代表显示一张灰度图像。
	if (src.empty()) 
	{
		printf("could not load image");//如果图片不存在 将无法读取,打印到终端。
		return -1;
	}
	//超过屏幕的图像无法显示时候调用此函数。
	
	namedWindow("输入窗口", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("输入窗口", src);//表示显示在新创建的输入窗口上,第一个参数表示窗口名称,src表示数据对象Mat 
//在主函数中调用之前创建的类对象	
	QuickDemo qd;
	qd.colorSpace_Demo(src);

	waitKey(0);//执行到这句,程序阻塞。参数表示延时时间。单位ms
	destroyAllWindows();//销毁前面创建的显示窗口
	return 0;
}

第二节课小结

这节主要介绍了创建一个类对象,然后通过类对象调用函数,在main主函数中进行调用实现类对象中的功能,比如转换成HSV类型图片和GRAY类型图片,最后通过imwrite函数进行图像的保存。

第三节课

图像对象的创建与赋值

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

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

	//创建空白图像
	Mat m3 = Mat::ones(Size(400, 400), CV_8UC3);//创建8*8的CV8位的无符号的n通道的unsigned char
	//ones&zeros是初始化的方法
	m3 = Scalar(255, 0, 0);//给三个通道都赋值127  ,单通道赋值方法 m3 = 127;
	//m3初始为蓝色
	//数据的宽度和长度是由通道数决定的。
	//std::cout << "width:"<<m3.cols<<"height"<< m3.rows <<"channels"<<m3.channels()<< std::endl;
	//用来查看宽度,高度与通道数。
	/*std::cout << m3 << std::endl;*/
	Mat m4 = m3.clone();//赋值M4就是M3 M4改变了,M3也改变了,没有产生新的自我(M4与M3同体)
	//M4为M3的克隆,M3还是原来的颜色,不会改变。(M4与M3不同体,各自是各自的颜色)
	//m3.copyTo(m4);//把M3赋值给M4,M4就是蓝色
	m4 = Scalar(0, 255, 255);//改变m4的颜色为黄色 ,m4也改变
	imshow("图像3", m3);//标题和图像名称   显示图像m3 纯蓝色
	imshow("图像4", m4);//标题和图像名称
}

第三节课小结

本节课介绍了如何创建一个Mat对象,通过创建新的Mat对象来创建用户的特定的底色画布,创建图像的基本类型有两种一种是ones一种是zeros,ones()中的第一个参数代表图像的大小,第二个参数代表创建几维的图像,UC代表无符号字符型,数组3代表通道数。克隆和赋值的区别,克隆就是产生一个新的对象,新对象改变属性,旧对象属性不变(各自为政)。赋值是二者同体,当新属性发生改变,旧属性也发生改变(二者同体)。

第四节课

图像像素的读写操作

如何遍历和修改每个像素点的数值,分为单通道和多通道。访问模式模式也有两种。第一种是数组访问模式,用最常规的数组下标访问像素值。

void QuickDemo::pixel_visit_demo(Mat &image)
{
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	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); //opencv特定的类型,获取三维颜色,3个值
				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];//对彩色图像读取它的像素值,并且对像素值进行改写。
			}
		}
	}
	namedWindow("像素读写演示", WINDOW_FREERATIO);
	imshow("像素读写演示", image);
}

第二种为指针访问模式,指定一个指针为图片的首地址,通过循环遍历,指针++,一次往后推。

void QuickDemo::pixel_visit_demo(Mat &image)
{
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	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;
			}
		}
	}
	namedWindow("像素读写演示", WINDOW_FREERATIO);
	imshow("像素读写演示", image);
	
}

第四节课小结

本节主要介绍了通过两种遍历的方式访问图像的像素值,并且改变图像的像素值。

第五节课

图像像素的操作

对图像的各个像素点实现加减乘除的操作。介绍了常用的除爆函数saturate_cast,防止数值过界。

void QuickDemo::operators_demo(Mat &image)
{
	Mat dst = Mat::zeros(image.size(), image.type());
	Mat m = Mat::zeros(image.size(), image.type());
	dst = image - Scalar(50, 50, 50);
	m = Scalar(50, 50, 50);
	multiply(image,m,dst);//乘法操作 api
	imshow("乘法操作", dst);
	add(image, m, dst);//加法操作 api
	imshow("加法操作", dst);
	subtract(image, m, dst);//减法操作 api
	imshow("减法操作", dst);
	divide(image, m, dst);//除法操作 api
	namedWindow("加法操作", WINDOW_FREERATIO);
	imshow("加法操作", dst);
	//加法操作底层
	int dims = image.channels();
	int h = image.rows;
	int w = image.cols;
	for (int row = 0; row < h; row++)
	{
		for (int col = 0; col < w; col++)
		{
				Vec3b p1 = image.at<Vec3b>(row, col); //opencv特定的类型,获取三维颜色,3个值
				Vec3b p2 = m.at<Vec3b>(row, col);
				dst.at<Vec3b>(row, col)[0] = saturate_cast<uchar>(p1[0]	+ p2[0]);//saturate_cast用来防爆,小于0就是0,大于255就是255
				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]);//对彩色图像读取它的像素值,并且对像素值进行改写。
		}
	}
	imshow("加法操作", dst);
}

第五节课小结

介绍了四种不同的API实现,并且演示了一种加法的算法。

第六节课

滚动条演示操作-调整图片亮度

本节介绍怎么通过createTrackbar来设置一个进度条,实现图片的亮度调节。

Mat  src, dst, m;
int lightness = 50;//定义初始的亮度为50
static void on_track(int ,void*) 
{
	m = Scalar(lightness,lightness,lightness);//创建调整亮度的数值
	subtract(src, m, dst);//定义亮度变化为减
	imshow("亮度调整", dst);//显示调整亮度之后的图片
}
void QuickDemo::tracking_bar_demo(Mat &image)
{
	namedWindow("亮度调整",WINDOW_AUTOSIZE);
	dst = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
	m = Mat::zeros(image.size(), image.type());//图片的初始化创建一个和image大小相等,种类相同的图像
	src = image;//给src赋值
	int max_value = 100;//定义最大值为100
	createTrackbar("Value Bar:", "亮度调整", &lightness, max_value,on_track);//调用函数实现功能。
	on_track(50, 0);
}

第七节课

滚动条演示操作-传递参数

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());
	m = Scalar(b,b,b);
	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);
}

第七节课小结

第八节课

键盘响应操作

本节介绍通过键盘输入,终端能够读取响应的信息。

void QuickDemo::key_demo(Mat &image) 
{
	Mat dst= Mat::zeros(image.size(), image.type());
	while (true) 
	{
		char c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
		if (c == 49)//key#1
		{
			std::cout <<"you enter key #1" << std::endl;
			cvtColor(image, dst, COLOR_BGR2GRAY);
		}
		if (c == 50)//key#1
		{
			std::cout << "you enter key #2"  << std::endl;
			cvtColor(image, dst, COLOR_BGR2HSV);
		}
		if (c == 51)//key#1
		{
			std::cout << "you enter key #3" << std::endl;
			dst = Scalar(50, 50, 50);
			add(image,dst,dst);
		}
		imshow("键盘响应",dst);
		std::cout << c << std::endl;
	}
}

第八节课小结

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

第九节课

opencv自带颜色操作

void QuickDemo::color_style_demo(Mat &image) 
{
	int colormap[] = {
		COLORMAP_AUTUMN ,
		COLORMAP_BONE,
		COLORMAP_CIVIDIS,
		COLORMAP_DEEPGREEN,
		COLORMAP_HOT,
		COLORMAP_HSV,
		COLORMAP_INFERNO,
		COLORMAP_JET,
		COLORMAP_MAGMA,
		COLORMAP_OCEAN,
		COLORMAP_PINK,
		COLORMAP_PARULA,
		COLORMAP_RAINBOW,
		COLORMAP_SPRING,
		COLORMAP_TWILIGHT,
		COLORMAP_TURBO,
		COLORMAP_TWILIGHT,
		COLORMAP_VIRIDIS,
		COLORMAP_TWILIGHT_SHIFTED,
		COLORMAP_WINTER
	};
	
	Mat dst;
	int index = 0;
	while (true) 
	{
		char c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
		if (c == 49)//key#1 按下按键1时,保存图片到指定位置
		{
			std::cout << "you enter key #1" << std::endl;
			imwrite("D:/gray.jpg", dst);
		}
		applyColorMap(image, dst, colormap[index%19]);//循环展示19种图片
		index++;
		imshow("循环播放", dst);
	}
}

第十节课

图像像素的逻辑操作

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

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);//小于0表示填充,大于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);
}

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::channels_demo(Mat &image)
{	
	std::vector<Mat>mv;
	split(image, mv);
	//imshow("蓝色", mv[0]);
	//0,1,2三个通道分别代表BGR。
	//关闭2个通道意味着开启一个通道。
	//imshow("绿色", mv[1]);
	//imshow("红色", mv[2]);
	Mat dst;
	mv[0] = 0;
	mv[2] = 0;
	merge(mv, dst);
	imshow("蓝色", dst);
	int from_to[] = { 0,2,1,1,2,0 };
	//把通道相互交换,第0->第2,第一->第一,第二->第0
	mixChannels(&image,1,&dst,1,from_to,3);//3表示3个通道
	//参数1指针引用图像->参数2引用到dst
	imshow("通道混合", dst);
}

第十一节课小结

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

第十二节课

图像色彩空间转换

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

HSV色彩空间的颜色
在这里插入图片描述

void QuickDemo::inrange_demo(Mat &image)
{
	Mat hsv;
	cvtColor(image, hsv, COLOR_BGR2HSV);
	Mat mask;
	inRange(hsv,Scalar(35,43,46),Scalar(77,255,255),mask);
	//35,43,46根据图片中绿色最低来确定最小值。
	//77,255,255 提取
	//参数1低范围,参数2高范围
	//将hsv中的由低到高的像素点提取出来并且存储到mask当中。
	imshow("mask",hsv);
	Mat redback = Mat::zeros(image.size(), image.type());
	redback = Scalar(40, 40, 200);
	bitwise_not(mask, mask);
	imshow("mask", mask);
	image.copyTo(redback, mask);//把redback复制到mask,mask通过inRange得到。
	imshow("roi区域提取", redback);
}

第十三节课

图像像素值统计

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

void QuickDemo::pixel_statistic_demo(Mat &image)
{
	double minv, maxv;//定义最值
	Point minLoc, maxLoc;//定义最值地址
	std::vector<Mat>mv;//mv是一个Mat类型的容器 装在这个容器内
	split(image, mv);
	for (int i = 0; i < mv.size(); i++) 
	{
		//分别打印各个通道的数值
		minMaxLoc(mv[i], &minv, &maxv, &minLoc, &maxLoc, Mat());//求出图像的最大值和最小值。
		std::cout <<"No.channels:"<<i<<"minvalue:" << minv << "maxvalue:" << maxv << std::endl;
	}
	Mat mean, stddev;
	meanStdDev(image, mean, stddev);//求出图像的均值和方差
	std::cout << "mean:" << mean << std::endl;
	std::cout << "stddev:" << stddev << std::endl;
}

第十三节课小结

第十四节课

图像几何形状的绘制

本节课介绍如何绘制椭圆,矩形,直线,圆等

void QuickDemo::drawing_demo(Mat &image)
{
	Rect rect;
	rect.x = 200;
	rect.y = 200;
	rect.width = 100;
	rect.height = 100;
	Mat bg = Mat::zeros(image.size(),image.type());
	rectangle(image, rect, Scalar(0, 0, 255), -1, 8, 0);
	//参数1为绘图的底图或者画布名称,参数2位图片的起始,宽度,高度
	//参数3代表填充颜色。参数4大于0是线小于0是填充
	//参数5表示邻域填充,参数6默认值为0
	circle(bg, Point(350, 400), 15, Scalar(0, 0, 255), 2, LINE_AA, 0);
	//参数2位图片中心位置,参数3为半径为15的圆
	Mat dst;
	//addWeighted(image, 0.7, bg, 0.3, 0, dst);
	RotatedRect rtt;
	rtt.center = Point(200, 200);
	rtt.size = Size(100, 200);
	rtt.angle = 0.0;
	line(bg,Point(100,100),Point(350,400), Scalar(0, 0, 255), 8, LINE_AA, 0);//line_AA表示去掉锯齿
	ellipse(bg,rtt, Scalar(0, 0, 255), 2, 8);
	imshow("矩形的绘制",bg);
}

第十四节课小结

第十五节课

随机数与随机颜色

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

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,canvas.cols);
		int y1 = rng.uniform(0, h);
		int x2 = rng.uniform(0, canvas.cols);
		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), 8, LINE_AA,0);//line_AA表示去掉锯齿	
		imshow("随机绘制演示", canvas);
	}
}

第十五节课小结

第十六节课

多边形填充与绘制

这节课介绍了2种多边形绘制的实现方式。

void QuickDemo::polyline_drawing_demo(Mat &image)
{
	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);
	std::vector<Point>pts;//将5个点装入一个容器内。
	pts.push_back(p1);//未初始化数组容量,只能用pushback操作
					  //如果初始化,可以用数组下标操作。
	pts.push_back(p2);
	pts.push_back(p3);
	pts.push_back(p4);
	pts.push_back(p5);
	//fillPoly(canvas, pts, Scalar(122, 155, 255), 8, 0);//填充多边形
	//polylines(canvas, pts, true, Scalar(0, 0, 255), 2, 8, 0);//绘制多边形
	/*
	参数1表示画布,参数2表示点集,参数3表示true,参数4颜色
	参数5表示线宽,参数6表示渲染方式,参数7表示相对左上角(0,0)的位置
	*/
	//单个API搞定图片的绘制填充
	std::vector<std::vector<Point>>contours;
	contours.push_back(pts);
	drawContours(canvas,contours,-1, Scalar(0, 0, 255),-1);
	//参数2表示容器名称,参数3为正表示多边形的绘制,为负表示多边形的填充
	imshow("多边形绘制", canvas);
}

第十六节课小结

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

第十七节课

鼠标操作与响应

//参数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);
			imshow("ROI区域", image(box));
			rectangle(image, box, Scalar(0, 0, 255), 2, 8, 0);
			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)
			{
				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));
	//设置窗口的回调函数。参数1表示名称,参数2表示调用on_draw
	imshow("鼠标绘制", image);
	temp = image.clone();
}

第十七节课小结

第十八节课

图像像素类型的转换与归一化

void QuickDemo::norm_demo(Mat &image)
{
	Mat dst;//定义一个名为dst的二值化类型的数据
	std::cout << image.type() << std::endl;//打印出来图片的类型
	image.convertTo(image,CV_32F);//将dst数据转换成浮点型float32位数据。
	std::cout << image.type() << std::endl;//再次打印转换后的数据类型
	normalize(image, dst, 1.0, 0, NORM_MINMAX);//进行归一化操作
	std::cout << dst.type() << std::endl;//打印归一化操作之后的数据
	imshow("图像的归一化", dst);//显示归一化的图像
	//CV_8UC3 ,CV_32FC3  //3通道每个通道8位的UC类型
	//转换后 3通道 每个通道32位的浮点数
}

第十八节课小结

第十九节课

图像的放缩与差值

介绍基本的图像变换大小的方法。图像的差值处理主要有线性、双线性差值、卢卡斯差值、双立方差值。

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("zoomin", zoomout);//
}

第二十节课

图像的旋转

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

第二十节课小结

第二十一节课

图像的翻转

本节课主要介绍了翻转图像的指定角度,之后,确定得到新的图像信息,长宽也发生改变。
在这里插入图片描述

void QuickDemo::rotate_demo(Mat &image)
{
	Mat dst, M;
	int h = image.rows;//定义图片的高度
	int w = image.cols;//定义图片的宽度
	M = getRotationMatrix2D(Point(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);
	//参数1原来图像的中心位置。参数2角度是多少。参数3是图像本身大小的放大缩小
	warpAffine(image, dst, M,Size(nw,nh),INTER_LINEAR,0, Scalar(0, 0, 255));
	imshow("旋转演示", dst);
}

第二十一节课小结

第二十二节课

视频文件摄像头使用

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

void QuickDemo::video_demo(Mat &image) 
{
	VideoCapture capture("D:/images/123.mp4");  //读取视频的地址
	Mat frame;//定义一个二值化的 frame
	
	while (true)
	{
		capture.read(frame); //读取视频
		//flip(frame, frame, 1);//图像镜像操作
		if(frame.empty())//如果视频为空的话 跳出操作
		{
			break;
		}
		imshow("frame", frame);//显示视频
		colorSpace_Demo(frame);//对视频调用之前的demo
		int c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
	}
	capture.release();//释放相机的资源
}

第二十三节课小结

对读取到的视频 操作方式有镜像对称。加各种滤镜等等。

第二十四节课

视频处理与保存

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

void QuickDemo::video_demo(Mat &image) 
{
	VideoCapture capture("D:/images/123.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);//视频总的帧数
	//fps是衡量处理视频的能力
	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 << "frame FPS" << fps << std::endl;
	std::cout << "frame count" << count << std::endl;
	VideoWriter writer("D:/test.mp4",capture.get(CAP_PROP_FOURCC),fps,Size(frame_width, frame_height),true);
	//参数1 保存地址。参数2 获取图片的格式 参数3 图片的帧数 参数4 视频宽高 参数5 真
	Mat frame;
	while (true)
	{
		capture.read(frame);
		//flip(frame, frame, 1);//图像镜像操作
		if(frame.empty())
		{
			break;
		}
		imshow("frame", frame);
		colorSpace_Demo(frame);
		writer.write(frame);

		int c = waitKey(100);//停顿100ms 做视频处理都是1
		if (c == 27) { //esc 退出应用程序
			break;
		}
	}
	capture.release();//释放相机的资源
	writer.release();//释放存放的资源
}

第二十四节课小结

本节课,介绍了视频的一些基本熟悉,紧接介绍如何获取视频的属性,并且通过特定的格式保存到相应的存储位置上。

第二十五节课

图像的直方图

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

第二十六节课

直方图的均衡化

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

void QuickDemo::histogram_eq_demo(Mat &image)
{
	Mat gray;
	cvtColor(image, gray, COLOR_BGR2GRAY);
	//直方图均衡化只支持灰度图像,不支持彩色图像。
	imshow("灰度图像", gray);
	Mat dst;
	equalizeHist(gray, dst);
	imshow("直方图均衡化", dst);
}

第二十六节课小结

第二十七节课

图像的卷积操作

卷积的作用,高的往下降,低的往上升。但是会造成信息丢失。产生模糊效果。是一种线性操作,点乘,之后相加。
在这里插入图片描述

void QuickDemo::blur_demo(Mat &image)
{
	Mat dst;
	blur(image, dst, Size(15, 15), Point(-1, -1));
	//参数1原始图像,参数2卷积之后的图像,参数3卷积的矩阵大小,支持单行或者单列的卷积操作,参数4卷积的起始点。
	imshow("图像卷积操作", dst);
}

第二十七节课小结

第二十八节课

高斯模糊

中心的数值最大,离中心距离越远,数值越小。
高斯卷积数学表达式说明:
在这里插入图片描述高斯卷积的图像说明:
在这里插入图片描述

void QuickDemo::gaussian_blur_demo(Mat &image)
{
	Mat dst;
	GaussianBlur(image, dst, Size(5, 5), 15);
	imshow("高斯模糊", dst);
	//参数1表示初始图像,参数2表示处理后的图像,参数3表示高斯矩阵大小 正数而且是奇数,
	//参数4表示西格玛x为15 西格玛y为15 
}

第二十九节课

高斯双边模糊

在这里插入图片描述

void QuickDemo::bifilter_demo(Mat &image)
{
	Mat dst;
	bilateralFilter(image,dst,0,100,0);
	//参数1代表原图,参数2代表处理之后的图像,参数3色彩空间。参数4表示坐标空间,双边是指 色彩空间和坐标空间。
	namedWindow("双边模糊", WINDOW_FREERATIO);//创建了一个新窗口,参数1表示名称,第二个参数代表一个自由的比例
	imshow("双边模糊", dst);//表示显示在新创建的
}

完结~

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

opencv4.0学习笔记 的相关文章

  • vector用法

    介绍 1 vector是表示可变大小数组的序列容器 2 就像数组一样 xff0c vector也采用的连续存储空间来存储元素 也就是意味着可以采用下标对vector的元素进行访问 xff0c 和数组一样高效 但是又不像数组 xff0c 它的
  • AAC 音频编码保存和解码播放

    一 编码器 MediaCodec MediaCodec 是 Android 提供的用于对音频进行编解码的类 xff0c 属于硬编解 MediaCodec 在编解码的过程中使用了一组缓冲区来处理数据 如下图所示 基本使用流程如下 xff1a
  • Camera 视频采集,H264 编码保存

    一 前言 上篇文章 AAC 音频编码保存和解码播放 讲述了通过 AudioRecord 录制音频数据 xff0c 并通过 AAC 编码保存为 AAC 文件 这里的 aac 既是一种编码方式 xff0c 也是一种容器 xff0c 因此可以直接
  • 基于Camera、AudioRecord 、MediaCodec 和 MediaMuxer 录制 MP4

    一 前言 在 AAC 音频编码保存和解码播放和Camera 视频采集 xff0c H264 编码保存 两篇文章中介绍了如何通过 AudioRecord 和 MediaCodec 录制 AAC 音频以及如何通过 Camera 和 MediaC
  • 基于 SurfaceView、AudioTrack、MediaCodec 和 MediaExtractor 解码 MP4 播放

    一 前言 上篇文章介绍了 基于Camera AudioRecord MediaCodec 和 MediaMuxer 录制 MP4 录制的过程是这样的 xff0c 那么相应的播放过程就是上述过程的逆过程 xff0c 本篇文章将介绍如何通过 M
  • 研发、运营必备实用工具网站

    目录 1 搜索引擎 2 PPT 3 图片操作 4 文件共享 5 招聘求职 6 程序员面试题库 7 办公 开发软件 8 高清图片 视频素材网站 9 项目开源 10 算法 11 在线工具宝典大全 12 音乐 13 神辅助工具 14 语音处理 1
  • 让人“眼前一亮、不明觉厉”的互联网技术PPT

    目录 1 互联网 1 1 智能 43 1 2 云计算 1 3 5G 2 大数据 2 1 用户画像 2 2 边缘计算 2 3 工业大数据 2 4 医疗大数据 2 5 数据平台 2 6 银行大数据 3 物联网 3 1 物联网产业 3 2 工业物
  • 基于FPGA的电梯控制系统设计

    在本项目中一共分为了五个模块 xff1a 时钟分频 按键消抖 状态控制 蜂鸣 译码显示及流水指示灯 其模块的作用分别是 xff1a 时钟分频 xff1a 将高频率系统时钟通过分频得到不同合适频率的时钟频率作为不同模块的输入时钟 clk xf
  • 【流媒体视频监控平台开发wvp-GB28181-pro】

    wvp GB28181 pro学习心得 wvp与GB28181介绍1 流媒体服务器视频协议介绍2 市面上的流媒体服务器3 wvp GB28181 pro框架需要学习的框架和工具4 工具准备项目整合和配置 wvp与GB28181介绍 学习原因
  • gazebo创建机器人模型06

    gazebo创建机器人模型05 kinect 信息仿真以及显示 kinect摄像头仿真基本流程 xff1a 1 已经创建完毕的机器人模型 xff0c 编写一个单独的 xacro 文件 xff0c 为机器人模型添加 kinect 摄像头配置
  • 【C++】C++中防止头文件重复包含的两种方法

    文章目录 01 错误分析 xff1a 类型重定义 xff08 头文件重复包含 xff09 02 解决方案2 1 微软宏2 2 条件编译2 3 两种方法比较 03 变量被重复包含3 1 解决办法 04 版权声明 amp 总结 01 错误分析
  • C/C++程序员应聘常见面试题深入剖析

    1 引言 本文的写作目的并不在于提供C C 43 43 程序员求职面试指导 xff0c 而旨在从技术上分析面试题的内涵 文中的大多数面试题来自各大论坛 xff0c 部分试题解答也参考了网友的意见 许多面试题看似简单 xff0c 却需要深厚的
  • Nvidia jetson tx2 详细安装、配置教程以及固定ip

    jetson tx2 是什么 一 硬件组装 xff1a 1 将 Wi Fi 天线插上 xff0c 组装好充电器即可 2 接口介绍 xff1a USB接口只有一个 xff08 建议使用USB拓展 xff0c 方便前期配置的时候连接键盘鼠标 x
  • C语言 用指针实现字符串函数 strlen strcpy strcat strcmp

    目录 一 指针模拟实现strlen 函数 1 strlen 函数description 2 用指针实现且将strlen封装 3 运行结果 二 指针模拟实现strcpy 函数 1 strcpy 函数description 2 用指针实现且将s
  • 常用器件介绍

    常用器件介绍 这篇文章主要介绍一些在做电子设计时最最常见的器件 xff0c 针对的是完全的小白们 面包板 首先是搭建设计电路用的面包板 面包板正面图 背面拆解图 面包板是专为电子电路的无焊接实验设计制造的 xff0c 上面有很多小插孔 各种
  • VScode代码格式化解决方案c/c++

    前贴链接 xff1a https tieba baidu com p 7891213649 之前说过研究出来了会和大家分享一下自己是如何解决的 xff0c 于是就有了此贴 首先要说明 xff0c 本文主要是针对c c 43 43 xff0c
  • C语言输入和输出

    文章目录 一 数据输入二 数据输出三 断章取义四 printf输出1 输出描述性的文字2 输出整数3 输出字符4 输出浮点数5 输出字符串6 输出多个内容7 示例 xff08 book12 c xff09 五 scanf输入1 输入整数2
  • c 和 python语法 对比

    直接干货 xff1a 先稍微了解两种语言的基本不同 pythonc执行方式无需手动编译 xff0c 执行时按行读取 xff0c 自动编译成字节码 所以python可轻易被获取源码需要手动进行编译生成机器可直接执行的机器码内存管理有自己的垃圾
  • 删除typora图片目录下失效的图片脚本

    背景 xff1a md中插入图片与word不同 xff0c 在word中图片是拷贝了一份放在文件中 xff0c 与原图片无关 xff0c 所以无论删除哪个互不影响 xff0c 但是md中却不同 xff0c md中插入图片时用超链接的方式从外
  • scanf中‘\n‘的用法和隐患

    读到这篇文章的人90 的可能是遇到了输入字符后 xff0c 回车没有预期的输出 xff0c 连续回车都没用 这种情况可能是因为你在scanf中加了 n xff0c 而且加了不该加的地方 把代码里的 n删了或者再输入一个不是 n的字符再回车

随机推荐

  • c语言使用一维数组实现杨辉三角

    通常使用在实现杨辉三角时使用的时使用二维数组的方式 xff0c 这种方式比较快捷 xff0c 且比较好理解 xff0c 但是使用二维数组浪费了大量的空间 xff0c 又大概一般的空间未被使用 如果使用一维数组进行计算能大大提高空间利用率 首
  • 链表、结构体和数组对比

    结构体和数组 1 结构体可以存不同类型的元素 而数组只能存同一类型 2 结构体类型需要我们自已定义 数组是用别的类型加 元素个数 3 结构体内存分配方式很特别 使用对齐原则 不一定是所有元素的字节数和 而数组一定是所有元素的字节数和 4 结
  • C和C++那些事儿

    1 new delete malloc free关系 delete会调用对象的析构函数 和new对应free只会释放内存 xff0c new调用构造函数 malloc与free是C 43 43 C语言的标准库函数 xff0c new del
  • 排序和复杂度

    常见的排序方式 1 冒泡排序 xff1a 时间复杂度 xff1a 最好情况是 O n xff0c 最坏情况是 O n2 空间复杂度 xff1a 开辟一个空间交换顺序O 1 2 快速排序 xff1a 时间复杂的 xff1a 最好情况是 O n
  • 文件IO过程

    基本概念 xff1a 文件描述符 xff1a xff08 文件描述符有时称为文件句柄 xff09 进程级 xff09 文件描述符是一个简单的整数 xff0c 用以标明每一个 被 进程所打开的文件和socket 通常0 1 2被标准输入 标准
  • private与构造函数

    通常我们都将构造函数的声明置于public区段 xff0c 假如我们将其放入private区段中会发生什么样的后果 xff1f 没错 xff0c 我也知道这将会使构造函数成为私有的 xff0c 这意味着什么 xff1f 我们知道 xff0c
  • 使用VS Code连接远程服务器

    目录 一 VS Code的安装与下载 二 安装插件 三 添加服务器连接配置 四 连接服务器 一 VS Code的安装与下载 关于VS Code的安装与下载及VS Code的使用方式详见如下链接 VSCode安装教程并配置C C 43 43
  • C语言 转换10进制为16进制

    实际上就是除16取余然后将其本身除以16 xff0c 得到的这一个数将它转换为具体的16进制数字的过程 xff0c 当然最后还要注意前面的字符位置的添加 span class token comment 进制之间互相转换 xff1a 将十进
  • TCP协议是如何保证传输可靠性的

    TCP确保传输可靠性的方式 校验和序列号 确认应答超时重传连接管理流量控制 xff08 滑动窗口控制 xff09 拥塞控制 校验和 xff1a TCP校验和是一个端到端的校验和 xff0c 由发送端计算 xff0c 然后由接收端验证 其目的
  • TCP的三次握手与四次挥手详解

    文章目录 TCP 协议简述TCP包首部TCP 三次握手建立连接TCP 四次挥手关闭连接常见面试题 xff1a TCP 协议简述 TCP 提供面向有连接的通信传输 xff0c 面向有连接是指在传送数据之前必须先建立连接 xff0c 数据传送完
  • IP数据报格式及分片与重组

    IP数据报 在 TCP IP 协议中 xff0c 使用 IP 协议传输数据的包被称为 IP 数据报 xff08 也叫数据包或数据报文 xff09 xff0c 每个数据包都包含 IP 协议规定的内容 IP协议提供不可靠无连接的数据报传输服务
  • mysql锁机制

    MySQL的锁机制 文章目录 MySQL的锁机制1 行锁2 表锁3 页锁4 乐观锁和悲观锁4 1悲观锁4 2乐观锁5 1InnoDB锁的特性 首先对mysql锁进行划分 xff1a 按照锁的粒度划分 xff1a 行锁 表锁 页锁按照锁的使用
  • uboot开发流程

    uboot其实就是一段比较复杂的单片机代码用来作为引导程序 xff0c 它的主要任务是初始化硬件设备 xff0c 将系统的软硬件环境带到一个合适的状态 xff0c 再将内核从一种存储介质读入到内存中 xff0c 然后跳到内核的入口点去运行
  • java的几种IO

    Java IO方式大体上可以分为三类 xff0c 基于不同的io模型可以简单分为同步阻塞的BIO 同步非阻塞的NIO和异步非阻塞的AIO IO又主要可以分为文件IO和网络IO 针对Java的网络IO模型 xff0c 可以看网络IO模型 xf
  • 哈希冲突和一致性哈希

    文章目录 哈希冲突处理哈希冲突1 开放地址法2 再散列法3 链地址法4 建立一个公共溢出区 一致性哈希普通 hash算法普通 hash 算法的缺陷 一致性哈希算法一致性 hash 算法的优点hash 环的倾斜与虚拟节点 哈希冲突 哈希函数又
  • Redis IO多路复用理解

    IO多路复用在Redis中的应用 Redis 服务器是一个事件驱动程序 xff0c 服务器处理的事件分为时间事件和文件事件两类 文件事件 xff1a Redis主进程中 xff0c 主要处理客户端的连接请求与相应 时间事件 xff1a fo
  • 分布式理论CAP,BASE

    什么是CAP理论 xff1f CAP理论指的是一个分布式系统最多只能同时满足一致性 xff08 Consistency xff09 可用性 xff08 Availability xff09 和分区容错性 xff08 Partition to
  • javaEE接收request参数以及输出结果到html页面

    1 引入需要的类 这里需要注意 xff0c servlet类不是jre自带的 xff0c 需要自己添加 添加相关类主要有以下两种方式 xff1a 下载servlet api jar xff08 tomcat自带 xff09 然后添加到cla
  • 西门子博途数据块(DB块)快速导入导出

    有些人可能会想用查表法计算CRC校验码 查表法效率和速度都很高 但是空间换时间 让你用几秒钟时间 把一张完整的表存入博途里 就算了你单身20年的手速估计也完成不了 想要几秒钟完成也不是不可以 就是导入别人的源文件 拿来主义当然块 继续上图
  • opencv4.0学习笔记

    目录 课程来源 xff1a 哔哩哔哩大学 第一节课 显示第一张图片 环境配置了一个早上 xff0c 到10 48分配置完毕 xff0c 有点难受 还好最后显示出第一张图片 include span class token operator