qt opencv -sigsegv显示转换的帧



我有一个应用程序,它必须从视频中摘下帧,对一个变化,经常转换一个并同时在GUI中显示它们。在工作线程中,有一个openCV循环:

while(1) {
    cv::VideoCapture kalibrowanyPlik; 
    kalibrowanyPlik.open(kalibracja.toStdString()); //open file from url
    int maxFrames = kalibrowanyPlik.get(CV_CAP_PROP_FRAME_COUNT);
    for(int i=0; i<maxFrames; i++) //I thought it crashed when finished reading the first time around
    {
        cv::Mat frame;
        cv::Mat gray;
        cv::Mat color;
        kalibrowanyPlik.read(frame);
        cv::cvtColor(frame, gray, CV_BGR2GRAY);
        cv::cvtColor(frame, color, CV_BGR2RGB);
        QImage image((uchar*)color.data, color.cols, color.rows,QImage::Format_RGB888);
        QImage processedImage((uchar*)gray.data, gray.cols, gray.rows,QImage::Format_Indexed8);
        emit progressChanged(image, processedImage);
        QThread::msleep(50);
    }
}

这就是将框架放在GUI

中的方式
void MainWindow::onProgressChagned(QImage image, QImage processedImage) {
    QPixmap processed = QPixmap::fromImage(processedImage);
    processed = processed.scaledToHeight(379);
    ui->labelHsv->clear();
    ui->labelHsv->setPixmap(processed);
    QPixmap original = QPixmap::fromImage(image); //debug points SIGSEGV here
    original = original.scaledToHeight(379);
    ui->labelKalibracja->clear();
    ui->labelKalibracja->setPixmap(original);
}

RGB图像总是崩溃,灰度图像永远不会崩溃(测试)。为什么RGB图像崩溃?

编辑:我刚刚发现,如果将msleep(50)更改为msleep(100),它将完美执行。但是我不想要那个。我每秒至少需要25帧,10帧是不可接受的...为什么会导致Sigsegv

标准问题。问题是内存管理!看到我的其他答案。在评论中有一个很好的链接。

因此,在您的代码中,QImage不复制,也不占据矩阵内存的所有权。后来,当矩阵被破坏并在QImage尝试访问此内存时(通过创建浅副本复制QImage),您有一个segfault。


这是此链接的代码表格(我已经对其进行了一些调整),出于某种原因,该网站有一些管理问题(一些配额),这就是为什么我在这里粘贴它。

inline QImage  cvMatToQImage( const cv::Mat &inMat )
   {
      switch ( inMat.type() )
      {
         // 8-bit, 4 channel
         case CV_8UC4:
         {
            QImage image( inMat.data, inMat.cols, inMat.rows, inMat.step, QImage::Format_RGB32 );
            QImage copy(image);
            copy.bits(); //enforce deep copy
            return copy;
         }
         // 8-bit, 3 channel
         case CV_8UC3:
         {
            QImage image( inMat.data, inMat.cols, inMat.rows, inMat.step, QImage::Format_RGB888 );
            return image.rgbSwapped();
         }
         // 8-bit, 1 channel
         case CV_8UC1:
         {
            static QVector<QRgb>  sColorTable;
            // only create our color table once
            if ( sColorTable.isEmpty() )
            {
               for ( int i = 0; i < 256; ++i )
                  sColorTable.push_back( qRgb( i, i, i ) );
            }
            QImage image( inMat.data, inMat.cols, inMat.rows, inMat.step, QImage::Format_Indexed8 );
            image.setColorTable( sColorTable );
            QImage copy(image);
            copy.bits(); //enforce deep copy
            return copy;
         }
         default:
            qWarning() << "ASM::cvMatToQImage() - cv::Mat image type not handled in switch:" << inMat.type();
            break;
      }
      return QImage();
   }

您的代码应像这样使用此功能:

while(1) {
    cv::VideoCapture kalibrowanyPlik; 
    kalibrowanyPlik.open(kalibracja.toStdString()); //open file from url
    int maxFrames = kalibrowanyPlik.get(CV_CAP_PROP_FRAME_COUNT);
    for(int i=0; i<maxFrames; i++) //I thought it crashed when finished reading the first time around
    {
        cv::Mat frame;
        cv::Mat gray;
        kalibrowanyPlik.read(frame);
        cv::cvtColor(frame, gray, CV_BGR2GRAY);
        QImage image(cvMatToQImage(frame));
        QImage processedImage(cvMatToQImage(gray));
        emit progressChanged(image, processedImage);
        QThread::msleep(10); // this is bad see comments below
    }
}

使用msleep在95%的情况下不良!删除此循环并创建插槽,该插槽将由QTimer的信号调用。

另一个解决方案是使用计时器:

void ??::timerEvent(QTimerEvent*){
 if(kalibrowanssky.isOpened()) 
        cv::Mat frame;
        cv::Mat gray;
        cv::Mat color;
        kalibrowanyPlik.read(frame);
        cv::cvtColor(frame, gray, CV_BGR2GRAY);
        cv::cvtColor(frame, color, CV_BGR2RGB);
        ui->labelHsv->setPixmap(QPixmap::fromImage(Mat2QImage(color)));
        ui->labelKalibracja->setPixmap(QPixmap::fromImage(Mat2QImage(gray)));
}

在您的主体中:

cv::VideoCapture kalibrowanyPlik; 
startTimer(1000/25); // 25 frames by second

和函数mat2qimage(我在这里找到了:如何将OpenCV CV :: MAT转换为qimage):

QImage ??::Mat2QImage(cv::Mat const& src) {
     cv::Mat temp; 
     cvtColor(src, temp,CV_BGR2RGB); 
     QImage dest((const uchar *) temp.data, temp.cols, temp.rows, temp.step, QImage::Format_RGB888);
     dest.bits();
     return dest;
}

相关内容

  • 没有找到相关文章

最新更新