OpenCv学习0813

本文复习了OpenCV中视频的读取和保存,包括从文件和摄像头获取视频,以及如何释放资源。此外,介绍了图像直方图的概念,强调其在图像处理中的应用,如阈值分割、图像检索和分类。还提到了二维直方图的绘制,通过将RGB图像转换为HSV图像,选取特定维度进行分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

视频文件及摄像头的使用

这一段其实一开始就已经了解过了,这里算是复习一下

视频的读取(从文件及摄像头)

读取视频文件和摄像头,实际上只是修改cap文件的获取方式而已

void Demo::video_demo(Mat &image) {
	VideoCapture cap1(0);	
	//打开摄像头
	VideoCapture cap2("视频文件路径");
	//读取视频文件

	Mat frame;
	//创建一帧
	while (true) {
	    //cap >> frame;
		cap1.read(frame);
		//读取图像
		imshow("video", frame);
		if (waitKey(20) == 27)
			break;
	}
}

在结束视频操作后,一定要将cap释放,养成好习惯

	cap1.release();
	cap2.release();

视频的保存

视频有许多的清晰度,HD,SD,720P,1080P,4K,这些不同的清晰度对应的每一帧的图像大小也不同,对于我们已经获取的视频文件,可以获取他们对应的视频属性

	//frame的意思是帧
	int width = cap1.get(CAP_PROP_FRAME_WIDTH);//宽
	int height = cap1.get(CAP_PROP_FRAME_HEIGHT);//高
	int count = cap1.get(CAP_PROP_FRAME_COUNT);//总帧数
	int fps = cap1.get(CAP_PROP_FPS);//每秒帧数

对视频的保存,可以使用VideoWriter函数

	VideoWriter writer("保存路径", cap1.get(CAP_PROP_FOURCC), fps, Size(width, height), 1);
	//保存路径,编码方式(一般直接获取原视频编码方式),每秒帧数,格式(即尺寸),是否彩色

对视频进行处理,实际上只要对每一帧用之前的图像处理方法即可

图像直方图

图像直方图是用来表现图像中亮度分布的直方图,给出的是图像中某个亮度或者某个范围亮度下共有几个像素,即统计一幅图某个亮度像素数量。

图像直方图由于其计算代价较小,且具有图像平移、旋转、缩放不变性等众多优点,广泛地应用于图像处理的各个领域,特别是灰度图像的阈值分割、基于颜色的图像检索以及图像分类。

但是直方图只能得到他的颜色信息,而不能得到他的位置信息,因此不能具体的对应某一张图片。

void Demo::histogram_demo(Mat &image) {
	//绘制一维直方图
	//首先运用通道知识,分离三通道(对于RGB图像,灰度图像则不需要分离)
	vector<Mat> bgr_plane;
	split(image, bgr_plane);

	//定义参数变量
	const int channels[1] = { 0 };//通道索引,灰度图像可填入[0],彩色图像(BGR)[0]、[1]、[2]代表三个颜色通道;(也要用方括号)
	const int bins[1] = { 256 };//总共的灰度级别
	float hranges[2] = { 0,255 };//取值范围
	const float* ranges[1] = { hranges };
	Mat b_hist, g_hist, r_hist;

	//计算三个通道的直方图
	//calcHist(images,niimage, channels, mask, output, dims, histSize, ranges)
	//images:待计算图像,需要用方括号 [img]
	//channels:通道索引,灰度图像可填入[0],彩色图像(BGR)[0]、[1]、[2]代表三个颜色通道;(也要用方括号)
	//mask:掩膜,计算整个图像,传入None就行,如果要对局部图像做处理,可以定义个mask传入
	//histSize:Bin(直方图的柱子)数量,全尺寸用 [256] 就行
	//ranges:像素范围,一般设为 [0, 256]
	calcHist(&bgr_plane[0], 1, 0, Mat(), b_hist, 1, bins, ranges);
	calcHist(&bgr_plane[1], 1, 0, Mat(), g_hist, 1, bins, ranges);
	calcHist(&bgr_plane[2], 1, 0, Mat(), r_hist, 1, bins, ranges);

	//绘制直方图画布
	//cvRound():返回跟参数最接近的整数值,即四舍五入
	//cvFloor():返回不大于参数的最大整数值,即向下取整
	//cvCeil():返回不小于参数的最小整数值,即向上取整
	int hist_w = 512,hist_h = 400;//定义宽高
	int bin_w = cvRound((double)hist_w / 256);//每一条的宽度,用总宽度除以条数256
	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, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
	normalize(g_hist, r_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());

	//绘制直方图曲线
	//因为直方图是从下往上绘制的,而屏幕的纵坐标是最上面为0,因此纵坐标需要用纵坐标减去直方图坐标
	for (int i = 1; i < bins[0]; i++) {
		//b
		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);
		rectangle(histImage, Rect(bin_w*(i), hist_h - cvRound(b_hist.at<float>(i)), 
			bin_w, cvRound(b_hist.at<float>(i))), Scalar(255, 0, 0), -1, 8, 0);
		
		//g
		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);
		rectangle(histImage, Rect(bin_w*(i), hist_h - cvRound(g_hist.at<float>(i)), 
			bin_w, cvRound(g_hist.at<float>(i))), Scalar(0, 255, 0), -1, 8, 0);
		
		//r
		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);
		rectangle(histImage, Rect(bin_w*(i), hist_h - cvRound(r_hist.at<float>(i)), 
			bin_w, cvRound(r_hist.at<float>(i))), Scalar(0, 0, 255), -1, 8, 0);
	}

	//显示直方图
	namedWindow("Histogram", WINDOW_AUTOSIZE);
	imshow("Histogram", histImage);
		
}

其实只要理解原理就不是很难

关键点:

  • 一次只能绘制一个通道的直方图曲线,因此彩色图片需要分离通道,灰度图不需要
  • 理解calcHist()中每一个参数的意义
  • 只有计算直方图的函数而并没有直接显示直方图曲线的函数
  • 在绘制时要注意屏幕的坐标原点在左上角,因此直方图的纵坐标需要转换

二维直方图

要绘制二维直方图,首先要将RGB图像转换成HSV图像

在这里我们选择h和s两个维度来制作

void Demo::histogram_2d_demo(Mat &image) {
	Mat hsv, hs_hist;
	//绘制二维直方图需要将图片转换成HSV格式
	cvtColor(image, hsv, COLOR_BGR2HSV);
	int hbins = 30, sbins = 32;
	//定义h和s两个维度的bin
	int hist_bins[] = { hbins,sbins };
	float h_range[] = { 0,180 };//h的取值范围
	float s_range[] = { 0,255 };//s的取值范围
	const float* hs_range[] = { h_range,s_range };
	int hs_channels[] = { 0,1 };
	calcHist(&hsv, 1, hs_channels, Mat(), hs_hist, 2, hist_bins, hs_range, 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);
		}
	}
	namedWindow("Histogram", WINDOW_AUTOSIZE);
	imshow("Histogram", hist2d_image);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值