i am using Qt Creator to implement an application that reads a video and by clicking on a button i will save the frame that is being showed. Then i will process that frame with Opencv.
Having a video being displayed with QmediaPlayer, how can i extract a frame from the video? I should then be able to convert that frame to a Mat image in Matlab.
Thanks
QMediaPlayer *player = new QMediaPlayer();
QVideoProbe *probe = new QVideoProbe;
connect(probe, SIGNAL(videoFrameProbed(QVideoFrame)), this, SLOT(processFrame(QVideoFrame)));
probe->setSource(player); // Returns true, hopefully.
processFrame slot:
void processFrame(QVideoFrame const&) {
if (isButtonClicked == false) return;
isButtonClicked = false;
...
process frame
...
}
QVideoProbe reference
QVideoFrame reference
You can use QVideoFrame::bits() to process image with OpenCV
Related
I am using QT to build a custom component for QML. I want this component to be able to play a WEBM video that contains an alpha channel. However, all of my attempts have resulted in the transparent pixels of the video getting replaced with black ones. This is my code currently:
MyClass::MyClass()
{
m_pixmap = new QPixmap(1920, 1080); // Create a canvas to draw on:
// Create something that can be drawn:
m_painter = new QPainter(m_pixmap);
m_rect = new QRect(0, 0, 1920, 1080);
// Create an area to present on:
m_label = new QLabel();
m_label->setPixmap(*m_pixmap);
m_label->show();
// Play video:
m_videoSink = new QVideoSink();
m_mediaPlayer = new QMediaPlayer();
m_mediaPlayer->setVideoSink(m_videoSink);
m_mediaPlayer->setSource(QUrl::fromLocalFile("path..."));
m_mediaPlayer->setLoops(QMediaPlayer::Infinite);
m_mediaPlayer->play();
// Add a an event for when the video frame changes:
connect(m_videoSink, SIGNAL(videoFrameChanged(QVideoFrame)), this, SLOT(SetFrame(QVideoFrame)));
qDebug() << "Constructed";
}
void MyClass::SetFrame(QVideoFrame frame)
{
frame.paint(m_painter, *m_rect, m_options); //Stores the frame in the m_pixmap
m_label->setPixmap(*m_pixmap);
}
In this example I attempt to use a QMediaPlayer to play the video, then a QVideoSink to extract the currently playing QVideoFrame and paint that to a QPixmap that is finally being displayed in a QLabel.
I have also tried to have the QMediaPlayer directly hooked up to a QVideoWidget.
I know that my WEBM video works as it is displaying as expected when imported in to other programs.
It may be a very silly problem, but I am really got stack on this.
Here, I am trying to display a video frame by frame in QLabel. In the user interface, there is a QPushButton by clicking which user can select the video. Then QString of the video file is obtained, which is then converted to cv::String so that video can be loaded by using OpenCV libraries. After being loaded, every Mat3b type frame from the cv::video is being converted to the QImage, so that these frames can be displayed in a QLabel. But when I run this program, the QLabel is not displaying the video. And after few moments, it crushes showing Project.exe is not responding.
This may be a bit complex, but it has been thus done so that, some specific OpenCV methods can be applied on each frame if needed. Here is some code, which is responsible for this.
void MainWindow::on_Browse_clicked()
{
QFileDialog dialog(this);
dialog.setNameFilter(tr("Videos (*.avi)"));
dialog.setViewMode(QFileDialog::Detail);
QString videofileName = QFileDialog::getOpenFileName(this, tr("Open
File"), "C:/", tr("Videos (*.avi)"));
if(!videofileName.isEmpty())
{
String videopath;
videopath = videofileName.toLocal8Bit().constData();
bool playVideo = true;
VideoCapture cap(videopath);
if(!cap.isOpened())
{
QMessageBox::warning(this, tr("Warning"),tr("Error loadeing
video."));
exit(0);
}
Mat frame;
while(1)
{
if(playVideo)
cap >> frame;
Mat3b src=frame;
QImage dest= Mat3b2QImage(src); //To convert Mat3b to QImage
ui->label->setPixmap(QPixmap::fromImage(dest));
if(frame.empty())
{
QMessageBox::warning(this, tr("Warning"),tr("Video frame
cannot be openned."));
break;
}
}
}
}
But when I added the following few lines before the last three curly brace bracket, both the QLabel and cv::window are displaying the video.
imshow("Video",src);
char key = waitKey(10);
if(key == 'p')
playVideo = !playVideo;
if(key == 'q')
break;
But I don't want to display with cv::window. Can anyone help me fix it? I appreciate any help.
Thanks in advance.
The GUI thread is busy in the infinite while loop, so you never give Qt the chance to update the GUI.
You should add QApplication::processEvents inside the loop, which:
Processes all pending events for the calling thread [...].
You can call this function occasionally when your program is busy performing a long operation
I want to use openCV to capture photos.
I use two labels for showing,one is for video stream and the other is for the captured photo.
Now the captured photo is works well,but the video stream cannot be display and always got a segmentation fault!
Actually,both of the codes almost exactly the sameļ¼
void CameraCap::on_CapBtn_clicked()
{
frame = cvQueryFrame(cam);
QImage image = QImage((const uchar*)frame->imageData, frame->width, \
frame->height, QImage::Format_RGB888).rgbSwapped();
ui->pictureLabel->setPixmap(QPixmap::fromImage(image));
}
void CameraCap::readFrame()
{
frame = cvQueryFrame(cam);
QImage image = QImage((const uchar*)frame->imageData, frame->width, \
frame->height, QImage::Format_RGB888).rgbSwapped();
ui->videoLabel->setPixmap(QPixmap::fromImage(image));
}
void CameraCap::on_openBtn_clicked()
{
cam = cvCreateCameraCapture(0);
timer->start(33);
}
timer = new QTimer(this);
connect(timer, SIGNAL(timeout()), this, SLOT(readFrame()));
That is to say, the function of on_CapBtn_clicked() works well,but the function readFrame() always leads to segmentation fault!
Why does this happen?
I am struggling with writing a video player which uses OpenCV to read a frame from video and display it in a QWidget.
This is my code:
// video caputre is opened here
...
void VideoPlayer::run()
{
int sleep = 1000 / static_cast<unsigned long>(video_capture_.get(CV_CAP_PROP_FPS));
forever
{
QScopedPointer<cv::Mat> frame(new cv::Mat);
if(!video_capture_.read(*frame))
break;
cv::resize(*frame, *frame, cv::Size(640, 360), 0, 0, cv::INTER_CUBIC);
cv::cvtColor(*frame, *frame, CV_BGR2RGB);
QImage image(frame->data, frame->cols, frame->rows, QImage::Format_RGB888);
emit signalFrame(image); // notifying QWidget to draw an image
msleep(sleep); // wait before we read another frame
}
}
and on the QWidget side, I am just using this image and drawing it in paintEvent.
It just looks to me that parameter sleep doesn't play important role here. As much as I decrease it (to get more FPS) the video is just not smooth.
The only thing here left for me is that I gave up on that approach because it doesn't work, but I wanted to ask here one more time, just to be sure - am I doing something wrong here?
In my program, I'm reading from a webcam or a video file, via OpenCV and displaying it via Qt.
I get the fps from the video properties and set the timer accordingly.
I have no problem reading the videos, the fps calibration is good (since the webcam show 0fps, I set it to 30)
But when I record the images, I set the output video's fps to the same as the original video, yet, when I read it in VLC or even Windows Media Player the video is accelerated.
The most curious thing is when I play the recorded video in my program, the fps is good, and the video isn't accelerated.
Here's how I do it :
Constructor()
{
// Initializing the video resources
cv::VideoCapture capture;
cv::VideoWriter writer;
cv::Mat frame;
int fps;
if (webcam)
{
capture.open(0);
fps = 30;
}
else
{
capture.open(inputFilePath);
fps = this->capture.get(CV_CAP_PROP_FPS);
}
// .avi
writer = cv::VideoWriter(outputFilePath, CV_FOURCC('M', 'J', 'P', 'G'), fps, frame.size());
// Defining the refresh timer;
QTimer timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(updateFeed()));
this->timer->start(1000 / fps);
}
updateFeed()
{
// ... display the image in a QLabel ... at a reasonnable speed.
writer.write(frame);
}
Now is there anything I do wrong ?
Thanks