Qt OpenCV - 显示转换帧时的 SIGSEGV
Qt OpenCV - SIGSEGV when displaying transformed frames
我有一个应用程序,它必须从视频中提取帧,一点点变换,大量变换,然后同时在 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
标准问题。问题是内存管理!
看我的另一个 answer. In comments there is a good link.
所以在您的代码中 QImage
不会复制也不会取得矩阵内存的所有权。稍后当矩阵被破坏并且 QImage
尝试访问此内存时(QImage
通过创建浅拷贝进行复制)你有一个段错误。
这是一个代码形式 this link(我稍微调整了一下),出于某种原因,该站点存在一些管理问题(超出了一些配额),这就是我将其粘贴在这里的原因。
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(我在这里找到它:how to convert an opencv cv::Mat to 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;
}
我有一个应用程序,它必须从视频中提取帧,一点点变换,大量变换,然后同时在 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
标准问题。问题是内存管理! 看我的另一个 answer. In comments there is a good link.
所以在您的代码中 QImage
不会复制也不会取得矩阵内存的所有权。稍后当矩阵被破坏并且 QImage
尝试访问此内存时(QImage
通过创建浅拷贝进行复制)你有一个段错误。
这是一个代码形式 this link(我稍微调整了一下),出于某种原因,该站点存在一些管理问题(超出了一些配额),这就是我将其粘贴在这里的原因。
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(我在这里找到它:how to convert an opencv cv::Mat to 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;
}