使用 Qt 和 OpenCV 读取和处理视频文件的有效方法

Posted

技术标签:

【中文标题】使用 Qt 和 OpenCV 读取和处理视频文件的有效方法【英文标题】:Efficient way to read and process video files with Qt and OpenCV 【发布时间】:2014-08-27 14:18:45 【问题描述】:

我有一些视觉算法在实时摄像头流中表现良好;但是,当我在视频文件上运行这些算法时,它还远远不够;流速度太慢了,尽管在不运行视觉算法时它很好,通过调用 VideoAlgoVision->execute( grabbedFrame, &CurrentROI ); 来执行

这是我目前阅读视频的方式:

//////////////////////////////////////////////////////////////////

void VisionUnit_widget::Play()

    if(IsVideoPause)
    
        ui->pausePushButton->setEnabled(true);
        ui->playPushButton->setEnabled(false);
        IsVideoPause = false;
        TimerOpen->start( (int) (1000/FPS_open) );

        return;
    
    else
    
        ui->pausePushButton->setEnabled(true);
        ui->stopPushButton ->setEnabled(true);
        ui->rewPushButton  ->setEnabled(true);
        ui->ffdPushButton  ->setEnabled(true);
        ui->videoSlider    ->setEnabled(true);

        ui->playPushButton ->setEnabled(false);

        if(!VideoCap)
            VideoCap = new VideoCapture( FileName.toStdString() );
        else
            VideoCap->open( FileName.toStdString() );

        if( VideoCap->isOpened() )
        
            FrameH    = (int) VideoCap->get(CV_CAP_PROP_FRAME_HEIGHT);
            FrameW    = (int) VideoCap->get(CV_CAP_PROP_FRAME_WIDTH);
            FPS_open  = (int) VideoCap->get(CV_CAP_PROP_FPS);
            NumFrames = (int) VideoCap->get(CV_CAP_PROP_FRAME_COUNT);

            ui->videoSlider->setMaximum( (int)NumFrames );

            ui->videoSlider->setEnabled(true);
            READCOUNT = 0;
            TimerOpen->start( (int) (1000/FPS_open) );
        
        



//////////////////////////////////////////////////////////////////

void VisionUnit_widget::Pause()

    ui->playPushButton->setEnabled(true);
    ui->pausePushButton->setEnabled(false);
    TimerOpen->stop();
    IsVideoPause = true;



//////////////////////////////////////////////////////////////////

void VisionUnit_widget::Stop()

    ui->stopPushButton->setEnabled(false);
    ui->playPushButton->setEnabled(false);
    ui->pausePushButton->setEnabled(false);
    ui->rewPushButton->setEnabled(false);
    ui->ffdPushButton->setEnabled(false);

    FileName = "";

    TimerOpen->stop();

    READCOUNT = 0;

    ui->videoSlider->setSliderPosition(0);
    ui->videoSlider->setEnabled(false);

    ui->frameLabel->setText( "No camera connected" );

    delete TimerOpen;
    TimerOpen = 0;

    if(VideoCap)
    
        delete VideoCap;
        VideoCap = 0;
    

    if(VideoAlgoVision)
    
        delete VideoAlgoVision;
        VideoAlgoVision = 0;
    



//////////////////////////////////////////////////////////////////

void VisionUnit_widget::Read()

    READCOUNT++;

    // Update Video Player's slider
    ui->videoSlider->setValue(READCOUNT);

    if(READCOUNT >= NumFrames) // if avi ends
    
        Pause();
        return;
    

    Mat grabbedFrame;


    // Get next frame
    if(VideoCap->isOpened() && VideoCap->read(grabbedFrame))
    
        // Execute the vision filter
        if(VideoAlgoVision)
            VideoAlgoVision->execute( grabbedFrame, &CurrentROI );

        // Convert Mat to QImage
        QImage frame = MatToQImage( grabbedFrame );

        // Update the display
        UpdateFrame( frame );
    



//////////////////////////////////////////////////////////////////

QImage VisionUnit_widget::MatToQImage(const Mat& mat)

    // 8-bits unsigned, NO. OF CHANNELS = 1
    if(mat.type()==CV_8UC1)
    
        // Set the color table (used to translate colour indexes to qRgb values)
        QVector<QRgb> colorTable;

        for (int i=0; i<256; i++)
        
            colorTable.push_back(qRgb(i,i,i));
        

        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;

        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_Indexed8);

        img.setColorTable(colorTable);
        return img;
    
    // 8-bits unsigned, NO. OF CHANNELS=3
    else if(mat.type()==CV_8UC3)
    
        // Copy input Mat
        const uchar *qImageBuffer = (const uchar*)mat.data;

        // Create QImage with same dimensions as input Mat
        QImage img(qImageBuffer, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);

        return img.rgbSwapped();
    
    else
    
        return QImage();
    

那么,我的问题是,有没有比这更好的方法来使用 Qt 和 OpenCV 读取视频文件,包括视频处理?我应该在运行时调整 QTimer 时间吗?我以TimerOpen-&gt;start( (int) (1000/FPS_open) ); 开头,但显然视觉算法会减慢整个过程。有什么想法吗?

可能需要对视觉算法进行一些优化,但我的观点是它们在我的网络摄像头和 IP 摄像头上表现良好,这让我觉得我阅读/使用视频文件的方式有问题。

谢谢

【问题讨论】:

【参考方案1】:

您没有提供完整的代码,但我猜您已将TimerOpentimeout() 信号连接到VisionUnit_widget::Read() 插槽。如果是这种情况,您正在累积1000/FPS_open 和处理时间。

将您的设计更改为以下内容将解决它:

int fSpace = 1000 / FPS;
QTime timer;
timer.start();

forever 
    if(timer.elapsed() < fSpace)
        msleep(1);

    timer.restart();

    ..Process the frame..

也许最好把它从主线程移到另一个线程。

【讨论】:

这不太合理......在你的无限循环中,帧处理之前的代码相当于我在TimerOpen和Read之间建立的直接连接...... connect(TimerOpen,SIGNAL(timeout ()),这个,SLOT(读取())); “您正在累积 1000/FPS_open 和处理时间”是什么意思?无论如何,我怀疑你的代码会改变我的问题,它看起来更笨拙。但是,对于您可能是对的线程,它已计划用于下一次迭代。谢谢。

以上是关于使用 Qt 和 OpenCV 读取和处理视频文件的有效方法的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV-Python实战——图像与视频文件的处理(两万字详解,️建议收藏️)

二.使用 OpenCV 读写视频

使用 opencv 和 Qt 录制视频

qt Android中使用opencv处理视频

OpenCV 例程 300篇252.视频文件的读取与保存

OpenCV 例程 300篇252.视频文件的读取与保存