简体   繁体   English

从内存缓冲区保存QImage

[英]Saving a QImage from a memory buffer

Here is basically what I'm doing : 这基本上是我在做什么:

I have a video stream (YUV format). 我有一个视频流(YUV格式)。 Each frame is extracted into a buffer ( frameBytes ). 每个帧都提取到缓冲区( frameBytes )中。 Later, this buffer is used to do the YUV->RGB conversion, then transfered in an IplImage . 以后,此缓冲区用于执行YUV-> RGB转换,然后在IplImage中进行IplImage The IplImage is then transfered into a cv::Mat and displayed in an OpenGL context. 然后将IplImage传输到cv::Mat并显示在OpenGL上下文中。 Everything works fine. 一切正常。

What I would like to do is bypass the IplImage and cv::Mat section to directly work with the frameBytes buffer in OpenGL and do the conversion in the shaders. 我想做的是绕过IplImagecv::Mat部分,直接在OpenGL中使用frameBytes缓冲区,并在着色器中进行转换。

This explaination is just for the context, since the problem I'm having is simpler. 这种解释仅是针对上下文,因为我遇到的问题比较简单。

To see if I can work with the buffer earlier, I try to copy it with memcpy and then save it in a QImage then in a file. 为了查看我是否可以更早使用该缓冲区,我尝试使用memcpy复制它,然后将其保存在QImage ,然后保存在文件中。

Here is my code for this part : 这是我这部分的代码:

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 contains the YUV data from the video stream. frameBytes包含来自视频流的YUV数据。 I know it's YUV and I'm trying to create a QImage with RGB888 format but since QImage doesn't support the format, I didn't make the conversion there, I thought it would still save an image but with the wrong colors so I don't care for the moment (Maybe this assumption is wrong ?). 我知道它是YUV,并且我正在尝试创建具有RGB888格式的QImage,但是由于QImage不支持该格式,因此我没有在那里进行转换,所以我认为它仍然可以保存图像但颜色错误,所以我暂时不关心(也许这个假设是错误的?)。

Problem is, the image saved is black. 问题是,保存的图像是黑色的。

Just for more information, here is an example where I use frameBytes for the YUV->RGB conversion. 只是为了获得更多信息,这是一个示例,其中我使用frameBytes进行frameBytes > 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;
    }


}

Fixing the bug 修正错误

You didn't copy all the data to your new buffer: 您没有将所有数据复制到新缓冲区中:

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

That sizeof in there means that you're only copying an int -sized block, rather than 6MB. 那里的sizeof意味着您只复制一个int大小的块,而不是6MB。 It looks like an accidental holdover from using a static array? 看起来是由于使用静态数组导致的意外保留? Replace it with 替换为

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

A simpler approach 更简单的方法

Alternatively, instead of doing the memory allocation yourself (and being responsible for delete[] ing it after the QImage is destructed), you could copy the image instead: 另外,您可以复制映像,而不是自己进行内存分配(并在QImage销毁后负责delete[]对其进行分配):

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

The way this works is that we create a temporary QImage using frameBytes as its source (we pass it as pointer to const to insist it's read-only). 这种工作方式是,我们使用frameBytes作为其源创建一个临时QImage (我们将其作为指向const指针传递,以使其坚持为只读)。 We then copy() the whole of it to a new QImage , throwing away the temporary. 然后,我们将整个过程都copy()到新的QImage ,丢弃临时图像。 The copy() does something similar to your code above, but we're now saved from having to do the calculations, eliminating some of the consequent potential for error. copy()功能与您上面的代码类似,但是现在不必进行计算了,从而避免了随之而来的潜在错误。

Note also that I prefer to pass QImage by value. 另请注意,我更喜欢按值传递QImage Although this might seem inefficient, most (copyable) Qt types are designed as reference-counted copy-on-write structures, and can be safely used this way, eliminating another class of errors (memory management). 尽管这看起来效率低下,但大多数(可复制)Qt类型都被设计为引用计数写时复制结构,可以安全地以这种方式使用,从而消除了另一类错误(内存管理)。 This is true of Qt's collection types, too, and very useful. Qt的集合类型也是如此,并且非常有用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM