Working with Video Using OpenCV and QT - Part 2

36 篇文章 0 订阅
This tutorial was written because of a request from a previous tutorial. In this tutorial, we improve upon the work done in that tutorial by adding a track-bar and display duration of the video. Also a few errors, I discovered will also be corrected in this tutorial. So let get cracking.

Add widgets to GUI

This is an extension to a previous tutorial so I will only point out changes or additions to the previous work so as not to repeat myself. Open the mainwindow.ui file, this filecould be edited manually but for this tutorial we would use thedesigner.
  • Add a horizontal track-bar to the GUI, this would be used to the adjust the position in the video.  
  • Add two labels to the GUI; place one on the left and another on the right of the horizontal track-bar ( or however suits your needs) the left one would show the current time into the video whereas the right  one would be used to show the total time of the video.  The GUI should now look similar to the image above.

Player Class Definition

Now we add a few function definitions to Player class header file - player.h.
 
 
  1. #ifndef PLAYER_H
  2. #ifndef PLAYER_H
  3. #define PLAYER_H
  4. #include <QMutex>
  5. #include <QThread>
  6. #include <QImage>
  7. #include <QWaitCondition>
  8. #include <opencv2/core/core.hpp>
  9. #include <opencv2/imgproc/imgproc.hpp>
  10. #include <opencv2/highgui/highgui.hpp>
  11. using namespace cv;
  12. class Player : public QThread
  13. { Q_OBJECT
  14. private:
  15. ....
  16. VideoCapture *capture;
  17. Mat RGBframe;
  18. QImage img;
  19. signals:
  20. ......
  21. protected:
  22. ......
  23. public:
  24. .......
  25. //set video properties
  26. void setCurrentFrame( int frameNumber);
  27.  
  28.  
  29. //Get video properties
  30. double getFrameRate();
  31. double getCurrentFrame();
  32. double getNumberOfFrames();
  33. };
  34.  
  35. #endif // VIDEOPLAYER_H
The class definition is still simple and straightforward. We add a few public setter and getter functions to enable us grab some important video parameters. Also I change the capture variable to a pointer I discovered that it was not possible to reload a new video once one has been loaded so to correct this I initialize a new VideoCapture instance when a new video is loaded. So the method used to access the VideoCapture instance members must be changed from the "." to the "->" notation.

Player Class Implementation

Here is the constructor for the Player class.
 
 
  1. bool Player::loadVideo(string filename) {
  2. capture = new cv::VideoCapture(filename);
  3.  
  4. if (capture->isOpened())
  5. {
  6. frameRate = (int) capture->get(CV_CAP_PROP_FPS);
  7. return true;
  8. }
  9. else
  10. return false;
  11. }
  12.  
  13. void Player::run()
  14. {
  15. int delay = (1000/frameRate);
  16. while(!stop){
  17. if (!capture->read(frame))
  18. {
  19. stop = true;
  20. }
  21. .....
  22. }
  23. }
In the loadVideo() method, we use the instance of the VideoCapture class to load the video and set the frame rate. As you should already know the VideoCapture class is from the OpenCV library
 
 
  1. double Player::getCurrentFrame(){
  2. return capture->get(CV_CAP_PROP_POS_FRAMES);
  3. }
  4. double Player::getNumberOfFrames(){
  5. return capture->get(CV_CAP_PROP_FRAME_COUNT);
  6. }
  7. double Player::getFrameRate(){
  8. return frameRate;
  9. }
  10. void Player::setCurrentFrame( int frameNumber )
  11. {
  12. capture->set(CV_CAP_PROP_POS_FRAMES, frameNumber);
  13. }
Here are the getter and setter function to access the video information. I ran into a glitch, with ffmpeg where the capture->get(CV_CAP_PROP_FRAME_COUNT) function returned the wrong frame count. The solution might be to update my ffmpeg. I would update the post once the solution is confirmed.
 
 
  1. Player::~Player()
  2. {
  3. mutex.lock();
  4. stop = true;
  5. capture.release();
  6. delete capture;
  7. condition.wakeOne();
  8. mutex.unlock();
  9. wait();
  10. }
Here is the rest of the Player class, in the destructor we release the VideoCapture object, also we allocated memory with the new keyword it must be freed.

