YUYVコードストリームからシングルフレームを抽出してRGBピクチャに変換

5582 ワード

YUVとRGBはいずれも色空間符号化であり,この2つの色空間間を変換するにはメモリレイアウトの状況が当然知られている.以下、この2つの色空間の符号化状況を簡単に説明する.
RGBの色空間は私たちがよく知っているはずです.それぞれRed、Green、Blueの3つのベース色で、成分ごとに1バイトを占めています.値は0-255で、3つの0は黒で、3つの255は白で、3つのバイトごとに1つの画素です.もちろん、私たちの多くの場合の処理では、alphaチャネルを加えて透明度を表し、組み合わせるとrgbaの4つのチャネルになる可能性があります.
YUVには2つの種類がありますが、平面フォーマットとパッケージフォーマット、具体的にはどのような違いがありますか.具体的なストレージフォーマットを知ってこそ、各画素を処理することができます.平面フォーマットはYUVの3つの成分Y,U,Vを分けて保存し、例えば3つの配列の中に置く.パッケージ形式はYUVの3つの成分を一緒に置いて、一定の符号化順序で1つの配列に格納する.ここでいうYUYVフォーマットとしては、メモリレイアウトの具体的な方法として、YUYV YUYV......、成分ごとに1バイトを占有し、2バイトごとに16ビットを1画素とし、2画素ごとに1組が巨大画素であり、2画素ごとに2つの巨大画素のうち2つのY成分と1つのUV成分が見られます.これはYUYVが4:2:2のフォーマットでパッケージされているためです.その他のyuv形式は以下の通りであるが、YUY 2からY 211まではパッケージ形式であり、IF 09からYVU 9までは平面形式である.yuvの詳細についてはこちらをご覧ください.
MEDIASUBTYPE_YUY2 
YUY 2形式で、4:2:2でテイクアウト
MEDIASUBTYPE_YUYV 
YUYV形式(実形式はYUY 2と同じ)
MEDIASUBTYPE_YVYU 
YVYU形式で、4:2:2でテイクアウト
MEDIASUBTYPE_UYVY 
UYVY形式で4:2:2でパッケージ化
MEDIASUBTYPE_AYUVバンドAlphaチャネルの4:4:4
YUV形式
MEDIASUBTYPE_Y41P 
Y 41 P形式、4:1:1でパッケージ化
MEDIASUBTYPE_Y411 
Y 411形式(実際の形式はY 41 Pと同じ)
MEDIASUBTYPE_Y211 
Y 211形式
MEDIASUBTYPE_IF 09 IF 09フォーマット
MEDIASUBTYPE_IYUV IYUV形式
MEDIASUBTYPE_YV 12 YV 12フォーマット
MEDIASUBTYPE_YVU 9 YVU 9フォーマット
これらのフォーマットの処理方法は、YUYVの処理方法と似ていますが、パッケージ形式が異なるため、メモリにおけるYUV成分の具体的な符号化方法が異なります.YUVの詳細を見て、列挙した各採集方法がよく分からない場合は、スケッチやYUVのレイアウトを自分で描いてみて理解してください.それらの異なる採集方式は異なる処理方式に対応し、以下は主にYUYVフォーマットを例に紹介する.
まず、長いと高い2つの変数を持つ画像を想定します.まず、画像を処理変換するとき、この2つの変数widthとheightは変わらないことを明確にします.つまり、RGB画像1枚とYUV画像1枚で、それらの長さと高さは同じで、これは私たちの後続の処理にとって重要です.同時にその長さと高さは画素点を基本単位としているので、総画素はこの図の面積width*heightであり、widthもheightも変わらない以上、1枚のピクチャの総画素点はきっと変わらないので、ピクチャの1行に占めるメモリはwidth*(1画素点に占めるバイト数)であり、これらに対して明確な概念があれば、処理が容易になる.1枚のRGB 24画像はalphaチャネルを考慮しないで、それでは1つの画素が3バイトを占有して、alphaチャネルRGB 32を考慮して、1つの画素は4バイトを占有します.
YUV形式の画像では、その色度サンプリング率、すなわちそのUV成分だけが低下しているが、輝度成分Yは低下していないので、ここでは具体的な説明は省略する.例えば、4:4:4のサンプリング方式は、1つのY成分が1つのU成分と1つのV成分に対応し、低下しない.4:2:2は2つのYが1つのUV成分を共用している.4:2:0は4つのYが1つのUV成分を共有している.そのため、画素点数は依然として変化していません.例えば、YUYVフォーマットは16ビットの1画素で、1枚の画像が占有する総メモリは:width*height*2で、その他のフォーマットのメモリの占有状況はここを見ることができます.
以下、YUYVコードストリームを抽出するシングルフレーム処理を行い、YUYVフォーマットのシングルフレームピクチャが占めるメモリはwidth*height*2であるべきであることが明らかになった.yuvフォーマットとrgb間の変換には対応する公式があり、ネット上で多くの説明を探すと、ここでは紹介しない.
次はyuyv回転rgb 24の関数です.
int convert_yuv_to_rgb_pixel(int y, int u, int v)
{
 unsigned int pixel32 = 0;
 unsigned char *pixel = (unsigned char *)&pixel32;
 int r, g, b;
 r = y + (1.370705 * (v-128));
 g = y - (0.698001 * (v-128)) - (0.337633 * (u-128));
 b = y + (1.732446 * (u-128));
 if(r > 255) r = 255;
 if(g > 255) g = 255;
 if(b > 255) b = 255;
 if(r < 0) r = 0;
 if(g < 0) g = 0;
 if(b < 0) b = 0;
 pixel[0] = r * 220 / 256;
 pixel[1] = g * 220 / 256;
 pixel[2] = b * 220 / 256;
 return pixel32;
}

