Qimage 到 cv::Mat 转换的奇怪行为
Posted
技术标签:
【中文标题】Qimage 到 cv::Mat 转换的奇怪行为【英文标题】:Qimage to cv::Mat convertion strange behaviour 【发布时间】:2012-06-23 14:57:21 【问题描述】:我正在尝试创建一个我尝试集成 opencv 和 qt 的应用程序。
我使用以下代码成功地将 cv::Mat 转换为 QImage:
void MainWindow::loadFile(const QString &fileName)
cv::Mat tmpImage = cv::imread(fileName.toAscii().data());
cv::Mat image;
if(!tmpImage.data || tmpImage.empty())
QMessageBox::warning(this, tr("Error Occured"), tr("Problem loading file"), QMessageBox::Ok);
return;
/* Mat to Qimage */
cv::cvtColor(tmpImage, image, CV_BGR2RGB);
img = QImage((const unsigned char*)(image.data), image.cols, image.rows, QImage::Format_RGB888);
imgLabel->setPixmap(QPixmap::fromImage(img));
imgLabel->resize(imgLabel->pixmap()->size());
saveAsAct->setEnabled(true);
但是,当我尝试使用以下代码将 QImage 转换为 cv::Mat 时:
bool MainWindow::saveAs()
if(fileName.isEmpty())
QMessageBox::warning(this, tr("Error Occured"), tr("Problem loading file"), QMessageBox::Close);
return EXIT_FAILURE;
else
outputFileName = QFileDialog::getSaveFileName(this, tr("Save As"), fileName.toAscii().data(), tr("Image Files (*.png *.jpg *.jpeg *.bmp)\n *.png\n *.jpg\n *.jpeg\n *.bmp"));
/* Qimage to Mat */
cv::Mat mat = cv::Mat(img.height(), img.width(), CV_8UC4, (uchar*)img.bits(), img.bytesPerLine());
cv::Mat mat2 = cv::Mat(mat.rows, mat.cols, CV_8UC3 );
int from_to[] = 0,0, 1,1, 2,2;
cv::mixChannels(&mat, 1, &mat2, 1, from_to, 3);
cv::imwrite(outputFileName.toAscii().data(), mat);
saveAct->setEnabled(true);
return EXIT_SUCCESS;
我没有成功,结果是完全混乱的形象。在我搜索的网络中,我看到人们正在使用这种方式,而没有提及任何具体问题。有人知道可能导致问题的原因吗?提前致谢。
西奥多
附:我在带有 gnome-3.4 的 Arch Linux 系统下使用 opencv 2.4 和 Qt 4.8
【问题讨论】:
【参考方案1】:只需找出复制(不参考)QImage 到 cv::Mat 的“正确”解决方案
马丁贝克特的答案几乎是正确的
for (int i=0;i<image.height();i++)
memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
我没有看到完整的代码,但我猜你可能想这样使用它
cv::Mat mat(image.height(), image.width(), CV_8UC3);
for (int i=0;i<image.height();i++)
memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
但是这段代码存在问题, cv::Mat 分配的内存可能不与 QImage 具有相同的“bytesperline”
我找到的解决方案是先引用QImage,然后克隆它
return cv::Mat(img.height(), img.width(), format, img.bits(), img.bytesPerLine()).clone();
Martin Beckett 建议的解决方案可以在大多数情况下产生正确的结果 有时,我在遇到错误之前都没有注意到它。
无论如何,我希望这是一个“正确”的解决方案。如果您发现任何错误,请让 每个人都知道,所以我们可以进行更改以改进代码。
【讨论】:
【参考方案2】:我认为您可能会发现这很有用。 http://www.jdxyw.com/?p=1480
它使用 IplImage 来获取数据,但您可以使用 cv::Mat 和 Mat.data 来获取指向原始矩阵的指针。我希望你会觉得这很有用。
【讨论】:
【参考方案3】:opencv 图像是阶梯式的,因此每一行都以 32 位的倍数开始,这使得内存访问更快。如果您使用的是 3 字节/像素格式,那么除非您的宽度是 4 的倍数的 1/3,否则您将在每行的末尾有“备用”内存
安全的方法是一次复制一行图像数据。 opencv mat.ptr(row) 返回一个指向每一行开头的指针,QImage .scanline(row) 成员也这样做
见How to output this 24 bit image in Qt
编辑:类似的东西
for (int i=0;i<image.height();i++)
memcpy(mat.ptr(i),image.scanline(i),image.bytesperline());
【讨论】:
我将“cv::Mat to QImage”的代码更改为 cv::cvtColor(tmpImage, image, CV_BGR2RGB); uchar *buffer = image.ptr(); img = QImage(buffer, image.cols, image.rows, image.step, QImage::Format_RGB888); imgLabel->setPixmap(QPixmap::fromImage(img)); imgLabel->resize(imgLabel->pixmap()->size());但它似乎没有任何影响。我认为的问题是如何正确地将“QImage 转换为 cv::Mat”。 不,您必须遍历所有行,一次复制一个,因为它们在其中一种格式中不一定是连续的,请参阅链接中的代码【参考方案4】:来自this source code
QImage 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
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
qDebug() << "ERROR: Mat could not be converted to QImage.";
return QImage();
// MatToQImage()
【讨论】:
OP 想要 QImage 到 Mat【参考方案5】:这是我从here thanks to jose. 那里得到的,它帮助我克服了这个问题。
要在 Qt (QImage) 中可视化 OpenCV 图像 (cv::Mat),您必须按照以下步骤操作:
-
反转颜色序列:
cv::cvtColor(imageBGR, imageRGB, CV_BGR2RGB);
将 OpenCV 格式更改为 Qt:QImage qImage((uchar*) imageRGB.data, imageRGB.cols, imageRGB.rows, imageRGB.step, QImage::Format_RGB888);
使用 QPainter 渲染图像。
请注意 QImage::Format 的使用。阅读有关此问题的 Qt。
【讨论】:
OP 想要 QImage 到 cv::Mat【参考方案6】:如果您仍在寻找解决方案。这是一个:
Cv::Mat 到 QImage :
QImage Mat2QImage(cv::Mat &image )
QImage qtImg;
if( !image.empty() && image.depth() == CV_8U )
if(image.channels() == 1)
qtImg = QImage( (const unsigned char *)(image.data),
image.cols,
image.rows,
QImage::Format_Indexed8 );
else
cvtColor( image, image, CV_BGR2RGB );
qtImg = QImage( (const unsigned char *)(image.data),
image.cols,
image.rows,
QImage::Format_RGB888 );
return qtImg;
对于 QImage 到 cv::Mat 。
cv::Mat QImage2Mat(QImage &image)
cv::Mat cvImage;
switch (image.format())
case QImage::Format_RGB888:
cvImage = cv::Mat(image.height(),
image.width(),
CV_8UC3,
image.bits(),
image.bytesPerLine());
cv::cvtColor(cvImage, cvImage, CV_RGB2BGR);
return cvImage;
case QImage::Format_Indexed8:
cvImage = cv::Mat(image.height(),
image.width(),
CV_8U,
image.bits(),
image.bytesPerLine());
return cvImage;
default:
break;
return cvImage;
【讨论】:
以上是关于Qimage 到 cv::Mat 转换的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章
使用 QImage::loadFromData 将 cv::mat 转换为 QImage