【问题标题】:Converting yuv 4:2:0 file to Rgb not getting expected output将 yuv 4:2:0 文件转换为 Rgb 未获得预期输出
【发布时间】:2018-12-12 12:24:18
【问题描述】:

我使用的逻辑是我正在读取缓冲区中的 yuv 文件并使用 3 个指针指向 Y、U、V 分量。图像尺寸为 1920*1080。

我是

  • 为对应的 1U,1V 像素取 4 y 像素。
  • 以整数形式提取像素值。
  • 将 Y、U、V 转换为 R、G、B 并将分量存储在 RGB 缓冲区中。

但是视频输出不正确。输出有点像黑白

#include "stdafx.h"
#include <string>
#include <stdio.h>

unsigned char* g_pcRGBbuffer;
unsigned char* g_pcYUVBuffer;

int _tmain(int argc, _TCHAR* argv[])
{
    int l_nSize = 1920 * 1080 * 1.5;

    g_pcYUVBuffer = new unsigned char[l_nSize];
    g_pcRGBbuffer = new unsigned char[1920 * 1080 * 3];
    FILE* fp_source;
    FILE* fp_rgb = NULL;
    int l_nY, l_nU, l_nV;
    double l_dR, l_dG, l_dB, l_ni;

    fp_source = fopen("D:\\Sample_1920x1080.yuv", "rb");
    // converting yuv file to rgb file
    if (fp_source)
    {
        fp_rgb = fopen("D:\\Sample_1920x1080.rgb", "wb+");
        while (!feof(fp_source))
        {
            fread(g_pcYUVBuffer, 1, l_nSize, fp_source);
            unsigned char* l_pcY = g_pcYUVBuffer;
            unsigned char* l_pcU = l_pcY + 1920 * 1080;
            unsigned char* l_pcV = l_pcU + ((1920 * 1080) / 4);
            unsigned char* l_pcRGBbuffer = g_pcRGBbuffer;

            for (l_ni = 0; l_ni < (1920 * 1080) / 4; l_ni++)
            {
                l_nY = l_pcY[0];
                l_nU = l_pcU[0];
                l_nV = l_pcV[0];

                l_dR = l_nY + 1.402 * (l_nV - 128);
                l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
                l_dB = l_nY + 1.772 * (l_nU - 128);

                // This prevents colour distortions in  rgb image
                if (l_dR < 0)
                    l_dR = 0;
                else if (l_dR > 255)
                    l_dR = 255;
                if (l_dG < 0)
                    l_dG = 0;
                else if (l_dG > 255)
                    l_dG = 255;
                if (l_dB < 0)
                    l_dB = 0;
                else if (l_dB > 255)
                    l_dB = 255;

                // 1st pixel of RGB
                l_pcRGBbuffer[0] = l_dR;
                l_pcRGBbuffer[1] = l_dG;
                l_pcRGBbuffer[2] = l_dB;

                l_nY = l_pcY[1];
                l_nU = l_pcU[0];
                l_nV = l_pcV[0];

                l_dR = l_nY + 1.402 * (l_nV - 128);
                l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
                l_dB = l_nY + 1.772 * (l_nU - 128);

                if (l_dR < 0)
                    l_dR = 0;
                else if (l_dR > 255)
                    l_dR = 255;
                if (l_dG < 0)
                    l_dG = 0;
                else if (l_dG > 255)
                    l_dG = 255;
                if (l_dB < 0)
                    l_dB = 0;
                else if (l_dB > 255)
                    l_dB = 255;

                // 2nd pixel of RGB
                l_pcRGBbuffer[3] = l_dR;
                l_pcRGBbuffer[4] = l_dG;
                l_pcRGBbuffer[5] = l_dB;

                l_nY = l_pcY[2];
                l_nU = l_pcU[0];
                l_nV = l_pcV[0];

                l_dR = l_nY + 1.402 * (l_nV - 128);
                l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
                l_dB = l_nY + 1.772 * (l_nU - 128);

                if (l_dR < 0)
                    l_dR = 0;
                else if (l_dR > 255)
                    l_dR = 255;
                if (l_dG < 0)
                    l_dG = 0;
                else if (l_dG > 255)
                    l_dG = 255;
                if (l_dB < 0)
                    l_dB = 0;
                else if (l_dB > 255)
                    l_dB = 255;

                // 3rd pixel of RGB
                l_pcRGBbuffer[6] = l_dR;
                l_pcRGBbuffer[7] = l_dG;
                l_pcRGBbuffer[8] = l_dB;

                l_nY = l_pcY[3];
                l_nU = l_pcU[0];
                l_nV = l_pcV[0];

                // l_dR = 1.164*(l_nY-16 ) + 1.596*(l_nV-128 );
                // l_dG = 1.164*(l_nY-16 ) - 0.813*(l_nV-128 ) - 0.391*(l_nU-128);
                // l_dB = 1.164*(l_nY-16 ) + 2.018*(l_nU-128 );

                l_dR = l_nY + 1.402 * (l_nV - 128);
                l_dG = l_nY - 0.34414 * (l_nU - 128) - 0.71414 * (l_nV - 128);
                l_dB = l_nY + 1.772 * (l_nU - 128);

                if (l_dR < 0)
                    l_dR = 0;
                else if (l_dR > 255)
                    l_dR = 255;
                if (l_dG < 0)
                    l_dG = 0;
                else if (l_dG > 255)
                    l_dG = 255;
                if (l_dB < 0)
                    l_dB = 0;
                else if (l_dB > 255)
                    l_dB = 255;

                // 4th pixel of RGB
                l_pcRGBbuffer[9] = l_dR;
                l_pcRGBbuffer[10] = l_dG;
                l_pcRGBbuffer[11] = l_dB;

                l_pcY += 4;
                l_pcU += 1;
                l_pcV += 1;
                l_pcRGBbuffer += 12;
            }

            fwrite(g_pcRGBbuffer, 1, 1920 * 1080 * 3, fp_rgb);
        }

        printf("Video converted to rgb file \n ");
    }
    else
    {
        printf("fail\n");
    }

    fclose(fp_rgb);
    fclose(fp_source);
    return 0;
}

