QT,C++:在QGraphicsview上从相机绘制实时图像流的快速方法



我正在编写一个QT GUI应用程序,其中连接的摄像机的实时流显示在QGraphicsview上。因此,openCV图像首先被转换为QImage,而不是QPixmap。这被添加到 QGraphicsView 的 QGraphicsScene 中。

带宽不是问题,相机通过以太网或USB连接。

我正在使用Visual Studio 2012中的Analyze Toole构建测试性能,它表明到QPixmap的转换非常慢,并且需要60%的计算时间(显示图像),因此我最终得到1 FPS左右。图像是2560年到1920年甚至更大。缩放 cv::P tr stream_image将其转换为 QImage 可以显着提高性能,但我需要图像中的所有图像细节。

编辑以下是我如何进行转换的一些代码:

cv::Ptr<IplImage> color_image;
// stream_image is a cv::Ptr<IplImage> and holds the current image from the camera
if (stream_image->nChannels != 3) {
    color_image = cvCreateImage(cvGetSize(stream_image), IPL_DEPTH_8U, 3);
    cv::Mat gr(stream_image);
    cv::Mat col(color_image);
    cv::cvtColor(gr, col, CV_GRAY2BGR);
}
else {
    color_image = stream_image;
}
QImage *tmp = new QImage(color_image->width, color_image->height, QImage::Format_RGB888);
memcpy(tmp->bits(), color_image->imageData, color_image->width * color_image->height * 3);

// update Scene
m_pixmap = QPixmap::fromImage(*tmp); // this line takes the most time!!!
m_scene->clear();
QGraphicsPixmapItem *item = m_scene->addPixmap(m_pixmap);
m_scene->setSceneRect(0,0, m_pixmap.width(), m_pixmap.height());

delete tmp;
m_ui->graphicsView->fitInView(m_scene.sceneRect(),Qt::KeepAspectRatio);

m_ui->graphicsView->update();

编辑 2我从托马斯的回答中测试了该方法,但它和我的方法一样慢。

QPixmap m_pixmap = QPixmap::fromImage(QImage(reinterpret_cast<uchar const*>(color_image->imageData), 
color_image->width, 
color_image->height, 
QImage::Format_RGB888));

编辑 3我试图纳入托马斯的第二个建议:

color_image = cvCreateImage(cvGetSize(resized_image), IPL_DEPTH_32F, 3);
//[...]   
QPixmap m_pixmap = QPixmap::fromImage(QImage( 
reinterpret_cast<uchar const*>( color_image->imageData), 
color_image->width, 
color_image->height, 
QImage::Format_RGB32));

但是当调用 Widget 的 drawEvent 时,它会崩溃。

问:有没有办法在QGraphicsView中显示图像流,而无需先将其转换为QPixmap或任何其他快速/高性能的方式?QGraphicsView很重要,因为我想为图像添加叠加层。

我已经找到了一个适合我的解决方案,但也用不同的方法和它们的性能进行了一些测试:

方法一即使在调试模式下也能达到高性能,并且仅占用绘图过程执行时间的23.7%(使用VS2012中的ANALYZE):

color_image = cvCreateImage(cvGetSize(stream_image), IPL_DEPTH_8U, 4);
cv::Mat gr(stream_image);
cv::Mat col(color_image);
cv::cvtColor(gr, col, CV_GRAY2RGBA,4);
QPixmap m_pixmap = QPixmap::fromImage(QImage(reinterpret_cast<uchar const*>( color_image->imageData), 
                                      color_image->width, 
                                      color_image->height, 
                                      QImage::Format_ARGB32));

方法二在调试模式下仍然具有性能,占用了 42,1% 的执行时间。 当在 QPixmap 中使用以下枚举时::fromeImage 代替

QImage::Format_RGBA8888

方法三是我在问题中展示的方法,它在调试版本中非常慢,负责 68,3% 的绘图工作量。

但是,当我在版本中编译时,所有三种方法的性能都非常相似

这是我通常做的事情。 使用使用现有缓冲区的 QImage 构造函数之一,然后对其余缓冲区使用 QPixmap::fromImage。缓冲区的格式应与显示兼容,例如 QImage::Format_RGB32 。在此示例中,矢量用作图像的存储。

std::vector<QRgb> image( 2560 * 1920 );
QPixmap pixmap = QPixmap::fromImage( QImage( 
    reinterpret_cast<uchar const*>( image.data() ), 
    2560, 
    1920, 
    QImage::Format_RGB32 ) );

请注意对齐约束。如果 alignemnt 不是 32 位对齐的,则可以使用采用 bytesPerLine 参数的构造函数之一。

编辑:

如果您的图像是 32 位,那么您可以写入。

QPixmap pixmap = QPixmap::fromImage( QImage( 
    reinterpret_cast<uchar const*>( color_image->imageData ), 
    color_image->width, 
    color_image->height, 
    QImage::Format_RGB32 ) );

最新更新