从内存缓冲区保存QImage

时间:2016-08-04 10:34:43

标签: c++ qt

基本上我正在做的事情:

我有一个视频流(YUV格式)。每帧被提取到缓冲区(frameBytes)。之后,此缓冲区用于进行YUV-> RGB转换,然后转换为IplImage。然后IplImage被转移到cv::Mat并显示在OpenGL上下文中。一切正常。

我想要做的是绕过IplImagecv::Mat部分直接使用OpenGL中的frameBytes缓冲区,并在着色器中进行转换。

这个解释仅适用于上下文,因为我遇到的问题更简单。

要查看我是否可以使用缓冲区,我尝试使用memcpy复制它,然后将其保存在QImage然后保存在文件中。

以下是此部分的代码:

unsigned char *mycopy = new unsigned char[1920*1080*3];
memcpy(mycopy, frameBytes, sizeof(1920*1080*3));
QImage *img = new QImage(mycopy, 1920, 1080, QImage::Format_RGB888);
img->save("image.jpg",0,-1);

frameBytes包含来自视频流的YUV数据。我知道它的YUV和我试图创建一个RGB888格式的QImage,但由于QImage不支持格式,我没有在那里进行转换,我认为它仍然会保存图像,但颜色错误,所以我不在乎当下(也许这个假设是错误的?)。

问题是,保存的图像为黑色。

仅供参考,以下是我使用frameBytes进行YUV-> RGB转换的示例。

void DeckLinkCaptureDelegate::convertFrameToOpenCV(void* frameBytes, IplImage * m_RGB){
    if(!m_RGB)  m_RGB = cvCreateImage(cvSize(1920, 1080), IPL_DEPTH_8U, 3);


    unsigned char* pData = (unsigned char *) frameBytes;


    for(int i = 0, j=0; i < 1920 * 1080 * 3; i+=6, j+=4)
    {

        unsigned char u = pData[j];
        unsigned char y = pData[j+1];
        unsigned char v = pData[j+2];

        //fprintf(stderr, "%d\n", v);
        m_RGB->imageData[i+2] = 1.0*y + 8 + 1.402*(v-128);               // r
        m_RGB->imageData[i+1] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128);   // g
        m_RGB->imageData[i] = 1.0*y + 1.772*(u-128) + 0;                            // b

        y = pData[j+3];
        m_RGB->imageData[i+5] = 1.0*y + 8 + 1.402*(v-128);               // r
        m_RGB->imageData[i+4] = 1.0*y - 0.34413*(u-128) - 0.71414*(v-128);   // g
        m_RGB->imageData[i+3] = 1.0*y + 1.772*(u-128) + 0;
    }


}

1 个答案:

答案 0 :(得分:0)

修复错误

您没有将所有数据复制到新缓冲区:

unsigned char *mycopy = new unsigned char[1920*1080*3];
memcpy(mycopy, frameBytes, sizeof(1920*1080*3));

那里的sizeof意味着您只复制int大小的块,而不是6MB。它看起来像是使用静态数组的意外保留?替换为

const size_t bufsize = 1920*1080*3;
auto *mycopy = new unsigned char[bufsize];
memcpy(mycopy, frameBytes, bufsize);

更简单的方法

或者,不是自己进行内存分配(并且在delete[]被破坏后负责QImage),您可以复制图像:

const unsigned char *bytes = frameBytes;
QImage img = QImage(bytes, 1920, 1080, QImage::Format_RGB888).copy();

这样做的方法是我们使用QImage创建一个临时frameBytes作为源(我们将其作为指针传递给const以坚持它是只读的)。然后我们copy()将整个QImage转移到新的copy(),扔掉临时的。{1}}。 QImage执行类似于上面代码的操作,但现在我们不必进行计算,从而消除了一些随之而来的错误。

另请注意,我更喜欢按值传递{{1}}。虽然这看起来效率低下,但大多数(可复制的)Qt类型都被设计为引用计数的写时复制结构,并且可以通过这种方式安全地使用,从而消除了另一类错误(内存管理)。对于Qt的集合类型也是如此,并且非常有用。