首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

RGB 與 YUV 影像格式相互轉換完整實作指南

     編輯:關於VC++

顯示技術基礎知識

CRT 螢幕與 RGB 色彩空間

傳統 CRT 螢幕以三電子槍激發紅綠藍螢光粉,每像素 24 位元(各 8 位元),可呈現約 1,670 萬色(真彩色)。掃描方式為逐行掃描,由上而下完成一幀。

電視訊號與隔行掃描

電視採用隔行掃描:奇數場掃描 1、3、5... 行,偶數場掃描 2、4、6... 行。中國採 PAL 制式,625 行、25 幀/秒、50 場/秒。隔行掃描使動態影像更平滑。

YUV 色彩空間

YUV 為歐洲電視系統採用編碼:Y = 亮度(相容黑白電視),U/V = 色度。PAL 制式下常見 720×576 解析度。


隔行讀取 BMP 實作

BMP 儲存順序為左至右、下至上。隔行顯示需先繪奇數行(上場),再繪偶數行(下場):

void CRGB2YUVView::OnReadBmp()
{
    // ... 開啟 BMP、讀取像素至 rgb 陣列 ...

    // 上場:奇數行
    for (int i = 0; i < bmih.biHeight; i++) {
        for (int j = 0; j < bmih.biWidth; j++) {
            if (!(i % 2))
                pDC->SetPixel(j, bmih.biHeight - i, RGB(...));
        }
    }
    Sleep(500);

    // 下場:偶數行
    for (int i = 0; i < bmih.biHeight; i++) {
        for (int j = 0; j < bmih.biWidth; j++) {
            if (i % 2)
                pDC->SetPixel(j, bmih.biHeight - i, RGB(...));
        }
    }
}

RGB 轉 YUV (UYVY 4:2:2 格式)

UYVY 位元組排序

每像素 16 位元,排序:[U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5]... 兩像素共用一組 U/V 分量。

轉換公式 (ITU-R BT.601)

Y  = 0.257*R + 0.504*G + 0.098*B + 16
Cb = -0.148*R - 0.291*G + 0.439*B + 128
Cr = 0.439*R - 0.368*G - 0.071*B + 128

核心轉換函式

void CRGB2YUVView::RGB2YUV(byte* pRGB, byte* pYUV)
{
    byte r = *pRGB++; byte g = *pRGB++; byte b = *pRGB;
    *pYUV++ = (byte)(0.257*r + 0.504*g + 0.098*b + 16);     // Y
    *pYUV++ = (byte)(-0.148*r - 0.291*g + 0.439*b + 128);   // U
    *pYUV   = (byte)(0.439*r - 0.368*g - 0.071*b + 128);    // V
}

完整 PAL 制式轉換流程 (720×576)

void CRGB2YUVView::OnConvertPAL()
{
    // ... 記憶體配置、BMP 讀取 ...

    // 上場處理
    for (int i = bmih.biHeight-1; i >= 0; i--) {
        for (int j = 0; j < bmih.biWidth; j++) {
            if (!(i % 2)) {
                // RGB→YUV 轉換
                RGB2YUV(bufRGB, bufYUV);
                yuv_y0 = bufYUV[0]; yuv_u0 = bufYUV[1]; yuv_v0 = bufYUV[2];

                // UYVY 交織寫入
                if ((j % 2) == 0) {
                    *Video_Field0++ = yuv_u0;
                    yuv_v1 = yuv_v0;  // 暫存 V 供下一像素用
                } else {
                    *Video_Field0++ = yuv_v1;
                }
                *Video_Field0++ = yuv_y0;
            }
        }
    }
    // 下場處理邏輯相同,寫入 Video_Field1
    // 最後寫入 .pal 檔案:上場 + 下場 = 720*576*2 = 829,440 bytes
}

YUV 轉 RGB 反向轉換

反轉換公式

R = 1.0*Y + 1.402*(V - 128)
G = 1.0*Y - 0.34413*(U - 128) - 0.71414*(V - 128)
B = 1.0*Y + 1.772*(U - 128)

實作挑戰與妥協

UYVY 4:2:2 格式下,每 4 位元組含 2 個 Y 與 1 組 U/V,無法完全還原每像素獨立 U/V。本實作採用「鄰近像素共用 U/V」近似法,肉眼幾乎無法分辨差異。

核心反轉換函式

void CRGB2YUVView::YUV2RGB(byte* pRGB, byte* pYUV)
{
    byte y = *pYUV++; byte u = *pYUV++; byte v = *pYUV;
    *pRGB++ = (byte)clamp(1.0*y + 1.402*(v-128));
    *pRGB++ = (byte)clamp(1.0*y - 0.34413*(u-128) - 0.71414*(v-128));
    *pRGB   = (byte)clamp(1.0*y + 1.772*(u-128));
}

PAL 檔案讀取與顯示流程

依序讀取上場/下場資料,解析 UYVY 交織格式,呼叫 YUV2RGB 後以 SetPixel 繪製還原影像。


結語與資源

本文詳細說明 RGB/YUV 轉換原理、隔行掃描處理、UYVY 格式交織邏輯,附完整 VC6.0 + MFC 實作碼。YUV 格式眾多(YV12, NV12, I420 等),本文以 UYVY 為例拋磚引玉。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved