大纲
1.视频文件摄像头的使用
2.一维直方图的绘制
3.二维直方图的绘制
4.直方图均衡化
1.视频文件摄像头的使用
(1)相关函数
开启摄像头设置:VideoCapture capture(0); //开启摄像头数据(电脑自带)
保存视频设置:VideoWriter writer("D:/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);
读取视频:capture.read(frame); //读取摄像头数据
保存视频:writer.write(frame); //保存视频帧
关闭:
capture.release();
writer.release();
source code
(1)开启摄像头或视频设置
VideoCapture capture("F:/snip/VIDEOS/运动/VID_20210525_215712俯卧撑标准20个.mp4"); //开启摄像头数据(电脑自带)
(2)获取视频信息(如宽度,高度,总帧数,每秒播放的帧数)
//视频信息
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); //视频总的帧数
double fps = capture.get(CAP_PROP_FPS); //1s有多少张图片
std::cout << "frame width:" << frame_width <<std:: endl;
std::cout << "frame_height:" << frame_height << std::endl;
std::cout << "count:" << count << std::endl;
std::cout << "fps:" << fps << std::endl;
(3)保存视频信息
//(1)视频编解码规则,
//(2)主要处理视频,相机的分辨率是否支持,由硬件决定的
//int xxx capture.set(CAP_PROP_FRAME_WIDTH);
//cou
VideoWriter writer("D:/test.mp4", capture.get(CAP_PROP_FOURCC), fps, Size(frame_width, frame_height), true);
(4)视频显示窗口,键盘退出,保存视频操作
Mat frame;
while (true)
{
capture.read(frame); //读取摄像头数据
flip(frame, frame, 1); //镜像
//chaneels_demo(frame); //通道的分解
//tracking_bar_demo(frame);
if (frame.empty()) //如果没有图像,退出。
{
break;
}
//键盘响应
namedWindow("frame", WINDOW_FREERATIO); //自适应窗口
imshow("frame", frame);
writer.write(frame); //保存视频帧
//TODO:do something...
int c = waitKey(3); //3ms 一帧
if (c == 27) //ESC退出
{
break;
}
}
(5)关闭视频,关闭保存
capture.release();
writer.release();
2.一维直方图的绘制
直方图的概念:
去除掉物理的地址信息,只保留像素大小。因而具有图像平移、旋转、缩放不变性等众多优点。
广泛应用于图像处理的各个领域。特别是灰度的阈值分割、基于颜色的图像检索以及图像分类等等。
OpenCV只支持灰度图片的直方图
效果图:
函数:
直方图:calcHist(某个通道的矩阵引用, 图片的数量, 通道数, Mat(), 输出直方图矩阵, 输出维度, 等份个数,自变量的范围);
归一化:normalize(b_hist, b_hist, 0, histImage.rows, NORM_MINMAX, -1, Mat());
source code
(1)通道分离
std::vector<Mat>bgr_plane;
split(image, bgr_plane); //分离通道到容器 bgr_plane
(2)定义参数,步长,像素/样本的范围,定义三个矩阵去接收直方图的数据
const int channels[1] = { 0 }; //通道的个数
const int bins[1] = { 256 }; //直方图分割成多少个区间,就是bin的个数
float hranges[2] = { 0,255 }; //像素取值范围在0-255,直方图分割成多少个区间
const float* ranges[1] = { hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist;
(3)Calculate Blue,green,red chaneels histogram
calcHist(某个通道的矩阵引用, 图片的数量, 通道数, Mat(), 输出直方图矩阵, 输出维度, 等份个数,自变量的范围);
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);
(4) 自己设计画布,划分最小区间
int hist_w = 512;
int hist_h = 400;
//划分x轴的数据,通过之前定义的区间个数
int bin_w = cvRound((double)hist_w / bins[0]); //OpenCV 四舍五入的函数,把它分割成256分
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); //创建与指定的图片的尺寸相同的画布
(5)归一化直方图数据,限定数据范围在0-histImage.rows
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());
(6)绘制直线
for (int i = 1; i < bins[0]; 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);
}
(7)显示直方图
namedWindow("Histogram Demo", WINDOW_AUTOSIZE);
imshow("Histogram Demo", histImage);
source code
void QuickDemo::histogram_demo(Mat& image) //图像直方图
{
//三通道分离
std::vector<Mat>bgr_plane;
split(image, bgr_plane); //分离通道到容器 bgr_plane
//定义参数变量
const int channels[1] = { 0 }; //通道的个数
const int bins[1] = { 256 }; //直方图分割成多少个区间,就是bin的个数
float hranges[2] = { 0,255 }; //像素取值范围在0-255,直方图分割成多少个区间
const float* ranges[1] = { hranges };
Mat b_hist;
Mat g_hist;
Mat r_hist;
//calculate Blue,green,red chaneels histogram
//直方图的结果存放到b_hist,g_hist,r_hist中,是一个256x1的列数组
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);
//自己设计--->直方图(尺寸)
int hist_w = 512;
int hist_h = 400;
//划分x轴的数据,通过之前定义的区间个数
int bin_w = cvRound((double)hist_w / bins[0]); //OpenCV 四舍五入的函数,把它分割成256分
Mat histImage = Mat::zeros(hist_h, hist_w, CV_8UC3); //创建与指定的图片的尺寸相同的画布
//归一化直方图数据(限定数据范围:0-histImage.rows 之间)
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());
//MINMAX:数组的数值被平移或缩放到一个指定的范围,线性归一化
//Mask :Mat()
//-1 表达式数据类型和通道相同
//NORM_MINMAX:数组的数值被平移或缩放到一个指定的范围。
//绘制直方图曲线
//在x轴方向上沿着从左到右绘制直线。
//数据可视化工作!!!
for (int i = 1; i < bins[0]; 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);
}
(3)二维直方图的绘制
RGB转HSV,V通道不算
效果图:
(1)转换颜色空间
Mat hsv, hs_hist;
cvtColor(image, hsv, COLOR_BGR2HSV);
(2)设定直方图参数,步长,数据范围,通道个数
int hbins = 30, sbins = 32; //得到步长,也就是180,划分30,得到6的步长
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_chaneels[] = { 0,1 }; //H,S
(3)直方图
calcHist(&hsv, 1, hs_chaneels, Mat(), hs_hist,2,hist_bins,hs_ranges,true,false);
(4)计算最大像素和最小像素
double maxVal = 0;
minMaxLoc(hs_hist, 0, &maxVal, 0, 0);
(5)自定义画布范围,创建图像
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); //(z = f(x,y))
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:/test1.png", hist2d_image);
}
(4)直方图均衡化
应用范围:用于图像增强(对比度),人脸检测,卫星遥感。均衡化的API只支持单通道
函数:equalizeHist(原图,目标图);
source code
void QuickDemo::histogram_eq_demo(Mat &image)
{
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
imshow("灰度图像", gray);
Mat dst;
equalizeHist(gray, dst);
imshow("直方图均衡化",dst);
}
Date:初心易得,始终难守 2021-12-24