Color Spaces
Không gian màu
Bạn cần phát hiện đèn đỏ giao thông. Trong ảnh RGB, 'đỏ sáng' có R=255, G=50, B=50 nhưng 'đỏ tối' có R=150, G=20, B=20 — giá trị rất khác nhau! Làm sao lọc dễ dàng hơn?
Kéo 3 slider R / G / B bên dưới. Các ô bên phải sẽ cập nhật LIVE sang HSV, HSL, LAB và Grayscale — kèm hình minh hoạ (bánh xe HSV, xi-lanh HSL, mặt phẳng a*b* của LAB).
Hình minh họa
Thử preset nhanh
RGB
(66, 135, 245)
HSL
(216.9°, 90%, 61%)
HSV
(216.9°, 73%, 96%)
LAB / Gray
L=57.1 a=14.9 b=-61.4
HSV — bánh xe màu
Góc = Hue (216.9°). Bán kính = Saturation (73%). Value (96%) là 'độ sáng' của bánh xe.
HSL — xi-lanh màu
Trục dọc = Lightness (61%). HSL khác HSV: L=0.5 là màu thuần, L=1 là trắng (HSV không có 'trắng' như vậy).
LAB — mặt phẳng a*b*
a* = 14.9 (đỏ-xanh lá). b* = -61.4 (vàng-xanh dương). L = 57.1 (độ sáng 0-100).
| Không gian | Giá trị | Ghi chú |
|---|---|---|
| RGB (sRGB) | R=66 · G=135 · B=245 | Chuẩn lưu trữ trên mọi thiết bị. |
| HSV | H=216.9° · S=73% · V=96% | Dễ lọc theo sắc — tốt cho segmentation. |
| HSL | H=216.9° · S=90% · L=61% | Phổ biến trong CSS, thiết kế UI. |
| LAB | L=57.1 · a=14.9 · b=-61.4 | Đồng đều tri giác — khoảng cách ≈ khác biệt thị giác. |
| Grayscale | Y=127 | 0.299R + 0.587G + 0.114B (Rec. 601). |
Kéo slider và quan sát: khi bạn chỉ tăng R, kênh H trong HSV thay đổi tinh tế, L trong HSL thay đổi theo công thức khác; LAB có a* tăng rõ (do R tăng = dịch về phía 'đỏ'). Đây là minh chứng các không gian màu có 'cảm giác' khác nhau với cùng một thay đổi vật lý.
Bạn cần so sánh màu da trong ảnh y tế để phát hiện tổn thương (vết nám, viêm). RGB cho kết quả không ổn định vì ảnh hưởng bởi ánh sáng chụp. Dùng không gian màu nào?
Giải thích
Không gian màu là hệ thống toán học biểu diễn màu sắc. Mỗi không gian phù hợp với mục đích khác nhau trong xử lý ảnh và thị giác máy tính. Bản thân 'màu' là cảm giác chủ quan do não bộ tạo ra khi photon kích thích 3 loại tế bào nón (L/M/S) — vì vậy mọi biểu diễn đều là xấp xỉ.
RGB (Red, Green, Blue): Chuẩn lưu trữ ảnh. 3 kênh x 0-255. Phụ thuộc ánh sáng, không tách riêng sắc/sáng. sRGB là biến thể chuẩn cho web/màn hình thông thường.
HSV (Hue, Saturation, Value): Tách sắc màu khỏi độ sáng. Lọc màu cụ thể rất dễ. Tốt cho segmentation theo màu (đèn giao thông, biển báo).
HSL (Hue, Saturation, Lightness): Giống HSV nhưng L khác V — trong HSL, L=1 là trắng (S=0), trong HSV V=1 có thể vẫn là màu thuần. HSL phổ biến trong CSS & thiết kế UI.
LAB (CIE L*a*b*): Đồng đều tri giác. Khoảng cách Euclidean = sự khác biệt thị giác (ΔE). Device-independent — chuẩn trao đổi giữa thiết bị.
YCrCb / YUV: Tách luminance (Y) khỏi chrominance (Cr, Cb). Dùng trong nén JPEG, phát video, detect da người.
Grayscale: 1 kênh (0-255). Bỏ màu, giữ cấu trúc. Nhanh 3x, tốt cho edge detection, OCR.
Công thức chuyển RGB sang Grayscale (weighted average theo tri giác, Rec. 601):
Mắt người nhạy với xanh lá (0.587) hơn đỏ (0.299) và xanh dương (0.114). Chuẩn BT.709 (HDTV) dùng hệ số khác một chút: 0.2126, 0.7152, 0.0722.
Công thức RGB → HSV (với M = max, m = min):
Khoảng cách trong LAB (ΔE*76):
ΔE < 1: mắt không phân biệt. ΔE 1-3: cần tinh mắt. ΔE > 5: khác biệt rõ. Phiên bản ΔE*2000 chính xác hơn nhưng phức tạp.
- Camera giao thông TP.HCM / HN: HSV để phát hiện đèn đỏ, biển báo theo màu (xanh, đỏ, vàng) — robust với đèn đường ban đêm.
- Nông nghiệp (cà phê, thanh long): HSV/LAB để phân biệt lá khoẻ (xanh bão hoà) vs lá bệnh (vàng/nâu). LAB cho bài 'độ chín' trái thanh long chính xác hơn HSV.
- eKYC (CCCD): Grayscale + edge detection cho OCR trên CCCD. YCrCb cho face detection / liveness.
- In ấn / dệt may:LAB để kiểm tra màu sắc đồng đều giữa các lô sản phẩm (ΔE < 2).
- Y tế da liễu: LAB so sánh nốt ruồi giữa 2 lần khám để phát hiện melanoma (ABCDE rule).
import cv2
import numpy as np
# -------------------------------------------------------
# 1. Đọc ảnh — OpenCV mặc định đọc theo BGR (không phải RGB!)
# -------------------------------------------------------
img_bgr = cv2.imread("den_giao_thong.jpg")
print("Shape:", img_bgr.shape) # (H, W, 3)
# -------------------------------------------------------
# 2. Chuyển sang HSV — lọc đèn đỏ
# -------------------------------------------------------
hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
# Đỏ trong HSV của OpenCV: H 0-10 hoặc 160-179 (H ở OpenCV chia đôi: 0-179)
mask_red1 = cv2.inRange(hsv, (0, 100, 100), (10, 255, 255))
mask_red2 = cv2.inRange(hsv, (160, 100, 100), (179, 255, 255))
mask_red = mask_red1 | mask_red2
# Ứng dụng: tìm contour đèn đỏ
contours, _ = cv2.findContours(mask_red, cv2.RETR_EXTERNAL,
cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
area = cv2.contourArea(c)
if area > 100:
x, y, w, h = cv2.boundingRect(c)
cv2.rectangle(img_bgr, (x, y), (x+w, y+h), (0, 255, 0), 2)
# -------------------------------------------------------
# 3. Chuyển sang LAB — so sánh màu chính xác tri giác
# -------------------------------------------------------
lab = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2LAB)
# OpenCV LAB: L in [0, 255], a in [0, 255] (offset 128), b in [0, 255]
def delta_e76(lab1, lab2):
"""ΔE*76 — khoảng cách Euclidean trong LAB."""
return np.sqrt(np.sum((lab1.astype(float) - lab2.astype(float))**2))
pixel1 = lab[100, 100]
pixel2 = lab[200, 200]
print(f"ΔE giữa hai điểm: {delta_e76(pixel1, pixel2):.2f}")
# -------------------------------------------------------
# 4. Chuyển sang Grayscale — OCR, edge detection
# -------------------------------------------------------
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
edges = cv2.Canny(gray, 100, 200) # Canny edge detector
# -------------------------------------------------------
# 5. YCrCb — tốt cho skin detection (eKYC VN)
# -------------------------------------------------------
ycrcb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YCrCb)
# Vùng da tiêu chuẩn (Chai & Ngan, 1999): Cr 133-173, Cb 77-127
skin_mask = cv2.inRange(ycrcb, (0, 133, 77), (255, 173, 127))
# Hậu xử lý: morphology để bớt noise
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
skin_mask = cv2.morphologyEx(skin_mask, cv2.MORPH_OPEN, kernel)
skin_mask = cv2.morphologyEx(skin_mask, cv2.MORPH_CLOSE, kernel)
# -------------------------------------------------------
# 6. HSV normalization — robust với điều kiện sáng khác
# -------------------------------------------------------
def normalize_brightness(img_bgr):
"""Chuẩn hoá V trong HSV bằng CLAHE — giảm phụ thuộc ánh sáng."""
hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
v_eq = clahe.apply(v)
hsv_eq = cv2.merge([h, s, v_eq])
return cv2.cvtColor(hsv_eq, cv2.COLOR_HSV2BGR)
img_equalized = normalize_brightness(img_bgr)
# -------------------------------------------------------
# 7. Lưu kết quả
# -------------------------------------------------------
cv2.imwrite("out_mask_red.png", mask_red)
cv2.imwrite("out_edges.png", edges)
cv2.imwrite("out_skin.png", skin_mask)
cv2.imwrite("out_equalized.png", img_equalized)
print("Xong.")Ưu điểm: Chuẩn lưu trữ trên mọi thiết bị, không cần chuyển đổi. Mỗi pixel = 3 byte, dễ xử lý song song GPU.
Nhược điểm: Phụ thuộc mạnh vào ánh sáng chụp. 'Đỏ sáng' và 'đỏ tối' khác nhau cả 3 kênh — khó viết ngưỡng. Không đồng đều tri giác.
Khi dùng: Input/output cuối (hiển thị, lưu file). Training CNN (vì CNN có thể tự học các không gian 'tốt' nếu đủ data).
Team của bạn xây hệ thống đếm cà phê chín (đỏ) trên cây. Ảnh chụp ngoài vườn nắng gắt vs bóng râm khác nhau rất lớn. Pipeline nào ổn định NHẤT?
- RGB là chuẩn lưu trữ (3 kênh 0-255) nhưng phụ thuộc ánh sáng — khó lọc theo màu trực tiếp.
- HSV / HSL tách Hue (sắc) khỏi Value/Lightness (sáng) — lý tưởng cho segmentation theo màu (đèn giao thông, trái chín). Chú ý Hue là không gian tròn.
- LAB đồng đều tri giác — khoảng cách Euclidean ≈ khác biệt mắt người. Device-independent. Dùng cho y tế, in ấn, kiểm tra chất lượng màu (ΔE).
- Grayscale bỏ màu giữ cấu trúc, nhanh 3x. Chuẩn cho edge detection, OCR, feature matching; không phân biệt được màu cùng độ sáng.
- YCrCb tách luminance khỏi chrominance — chuẩn cho nén video/JPEG, tốt cho skin detection (Cr 133-173, Cb 77-127).
- Quy tắc ngón tay cái: hiển thị/lưu → RGB; lọc màu → HSV; so sánh chính xác → LAB; tốc độ/OCR → Grayscale; skin/video → YCrCb.
Kiểm tra hiểu biết
Tại sao HSV tốt hơn RGB cho bài toán phát hiện đèn đỏ giao thông?