int convert_yuv_to_rgb_buffer(unsigned char *yuv, unsigned char *rgb, unsigned int width, unsigned int height)
{
 unsigned int in, out = 0;
 unsigned int pixel_16;
 unsigned char pixel_24[3];
 unsigned int pixel32;
 int y0, u, y1, v;
 for(in = 0; in < width * height * 2; in += 4) {
  pixel_16 =
   yuv[in + 3] << 24 |
   yuv[in + 2] << 16 |
   yuv[in + 1] <<  8 |
   yuv[in + 0];
  y0 = (pixel_16 & 0x000000ff);
  u  = (pixel_16 & 0x0000ff00) >>  8;
  y1 = (pixel_16 & 0x00ff0000) >> 16;
  v  = (pixel_16 & 0xff000000) >> 24;
  pixel32 = convert_yuv_to_rgb_pixel(y0, u, v);
  pixel_24[0] = (pixel32 & 0x000000ff);
  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
  rgb[out++] = pixel_24[0];
  rgb[out++] = pixel_24[1];
  rgb[out++] = pixel_24[2];
  pixel32 = convert_yuv_to_rgb_pixel(y1, u, v);
  pixel_24[0] = (pixel32 & 0x000000ff);
  pixel_24[1] = (pixel32 & 0x0000ff00) >> 8;
  pixel_24[2] = (pixel32 & 0x00ff0000) >> 16;
  rgb[out++] = pixel_24[0];
  rgb[out++] = pixel_24[1];
  rgb[out++] = pixel_24[2];
 }
 return 0;
}

次はテストコードです.
    // , 
    QFile file("G:/Documents/QtProject/yuyvSplit/flower_yuyv422_352X288.yuv");
    if(!file.open(QIODevice::ReadOnly))
    {
        qDebug() << "open file failed.";
        return;
    }

    int width = 352;
    int height = 288;
    int frames  = 250;  //yuyv 
    int singleCounts = width * height * 2;
    int yuyvCounts = singleCounts * 250;
	int yuyvPitch = width * 2;    //yuyv  

    int rgb24Size = width * height * 3;
	int rgb32Size = width * height * 4;
	int rgb32Pitch = width * 4;   //rgb32  
    int rgb24Pitch = width * 3;

    qDebug() << "yuyvCounts: " << yuyvCounts << "
fileSize: " << file.size(); for(int i = 0; i < 1; ++i ) { char *singleFrame = new char[singleCounts](); int ret = file.read(singleFrame, singleCounts); qDebug() << "read return size: " << ret << " signleCounts: " << singleCounts; char *rgb24 = new char[rgb24Size](); convert_yuv_to_rgb_buffer((unsigned char*)singleFrame, (unsigned char*)rgb24, width, height); // QT , rgb24buffer image.bmp , // ,bmp , jpg,png 。 QImage *img = new QImage((unsigned char*)rgb24, width, height, rgb24Pitch, QImage::Format_RGB888); // ui->image->setPixmap(QPixmap::fromImage(*img)); delete[] singleFrame; delete[] rgb32; } file.close();

YUVコードストリームファイルはこのツールで開くことができて、yuvコードストリームのフレーム数を直接見ることができて、使うYUYVファイルはここを見て、提供者に感謝します!