【问题讨论】:

  • 与其将所有公式和所有钳位在 0..255 范围内重复三次,不如考虑将其编写为一个函数,这样您就无需更正和维护。此外,与其说if(fopen...) 和缩进然后if(open...) 并再次缩进,恕我直言,如果您在知道出现问题后立即退出函数,即@ 987654324@
  • 你检查过你的 YUV 文件的布局,还是你猜它是 4 个一组的?通常首先出现所有 Y 值,然后是二次采样的 U,然后是 V 值...
  • 我的 yuv 文件是 4:2:0 平面格式,所以我假设每个 1U 和 1V 会有四个 4y 像素。因为 y 像素的数量是 u 和 v.am i 的 4 倍指向 l_pcY,l_pcU,l_pcV 的正确位置??
  • 如果是平面的,所有的 Y 像素都在前,然后是所有的 U 像素,然后是所有的 V 像素。您愿意分享您的文件吗?
  • 嗨,OP。我已经通过自动格式化程序运行您的代码并修复了帖子中的格式,因此所有代码都显示为代码。我还修正了你的语法并添加了 c++ 标签。如果你只用 c++11 标记它,人们就不太可能看到你的帖子。如果您使用 c++11 标记帖子,通常也应该使用 c++ 标记它。

标签: c++ c++11 image-processing video-processing file-handling


【解决方案1】:

实际上 YUV 4:2:0 平面首先存储所有 Y 像素,然后是 U 像素,然后是 V 像素 要提取正确的像素,请使用以下论坛:

//Refer wikipedia for further details
size.total = size.width * size.height;
 y = yuv[position.y * size.width + position.x];
 u = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total];
 v = yuv[(position.y / 2) * (size.width / 2) + (position.x / 2) + size.total +           (size.total / 4)];

YUV2RGBTestApp2.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <string>
#include <stdio.h>

unsigned char *g_pcRGBbuffer;
unsigned char *g_pcYUVBuffer;

int  _tmain(int argc, _TCHAR* argv[])
{
    int l_nSize = 1920 * 1080 * 1.5;
    g_pcYUVBuffer = new unsigned char[l_nSize];
    g_pcRGBbuffer = new unsigned char[1920 * 1080 * 3];
    FILE *fp_source;
    FILE *fp_rgb = NULL;
    int l_ny, l_nu, l_nv, l_ni, RGBval;
    int l_dr, l_dg, l_db;
    fp_source = fopen("D:\\Sample_1920x1080.yuv", "rb");
    int l_nj;


//converting yuv file to rgb file
     if (fp_source) {
          fp_rgb = fopen("D:\\Sample_1920x1080.rgb", "wb");
          while (!feof(fp_source))
            {
                fread(g_pcYUVBuffer, 1, l_nSize, fp_source);
                unsigned char *l_pcRGBbuffer = g_pcRGBbuffer;
                for (int j = 0; j < 1080; j++)
                {
                   for (int i = 0; i<1920; i++)
                    {
                   /*
                          Position  for y,u,v components for yuv planar 4:2:0  
                          Refer wikipedia for further reference  
                            
                   */
                      int Y = g_pcYUVBuffer[j * 1920 + i];
                      int U = g_pcYUVBuffer[((j / 2) * 960) + (i / 2) + (1920 * 1080)];
                      int V = g_pcYUVBuffer[((j / 2) * 960) + (i / 2) + (1920 * 1080) + ((1920 * 1080) / 4)];

                       int R = 1.164*(Y - 16) + 1.596*(V - 128);
                       int G = 1.164*(Y - 16) - 0.813*(V - 128) - 0.391*(U - 128);
                       int B = 1.164*(Y - 16) + 2.018*(U - 128);



                       if (R>255)R = 255;
                       if (R<0)R = 0;
                       if (G>255)G = 255;
                       if (G<0)G = 0;
                       if (B>255)B = 255;
                       if (B<0)B = 0;


                       l_pcRGBbuffer[0] = R;
                       l_pcRGBbuffer[1] = G;
                       l_pcRGBbuffer[2] = B;
                       l_pcRGBbuffer += 3;

                }
             }
        
            fwrite(g_pcRGBbuffer, 1, 1920 * 1080 * 3, fp_rgb);
        }

        printf("Video converted to rgb file \n ");

     }
     else {
        printf("fail\n");
   }

    fclose(fp_rgb);
    fclose(fp_source);
    return 0;
}

【讨论】:

  • 干得好!感谢您与社区分享。您也可以“接受”自己的答案并获得分数。
猜你喜欢
  • 1970-01-01
  • 2017-06-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-11-25
  • 2021-03-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多