Color Space Conversion(顏色空間轉換)
是圖像處理中的一個重要步驟,它將圖像從一個顏色空間(Color Space)轉換到另一個,以滿足 顯示、分析、壓縮或算法需求。
為什么轉換顏色空間?
應用場景 | 常用顏色空間 |
---|---|
圖像壓縮(JPEG) | RGB → YCbCr(壓縮色度) |
人臉/物體檢測 | RGB → HSV(更容易識別膚色/顏色區域) |
白平衡 / 曝光控制 | RGB / Lab / YCbCr |
圖像增強 / 調色 | HSV / HSL |
色彩分割 / 識別 | HSV / Lab |
?
-
Y(Luma) 表示圖像的亮度(明暗信息)
-
Cb(Blue-difference Chroma) 表示藍色色差
-
Cr(Red-difference Chroma) 表示紅色色差
它們是從 RGB 轉換而來的三個通道,組合在一起可以重建出原始的顏色圖像。
為什么用 YCbCr 而不是 RGB?
因為:人眼對 亮度(Y)很敏感,但對顏色細節(CbCr)沒那么敏感。
所以我們可以:
-
高質量保留 Y(清晰度、輪廓都在這里)
-
對 Cb、Cr 進行壓縮、降采樣、去噪都不會影響視覺感受太多
RGB → YCbCr 轉換公式:
這里加 128 是為了讓 Cb/Cr 落在 [0, 255]
的無符號整型范圍內(方便存儲)
?RGB->YCbCr
def CSC(gac_img):"""Convert gamma-corrected RGB image to Y and CbCr channels.Args:gac_img: np.ndarray, dtype=uint8, RGB image after gamma correction.Returns:y: np.ndarray, dtype=uint8, grayscale image (luma channel)cbcr_img: np.ndarray, dtype=uint8, two-channel image (Cb and Cr)"""gac_img = gac_img.astype(np.float32)r = gac_img[:, :, 0]g = gac_img[:, :, 1]b = gac_img[:, :, 2]# Y is luma (perceptual grayscale)y = 0.299 * r + 0.587 * g + 0.114 * b# Cb and Cr are chroma (color difference)cb = 0.564 * (b - y)cr = 0.713 * (r - y)# Shift cb/cr to 128-centered range to store in 8-bit (optional, like JPEG)cb = np.clip(cb + 128, 0, 255).astype(np.uint8)cr = np.clip(cr + 128, 0, 255).astype(np.uint8)y = np.clip(y, 0, 255).astype(np.uint8)cbcr_img = np.dstack((cb, cr))return y, cbcr_img
為啥 Cb/Cr 要加 128?
-
原始 Cb/Cr 值在
[-127, +127]
左右 -
加上 128 把它們映射到
[0, 255]
范圍,以便 8-bit 存儲 -
這是 JPEG 和 H.264 中的做法
?YCBCR->RGB:
def YCbCr_to_RGB(y, cbcr_img):"""Convert Y (luma) + CbCr (chroma) back to RGB.Inputs:y: np.ndarray, uint8, grayscale image (Y channel)cbcr_img: np.ndarray, uint8, (H, W, 2), Cb and Cr channelsReturns:rgb_img: np.ndarray, uint8, reconstructed RGB image"""y = y.astype(np.float32)cb = cbcr_img[:, :, 0].astype(np.float32) - 128.0cr = cbcr_img[:, :, 1].astype(np.float32) - 128.0# Inverse conversion from YCbCr to RGBr = y + 1.403 * crg = y - 0.344 * cb - 0.714 * crb = y + 1.773 * cb# Clip to valid [0, 255] ranger = np.clip(r, 0, 255).astype(np.uint8)g = np.clip(g, 0, 255).astype(np.uint8)b = np.clip(b, 0, 255).astype(np.uint8)rgb_img = np.dstack((r, g, b))return rgb_img