傳統 CRT 螢幕以三電子槍激發紅綠藍螢光粉,每像素 24 位元(各 8 位元),可呈現約 1,670 萬色(真彩色)。掃描方式為逐行掃描,由上而下完成一幀。
電視採用隔行掃描:奇數場掃描 1、3、5... 行,偶數場掃描 2、4、6... 行。中國採 PAL 制式,625 行、25 幀/秒、50 場/秒。隔行掃描使動態影像更平滑。
YUV 為歐洲電視系統採用編碼:Y = 亮度(相容黑白電視),U/V = 色度。PAL 制式下常見 720×576 解析度。
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(...));
}
}
}
每像素 16 位元,排序:[U0 Y0 V0 Y1] [U1 Y2 V1 Y3] [U2 Y4 V2 Y5]... 兩像素共用一組 U/V 分量。
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
}
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
}
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));
}
依序讀取上場/下場資料,解析 UYVY 交織格式,呼叫 YUV2RGB 後以 SetPixel 繪製還原影像。
本文詳細說明 RGB/YUV 轉換原理、隔行掃描處理、UYVY 格式交織邏輯,附完整 VC6.0 + MFC 實作碼。YUV 格式眾多(YV12, NV12, I420 等),本文以 UYVY 為例拋磚引玉。