QT5+opencv3.1实现视频播放加实时直方图
首先:本文程序是结合博客中各个网友的智慧基础上,自我思考改进,最终写成这个程序。
本文主要参考如下:
视频播放类:
http://blog.****.net/AP1005834/article/details/51263012
http://blog.****.net/obervose/article/details/70038901
直方图类:
http://blog.****.net/NNNNNNNNNNNNY/article/details/52874710
具体实现:
1.目标是两个,视频播放、直方图,所以程序分为两大块。
2.视频播放的难点,是一定要有定时器,不然程序显示没问题,实际一打开摄像头程序就会异常退出。
3.直方图一开始只能显示一帧,后来改变思路才能实时。
4.目前未实现:视频暂停,音频问题,界面简陋无滑动条,视频过大可能导致显示不全。
1-1. ui界面添加如下:
1-2. mainwindow.cpp代码如下:
#include "mainwindow.h"
#include "ui_mainwindow.h"
// 多种头文件类省略
//以下为一些定义
QTimer *timer;
QImage image,histpic;
VideoCapture cap;
Mat frame , chuhouImage;
bool flag = false;
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
timer = new QTimer(this);
/*信号和槽*/
connect(timer, SIGNAL(timeout()), this, SLOT(showImage())); // 时间到,读取当前摄像头信息
}
MainWindow::~MainWindow()
{
delete ui;
}
QImage Mat2QImage(cv::Mat cvImg)
{
QImage qImg;
if (cvImg.channels() == 3) //3 channels color image
{
cv::cvtColor(cvImg, cvImg, CV_BGR2RGB);
qImg = QImage((const unsigned char*)(cvImg.data),
cvImg.cols, cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_RGB888);
}
else if (cvImg.channels() == 1) //grayscale image
{
qImg = QImage((const unsigned char*)(cvImg.data),
cvImg.cols, cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_Indexed8);
}
else
{
qImg = QImage((const unsigned char*)(cvImg.data),
cvImg.cols, cvImg.rows,
cvImg.cols*cvImg.channels(),
QImage::Format_RGB888);
}
return qImg;
}
void MainWindow::on_pushButton_2_clicked()
{
timer->start(30);
cap.open("E:\\2.avi");
//获取整个帧数
long totalFrameNumber = cap.get(CV_CAP_PROP_FRAME_COUNT);
ui->textEdit->append(QString::fromLocal8Bit("整个视频共 %1 帧").arg(totalFrameNumber));
//设置开始帧()
long frameToStart = 0;
cap.set(CV_CAP_PROP_POS_FRAMES, frameToStart);
ui->textEdit->append(QString::fromLocal8Bit("从第 %1 帧开始读").arg(frameToStart));
//获取帧率
double rate = cap.get(CV_CAP_PROP_FPS);
ui->textEdit->append(QString::fromLocal8Bit("帧率为:第 %1 ").arg(rate));
int delay = 1000 / rate;
}
void MainWindow::showImage()
{
cap >> frame;
if (frame.empty())
{
std::cerr<<"ERROR: Couldn't grab a camera frame."<<
std::endl;
exit(1);
}
if (flag)
zhifangtuchuli(frame , chuhouImage);
else
frame.copyTo(frame);
image = Mat2QImage(frame);
ui->label->setPixmap(QPixmap::fromImage(image));// 将图片显示到label上
//获取当前第几帧
long totalFrameNumber2 = cap.get(CV_CAP_PROP_POS_FRAMES);
ui->textEdit->append(QString::fromLocal8Bit("正在读取第:第 %1 帧").arg(totalFrameNumber2));
// ui->label->resize(image.size()); //让label大小为图片大小
}
void MainWindow::on_pushButton_3_clicked() //直方图
{
flag = !flag;
// if (waitKey(30) >= 0)break;
}
void MainWindow::zhifangtuchuli(Mat &frames, Mat &histImage)
{
int bins = 256;
int hist_size[] = { bins };
float range[] = { 0, 256 };
const float* ranges[] = { range };
MatND redHist, greenHist, blueHist;
//红色分量直方图的计算
int channels_r[] = { 2 };
calcHist(&frames, 1, channels_r, Mat(), redHist, 1, hist_size, ranges);
//绿色分量直方图的计算
int channels_g[] = { 1 };
calcHist(&frames, 1, channels_g, Mat(), greenHist, 1, hist_size, ranges);
//蓝色分量直方图的计算
int channels_b[] = { 0 };
calcHist(&frames, 1, channels_b, Mat(), blueHist, 1, hist_size, ranges);
double maxValue_red, maxValue_green, maxValue_blue;
minMaxLoc(redHist, 0, &maxValue_red, 0, 0);
minMaxLoc(greenHist, 0, &maxValue_green, 0, 0);
minMaxLoc(blueHist, 0, &maxValue_blue, 0, 0);
int scale = 1;
int histHeight = 256;
histImage = Mat::zeros(histHeight, bins * 3, CV_8UC3);
for (int i = 0; i < bins; i++)
{
float binValue_red = redHist.at<float>(i);
float binValue_green = greenHist.at<float>(i);
float binValue_blue = blueHist.at<float>(i);
int intensity_red = cvRound(binValue_red*histHeight / maxValue_red);
int intensity_green = cvRound(binValue_green*histHeight / maxValue_green);
int intensity_blue = cvRound(binValue_blue*histHeight / maxValue_blue);
rectangle(histImage, Point(i*scale, histHeight - 1), Point((i + 1)*scale - 1, histHeight - intensity_red), Scalar(0, 0, 255));
rectangle(histImage, Point((i + bins)*scale, histHeight - 1), Point((i + bins + 1)*scale - 1, histHeight - intensity_green), Scalar(0, 255, 0));
rectangle(histImage, Point((i + bins * 2)*scale, histHeight - 1), Point((i + bins * 2 + 1)*scale - 1, histHeight - intensity_blue), Scalar(255, 0, 0));
}
histpic = Mat2QImage(histImage);
// imshow("【图像的RGB直方图】", histImage);
ui->label_2->setPixmap(QPixmap::fromImage(histpic));
}
1-3. 最后运行结果: