Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/137.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/image-processing/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在C/C+中写入YUV图像帧的问题+;_C++_Image Processing_File Io_Rgb_Yuv - Fatal编程技术网

C++ 在C/C+中写入YUV图像帧的问题+;

C++ 在C/C+中写入YUV图像帧的问题+;,c++,image-processing,file-io,rgb,yuv,C++,Image Processing,File Io,Rgb,Yuv,我正在尝试将取自OpenGL glReadPixels()的RGB帧转换为YUV帧,并将YUV帧写入文件(.YUV)。稍后,我想将其写入命名的_管道作为FFMPEG的输入,但现在我只想将其写入文件,并使用YUV图像查看器查看图像结果。因此,暂时不要理会“向管道写入”的问题 运行代码后,我遇到以下错误: YUV Image Viewer软件中显示的帧数始终是我在程序中声明的帧数的1/3。当我将fps声明为10时,我只能查看3帧。当我声明fps为30时,我只能查看10帧。但是,当我在文本编辑器中查看

我正在尝试将取自OpenGL glReadPixels()的RGB帧转换为YUV帧,并将YUV帧写入文件(.YUV)。稍后,我想将其写入命名的_管道作为FFMPEG的输入,但现在我只想将其写入文件,并使用YUV图像查看器查看图像结果。因此,暂时不要理会“向管道写入”的问题

运行代码后,我遇到以下错误:

  • YUV Image Viewer软件中显示的帧数始终是我在程序中声明的帧数的1/3。当我将fps声明为10时,我只能查看3帧。当我声明fps为30时,我只能查看10帧。但是,当我在文本编辑器中查看文件时,我可以看到文件中打印了正确数量的单词“FRAME”。 这是我得到的示例输出:

  • 我看不到正确的图像,只是一些扭曲的绿色、蓝色、黄色和黑色像素

  • 我从和中了解了YUV格式

    以下是我到目前为止所做的尝试。我知道这种转换方法非常有效,我可以在以后对其进行优化。现在我只想让这种天真的方法发挥作用,并让图像正确地显示出来

    int frameCounter = 1; 
    int windowWidth = 0, windowHeight = 0;
    unsigned char *yuvBuffer;
    unsigned long bufferLength = 0;
    unsigned long frameLength = 0;
    int fps = 10;
    
    void display(void) {
    
        /* clear the color buffers */
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    
        /* DRAW some OPENGL animation, i.e. cube, sphere, etc 
         .......
         .......
        */
    
        glutSwapBuffers();
    
        if ((frameCounter % fps) == 1){
            bufferLength = 0;
            windowWidth = glutGet(GLUT_WINDOW_WIDTH);
            windowHeight = glutGet (GLUT_WINDOW_HEIGHT);
            frameLength = (long) (windowWidth * windowHeight * 1.5 * fps) + 100; // YUV 420 length (width*height*1.5) + header length
            yuvBuffer = new unsigned char[frameLength];
            write_yuv_frame_header();
        }
    
        write_yuv_frame();
    
        frameCounter = (frameCounter % fps) + 1;
    
        if ( (frameCounter % fps) == 1){
            snprintf(filename, 100, "out/image-%d.yuv", seq_num);
            ofstream out(filename, ios::out | ios::binary); 
            if(!out) { 
                cout << "Cannot open file.\n"; 
            } 
    
            out.write (reinterpret_cast<char*> (yuvBuffer), bufferLength);
            out.close();
            bufferLength = 0;
            delete[] yuvBuffer;
        }
    }
    
    
    void write_yuv_frame_header (){
        char *yuvHeader = new char[100];
        sprintf (yuvHeader, "YUV4MPEG2 W%d H%d F%d:1 Ip A0:0 C420mpeg2 XYSCSS=420MPEG2\n", windowWidth, windowHeight, fps);
        memcpy ((char*)yuvBuffer + bufferLength, yuvHeader, strlen(yuvHeader));
        bufferLength += strlen (yuvHeader);
        delete (yuvHeader);
    }
    
    void write_yuv_frame() {
        int width = glutGet(GLUT_WINDOW_WIDTH);
        int height = glutGet(GLUT_WINDOW_HEIGHT);
        memcpy ((void*) (yuvBuffer+bufferLength), (void*) "FRAME\n", 6);
        bufferLength +=6;
    
        long length = windowWidth * windowHeight;
        long yuv420FrameLength = (float)length * 1.5;
        long lengthRGB = length * 3;
        unsigned char *rgb      = (unsigned char *) malloc(lengthRGB * sizeof(unsigned char));
        unsigned char *yuvdest  = (unsigned char *) malloc(yuv420FrameLength * sizeof(unsigned char));
        glReadPixels(0, 0, windowWidth, windowHeight, GL_RGB, GL_UNSIGNED_BYTE, rgb);
    
        int r, g, b, y, u, v, ypos, upos, vpos;
    
        for (int j = 0; j <  windowHeight; ++j){
            for (int i = 0; i < windowWidth; ++i){
                r = (int)rgb[(j * windowWidth + i) * 3 + 0];
                g = (int)rgb[(j * windowWidth + i) * 3 + 1];
                b = (int)rgb[(j * windowWidth + i) * 3 + 2];
    
                y = (int)(r *  0.257 + g *  0.504 + b *  0.098) + 16;
                u = (int)(r *  0.439 + g * -0.368 + b *  -0.071) + 128;
                v = (int)(r *  -0.148 + g * -0.291 + b * 0.439 + 128);
    
                ypos = j * windowWidth + i;
                upos = (j/2) * (windowWidth/2) + i/2 + length;
                vpos = (j/2) * (windowWidth/2) + i/2 + length + length/4;
    
                yuvdest[ypos] = y;
                yuvdest[upos] = u;
                yuvdest[vpos] = v;            
            } 
        }
    
        memcpy ((void*) (yuvBuffer + bufferLength), (void*)yuvdest, yuv420FrameLength);
        bufferLength += yuv420FrameLength;
        free (yuvdest);   
        free (rgb);
    }
    
    int frameCounter=1;
    int windowWidth=0,windowHeight=0;
    未签名字符*yuvBuffer;
    无符号长缓冲区长度=0;
    无符号长帧长度=0;
    int fps=10;
    作废显示(作废){
    /*清除颜色缓冲区*/
    glClear(GL_颜色_缓冲_位| GL_深度_缓冲_位);
    /*绘制一些OPENGL动画,例如立方体、球体等
    .......
    .......
    */
    glutSwapBuffers();
    如果((帧计数器%fps)==1){
    缓冲长度=0;
    windowWidth=glutGet(GLUT\u窗口\u宽度);
    窗口高度=glutGet(GLUT\U窗口高度);
    frameLength=(长)(窗宽*窗高*1.5*fps)+100;//YUV 420长度(宽*高*1.5)+页眉长度
    yuvBuffer=新的无符号字符[frameLength];
    写入帧头();
    }
    写下你的框架();
    帧计数器=(帧计数器%fps)+1;
    如果((帧计数器%fps)==1){
    snprintf(文件名,100,“输出/图像-%d.yuv”,序号);
    输出流(文件名,ios::out | ios::binary);
    如果(!out){
    
    cout在我看来,对于4:2:0数据,每帧的字节数太多。根据链接到的规范,200x200像素4:2:0帧的字节数应该是200*200*3/2=60000。但是您有大约90000个字节。查看您的代码,我看不到从4:4:4转换到4:2:0的位置。因此,您有两个选择—设置标头设置为4:4:4,或者在写入之前将YCbCr数据转换为4:2:0。

    我编译了您的代码,在计算upos和vpos值时肯定会出现问题。 对我来说,这很有效(RGB到YUV NV12):


    我已经将字节数设置为200*200*3/2(在yuv420FrameLength中)。因此,对于200*200像素的图像,yuv缓冲区的大小为60000。我还将帧长度设置为width*height*1.5*fps。此外,以下代码以4:2:0格式定位数据:ypos=j*windowWidth+I;upos=(j/2)*(windowWidth/2)+i/2+length;vpos=(j/2)*(windowWidth/2)+i/2+length+length/4;yuvdest[ypos]=y;yuvdest[upos]=u;yuvdest[vpos]=v;啊,对不起。我下载了你的输出文件,在文本编辑器中查看时,第一个“帧”和第二个“帧”之间大约有90000字节,但事实证明,这是因为它被文本编辑器转换为UTF8。在十六进制编辑器中查看它,只有60000字节,这似乎是正确的。你能发布前后的图片吗?这可能会让事情变得更加明显。此外,如果你写出4:4:4的数据(使用正确的标题),会发生什么?那么你得到所有的帧了吗?还有一件事-我注意到维基百科的链接提到标题以“YUVMPEG4”(结尾有一个空格)开头,所有字段都以一个空格开头。YUV标记和宽度标记之间需要2个空格吗?(我在维基百科上不清楚是否如此。)你能在写数据的地方发布代码吗?另外,你能在调试器中验证当你将u和v从有符号整数转换为无符号字符时,你得到了正确的位模式吗?你解决了这个问题吗?
    vpos = length + (windowWidth * (j/2)) + (i/2)*2;
    upos = vpos + 1;