MainWindow Class Definition

 
 
  1. #ifndef MAINWINDOW_H
  2. #define MAINWINDOW_H
  3. #include <QMainWindow>
  4. #include <QFileDialog>
  5. #include <QMessageBox>
  6. #include <player.h>
  7. #include <QTime>
  8.  
  9. namespace Ui {
  10. class MainWindow;
  11. }
  12. class MainWindow : public QMainWindow
  13. {
  14. Q_OBJECT
  15. public:
  16. .......
  17. private slots:
  18. .........
  19. QString getFormattedTime(int timeInSeconds);
  20. void on_horizontalSlider_sliderPressed();
  21. void on_horizontalSlider_sliderReleased();
  22. void on_horizontalSlider_sliderMoved(int position);
  23. private:
  24. ........
  25. };
  26. #endif // MAINWINDOW_H
Here is the class definition for the MainWindow class, we include the 3 event slots for the new horizontal slider and a update some other functions

Mainwindow class implementation

 
 
  1. MainWindow::MainWindow(QWidget *parent) :
  2. QMainWindow(parent),
  3. ui(new Ui::MainWindow)
  4. {
  5. .......
  6.  
  7. ui->pushButton_2->setEnabled(false);
  8. ui->horizontalSlider->setEnabled(false);
  9. }
We disable the play button and the horizontal slider; these would be enabled once a video is loaded.
 
 
  1. void MainWindow::updatePlayerUI(QImage img)
  2. {
  3. if (!img.isNull())
  4. {
  5. ui->label->setAlignment(Qt::AlignCenter);
  6. ui->label->setPixmap(QPixmap::fromImage(img).scaled(ui->label->size(),
  7. Qt::KeepAspectRatio, Qt::FastTransformation));
  8. ui->horizontalSlider->setValue(myPlayer->getCurrentFrame());
  9. ui->label_2->setText( getFormattedTime( (int)myPlayer->getCurrentFrame()/(int)myPlayer->getFrameRate()) );
  10. }
  11. }
The updatePlayerUI slot receives a QImage and resizes it to fit the label (keeping the aspect ratio) which will be used to display. It displays the image by setting the label pixmap. We also update the horizontal slider position and the label that displays the elapsed time. We calculate the duration of the video but dividing the total number of frames by the frame rate.
 
 
  1. void MainWindow::on_pushButton_clicked()
  2. {
  3. QString filename = QFileDialog::getOpenFileName(this,
  4. tr("Open Video"), ".",
  5. tr("Video Files (*.avi *.mpg *.mp4)"));
  6. QFileInfo name = filename;
  7.  
  8. if (!filename.isEmpty()){
  9. if (!myPlayer->loadVideo(filename.toAscii().data()))
  10. {
  11. QMessageBox msgBox;
  12. msgBox.setText("The selected video could not be opened!");
  13. msgBox.exec();
  14. }
  15. else{
  16. this->setWindowTitle(name.fileName());
  17. ui->pushButton_2->setEnabled(true);
  18. ui->horizontalSlider->setEnabled(true);
  19. ui->horizontalSlider->setMaximum(myPlayer->getNumberOfFrames());
  20. ui->label_3->setText( getFormattedTime( (int)myPlayer->getNumberOfFrames()/(int)myPlayer->getFrameRate()) );
  21. }
  22. }
  23. }
  24.  
  25. QString MainWindow::getFormattedTime(int timeInSeconds){
  26. int seconds = (int) (timeInSeconds) % 60 ;
  27. int minutes = (int) ((timeInSeconds / 60) % 60);
  28. int hours = (int) ((timeInSeconds / (60*60)) % 24);
  29. QTime t(hours, minutes, seconds);
  30. if (hours == 0 )
  31. return t.toString("mm:ss");
  32. else
  33. return t.toString("h:mm:ss");
  34. }
  35. void MainWindow::on_horizontalSlider_sliderPressed()
  36. {
  37. myPlayer->Stop();
  38. }
  39. void MainWindow::on_horizontalSlider_sliderReleased()
  40. {
  41. myPlayer->Play();
  42. }
  43. void MainWindow::on_horizontalSlider_sliderMoved(int position)
  44. {
  45. myPlayer->setCurrentFrame(position);
  46. ui->label_2->setText( getFormattedTime( position/(int)myPlayer->getFrameRate()) );
  47. }
  48.  
This is the remaining part of the MainWindow Class, the getFormattedTime function takes the time in seconds and formats it for display, the rest is self explanatory. You can Download the full code Here.

Final words...

This is just a simple tutorial to help anyone get started with videos in OpenCV and QT. Please let me know if this was helpful and ask questions and give suggestions(if any) in the comments. Happy Coding!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值