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界面添加如下:

QT5+opencv3.1实现视频播放加实时直方图


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. 最后运行结果:

QT5+opencv3.1实现视频播放加实时直方图