Python编程:ISP中色彩空间转换

色彩空间转换(Color Space Conversion)是图像处理中的基础操作,用于在不同颜色表示系统之间进行转换。下面介绍常见的色彩空间及其转换方法,并提供Python实现示例。

常见色彩空间概述

色彩空间主要用途通道组成特点
RGB显示器显示红(R)、绿(G)、蓝(B)设备相关,直观
HSV/HSL颜色选择、分析色调(H)、饱和度(S)、明度(V)/亮度(L)更符合人类感知
LAB颜色差异测量明度(L)、a(红绿轴)、b(黄蓝轴)设备无关,均匀色差
YUV/YCbCr视频压缩亮度(Y)、色度(UV/CbCr)分离亮度和色度
CMYK印刷青(C)、品红(M)、黄(Y)、黑(K)减色混合

Python基础转换方法

1. 使用OpenCV进行转换

import cv2
import numpy as np

# 读取图像(BGR格式)
img_bgr = cv2.imread('image.jpg')

# BGR转RGB
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# BGR转HSV
img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

# BGR转LAB
img_lab = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2LAB)

# BGR转YCrCb
img_ycrcb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2YCrCb)

# 显示转换结果
def show_images(images, titles):
    for i, (img, title) in enumerate(zip(images, titles)):
        cv2.imshow(title, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

show_images(
    [img_bgr, img_rgb, img_hsv[:,:,0], img_lab[:,:,0]], 
    ['BGR', 'RGB', 'HSV-Hue', 'LAB-L']
)

2. 手动实现RGB转HSV

def rgb_to_hsv(rgb_img):
    """手动实现RGB到HSV转换"""
    img = rgb_img.astype('float32') / 255.0
    r, g, b = cv2.split(img)
    
    # 计算值(Value)
    v = np.maximum.reduce([r, g, b])
    
    # 计算饱和度(Saturation)
    min_val = np.minimum.reduce([r, g, b])
    delta = v - min_val
    s = np.where(v == 0, 0, delta / v)
    
    # 计算色调(Hue)
    h = np.zeros_like(v)
    mask = delta != 0
    
    # 红色为基准
    idx = (v == r) & mask
    h[idx] = (60 * ((g[idx] - b[idx]) / delta[idx]) + 360) % 360
    
    # 绿色为基准
    idx = (v == g) & mask
    h[idx] = (60 * ((b[idx] - r[idx]) / delta[idx]) + 120) % 360
    
    # 蓝色为基准
    idx = (v == b) & mask
    h[idx] = (60 * ((r[idx] - g[idx]) / delta[idx]) + 240) % 360
    
    # 归一化到OpenCV标准范围
    h = h / 2  # [0,180]
    s = s * 255  # [0,255]
    v = v * 255  # [0,255]
    
    return cv2.merge([h, s, v]).astype('uint8')

# 使用示例
hsv_manual = rgb_to_hsv(img_rgb)
hsv_opencv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2HSV)

# 比较手动实现与OpenCV结果
print("差异:", np.sum(np.abs(hsv_manual - hsv_opencv)))

高级色彩空间转换

1. RGB与LAB的精确转换

def rgb_to_lab(rgb_img):
    """
    RGB转LAB色彩空间(精确实现)
    参考: http://www.easyrgb.com/en/math.php
    """
    # 转换为float32并归一化
    rgb = rgb_img.astype('float32') / 255.0
    
    # 线性化RGB(去除gamma校正)
    mask = rgb <= 0.04045
    rgb_linear = np.where(mask, rgb / 12.92, ((rgb + 0.055) / 1.055) ** 2.4)
    
    # 转换为XYZ色彩空间
    x = rgb_linear[...,0] * 0.4124 + rgb_linear[...,1] * 0.3576 + rgb_linear[...,2] * 0.1805
    y = rgb_linear[...,0] * 0.2126 + rgb_linear[...,1] * 0.7152 + rgb_linear[...,2] * 0.0722
    z = rgb_linear[...,0] * 0.0193 + rgb_linear[...,1] * 0.1192 + rgb_linear[...,2] * 0.9505
    
    # 归一化到白点D65
    x /= 0.95047
    y /= 1.0
    z /= 1.08883
    
    # 非线性变换
    epsilon = 216/24389
    kappa = 24389/27
    
    # 计算f(t)
    def f(t):
        return np.where(t > epsilon, t ** (1/3), (kappa * t + 16) / 116)
    
    fx = f(x)
    fy = f(y)
    fz = f(z)
    
    # 计算LAB
    l = 116 * fy - 16
    a = 500 * (fx - fy)
    b = 200 * (fy - fz)
    
    # 转换为OpenCV范围
    l = l * 255 / 100
    a = a + 128
    b = b + 128
    
    return cv2.merge([l, a, b]).astype('uint8')

# 使用示例
lab_manual = rgb_to_lab(img_rgb)
lab_opencv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2LAB)

# 比较结果
print("L通道差异:", np.mean(np.abs(lab_manual[:,:,0] - lab_opencv[:,:,0])))

2. 色彩空间转换矩阵优化

def apply_color_matrix(img, matrix):
    """应用色彩转换矩阵"""
    # 重塑为(像素数, 3)
    orig_shape = img.shape
    pixels = img.reshape(-1, 3).astype('float32')
    
    # 添加齐次坐标
    pixels = np.hstack([pixels, np.ones((pixels.shape[0], 1))])
    
    # 应用矩阵变换
    transformed = np.dot(pixels, matrix.T)
    
    # 裁剪并重塑回原形状
    transformed = np.clip(transformed[:,:3], 0, 255).reshape(orig_shape)
    return transformed.astype('uint8')

# RGB转YUV矩阵
rgb_to_yuv_matrix = np.array([
    [0.299, 0.587, 0.114, 0],
    [-0.14713, -0.28886, 0.436, 128],
    [0.615, -0.51499, -0.10001, 128]
])

# 使用示例
yuv_manual = apply_color_matrix(img_rgb, rgb_to_yuv_matrix)
yuv_opencv = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2YUV)

print("YUV转换差异:", np.mean(np.abs(yuv_manual - yuv_opencv)))

色彩空间应用案例

1. 基于HSV的颜色检测

def detect_color_hsv(image, lower_hsv, upper_hsv):
    """使用HSV空间检测特定颜色范围"""
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    mask = cv2.inRange(hsv, lower_hsv, upper_hsv)
    result = cv2.bitwise_and(image, image, mask=mask)
    return result

# 检测红色范围
lower_red = np.array([0, 120, 70])
upper_red = np.array([10, 255, 255])
red_objects = detect_color_hsv(img_bgr, lower_red, upper_red)

# 显示结果
cv2.imshow('Red Objects', red_objects)
cv2.waitKey(0)

2. 基于LAB的色彩增强

def lab_color_enhance(image, l_scale=1.2, a_scale=1.1, b_scale=1.1):
    """在LAB空间增强色彩"""
    lab = cv2.cvtColor(image, cv2.COLOR_BGR2LAB)
    l, a, b = cv2.split(lab)
    
    # 增强各通道
    l = np.clip(l * l_scale, 0, 255)
    a = np.clip(a * a_scale - 0.5*(a_scale-1)*128, 0, 255)
    b = np.clip(b * b_scale - 0.5*(b_scale-1)*128, 0, 255)
    
    enhanced_lab = cv2.merge([l, a, b])
    return cv2.cvtColor(enhanced_lab, cv2.COLOR_LAB2BGR)

# 使用示例
enhanced = lab_color_enhance(img_bgr)
cv2.imshow('Original vs Enhanced', np.hstack([img_bgr, enhanced]))
cv2.waitKey(0)

性能优化

1. 使用查找表(LUT)加速

def build_3d_lut(input_space, output_space, size=33):
    """构建3D色彩查找表"""
    # 创建输入网格
    axis = np.linspace(0, 255, size)
    grid = np.stack(np.meshgrid(axis, axis, axis, indexing='ij'), axis=-1)
    
    # 转换色彩空间
    lut = cv2.cvtColor(grid.astype('float32'), input_space, output_space)
    return lut.astype('float32')

# 构建RGB到LAB的3D LUT
rgb_to_lab_lut = build_3d_lut(cv2.COLOR_RGB2LAB, size=17)

def apply_3d_lut(image, lut):
    """应用3D LUT进行色彩转换"""
    # 归一化图像到LUT尺寸
    scaled = (image * (lut.shape[0]-1) / 255.0).astype('float32')
    
    # 三线性插值
    from scipy.interpolate import RegularGridInterpolator
    axes = [np.linspace(0, 255, lut.shape[i]) for i in range(3)]
    interpolator = RegularGridInterpolator(axes, lut, method='linear')
    
    # 应用插值
    return interpolator(scaled.reshape(-1, 3)).reshape(image.shape)

# 使用示例(适用于小图像)
small_img = cv2.resize(img_rgb, (200, 200))
lab_lut = apply_3d_lut(small_img, rgb_to_lab_lut)

2. 使用Numba加速

from numba import jit

@jit(nopython=True)
def rgb_to_hsv_numba(rgb_img):
    """使用Numba加速的RGB转HSV"""
    hsv = np.empty_like(rgb_img)
    for i in range(rgb_img.shape[0]):
        for j in range(rgb_img.shape[1]):
            r, g, b = rgb_img[i,j] / 255.0
            
            max_val = max(r, g, b)
            min_val = min(r, g, b)
            delta = max_val - min_val
            
            # 计算Value
            v = max_val
            
            # 计算Saturation
            s = 0 if max_val == 0 else delta / max_val
            
            # 计算Hue
            if delta == 0:
                h = 0
            elif max_val == r:
                h = 60 * ((g - b) / delta % 6)
            elif max_val == g:
                h = 60 * ((b - r) / delta + 2)
            else:
                h = 60 * ((r - g) / delta + 4)
            
            # 转换为OpenCV范围
            hsv[i,j,0] = h / 2
            hsv[i,j,1] = s * 255
            hsv[i,j,2] = v * 255
    
    return hsv.astype('uint8')

# 使用示例
hsv_numba = rgb_to_hsv_numba(img_rgb)

注意事项

  1. 数据范围

    • OpenCV的HSV:H∈[0,179], S∈[0,255], V∈[0,255]

    • OpenCV的LAB:L∈[0,255], a∈[0,255], b∈[0,255]

  2. 色彩空间特性

    • HSV/HSL对亮度变化敏感

    • LAB对颜色差异感知均匀

    • YUV/YCrCb适合压缩处理

  3. 性能考虑

    • 优先使用OpenCV内置函数

    • 大图像考虑使用LUT或GPU加速

    • 避免不必要的色彩空间转换

  4. gamma校正

    • RGB↔LAB转换需要考虑gamma校正

    • 使用cv2.COLOR_BGR2LAB时OpenCV会自动处理

完整色彩处理流程示例

def professional_color_grading(image):
    """专业的色彩分级流程"""
    # 1. 转换为浮点并归一化
    img_float = image.astype('float32') / 255.0
    
    # 2. 反gamma校正(sRGB -> 线性RGB)
    linear = np.where(
        img_float <= 0.04045,
        img_float / 12.92,
        ((img_float + 0.055) / 1.055) ** 2.4
    )
    
    # 3. 转换为LAB色彩空间(通过XYZ)
    # 线性RGB转XYZ
    xyz = np.empty_like(linear)
    xyz[...,0] = linear[...,0] * 0.4124 + linear[...,1] * 0.3576 + linear[...,2] * 0.1805
    xyz[...,1] = linear[...,0] * 0.2126 + linear[...,1] * 0.7152 + linear[...,2] * 0.0722
    xyz[...,2] = linear[...,0] * 0.0193 + linear[...,1] * 0.1192 + linear[...,2] * 0.9505
    
    # XYZ转LAB
    xyz[...,0] /= 0.95047  # D65白点
    xyz[...,2] /= 1.08883
    
    epsilon = 216/24389
    kappa = 24389/27
    
    def f(t):
        return np.where(t > epsilon, t ** (1/3), (kappa * t + 16) / 116)
    
    fx = f(xyz[...,0])
    fy = f(xyz[...,1])
    fz = f(xyz[...,2])
    
    lab = np.empty_like(xyz)
    lab[...,0] = 116 * fy - 16  # L [0,100]
    lab[...,1] = 500 * (fx - fy) # a [-128,127]
    lab[...,2] = 200 * (fy - fz) # b [-128,127]
    
    # 4. 在LAB空间进行色彩调整
    lab[...,0] = np.clip(lab[...,0] * 1.1, 0, 100)  # 增强亮度
    lab[...,1] *= 1.2  # 增强a通道
    lab[...,2] *= 0.9  # 减弱b通道
    
    # 5. LAB转回RGB
    # LAB转XYZ
    fy = (lab[...,0] + 16) / 116
    fx = lab[...,1] / 500 + fy
    fz = fy - lab[...,2] / 200
    
    def inv_f(t):
        return np.where(t > 6/29, t**3, 3*(6/29)**2*(t-4/29))
    
    xyz[...,1] = inv_f(fy)
    xyz[...,0] = inv_f(fx) * 0.95047
    xyz[...,2] = inv_f(fz) * 1.08883
    
    # XYZ转线性RGB
    linear[...,0] = xyz[...,0] * 3.2406 + xyz[...,1] * -1.5372 + xyz[...,2] * -0.4986
    linear[...,1] = xyz[...,0] * -0.9689 + xyz[...,1] * 1.8758 + xyz[...,2] * 0.0415
    linear[...,2] = xyz[...,0] * 0.0557 + xyz[...,1] * -0.2040 + xyz[...,2] * 1.0570
    
    # 线性RGB转sRGB
    srgb = np.where(
        linear <= 0.0031308,
        12.92 * linear,
        1.055 * (linear ** (1/2.4)) - 0.055
    )
    
    # 6. 转换为8位图像
    return (np.clip(srgb, 0, 1) * 255).astype('uint8')

# 使用示例
graded = professional_color_grading(img_bgr)
cv2.imshow('Original vs Graded', np.hstack([img_bgr, graded]))
cv2.waitKey(0)

ISP中的颜色空间转换

颜色空间转换是图像信号处理(ISP)流水线中的关键环节,负责在不同颜色表示系统之间进行转换,以满足不同处理阶段的需求。

ISP中颜色空间转换的典型流程

1. ISP流水线中的颜色空间位置

Sensor RAW → 黑电平校正 → 镜头阴影校正 → 去马赛克 → 
颜色空间转换 → 白平衡 → 色彩校正 → 伽马校正 → 色彩空间转换 → 输出

2. 常见转换路径

  1. 传感器原始数据(Raw Bayer) → RGB

  2. RGB → YUV/YCbCr (用于视频编码)

  3. RGB → HSV/HSL (用于色彩分析)

  4. RGB → LAB (用于色彩增强)

  5. YUV → RGB (用于显示)

颜色空间转换算法

1. Bayer RAW 转 RGB (去马赛克)

def bayer_to_rgb(bayer, pattern='RGGB'):
    """
    Bayer格式转RGB图像(简单双线性插值)
    :param bayer: 单通道Bayer图像
    :param pattern: Bayer模式(RGGB/GBRG等)
    :return: RGB图像
    """
    h, w = bayer.shape
    rgb = np.zeros((h, w, 3), dtype=bayer.dtype)
    
    if pattern == 'RGGB':
        # R通道
        rgb[0::2, 0::2, 0] = bayer[0::2, 0::2]  # R位置
        rgb[0::2, 1::2, 0] = (bayer[0::2, 0::2] + bayer[0::2, 2::2]) // 2  # 水平插值
        rgb[1::2, :, 0] = rgb[0::2, :, 0]  # 垂直复制
        
        # G通道
        rgb[0::2, 1::2, 1] = bayer[0::2, 1::2]  # G位置(第一行)
        rgb[1::2, 0::2, 1] = bayer[1::2, 0::2]  # G位置(第二行)
        # 插值缺失的G像素
        for i in range(1, h-1):
            for j in range(1, w-1):
                if (i % 2 == 0 and j % 2 == 1) or (i % 2 == 1 and j % 2 == 0):
                    continue
                rgb[i,j,1] = (bayer[i-1,j] + bayer[i+1,j] + bayer[i,j-1] + bayer[i,j+1]) // 4
        
        # B通道
        rgb[1::2, 1::2, 2] = bayer[1::2, 1::2]  # B位置
        rgb[1::2, 0::2, 2] = (bayer[1::2, 1::2] + bayer[1::2, -1:1:-2]) // 2  # 水平插值
        rgb[0::2, :, 2] = rgb[1::2, :, 2]  # 垂直复制
    
    return rgb

2. RGB 转 YUV/YCbCr (ISP常用)

def rgb_to_yuv(rgb, version='bt601'):
    """
    RGB转YUV色彩空间
    :param version: 标准版本(bt601/bt709/bt2020)
    """
    if version == 'bt601':
        # ITU-R BT.601标准
        matrix = np.array([
            [0.299, 0.587, 0.114],
            [-0.168736, -0.331264, 0.5],
            [0.5, -0.418688, -0.081312]
        ])
    elif version == 'bt709':
        # ITU-R BT.709标准
        matrix = np.array([
            [0.2126, 0.7152, 0.0722],
            [-0.114572, -0.385428, 0.5],
            [0.5, -0.454153, -0.045847]
        ])
    else:  # bt2020
        matrix = np.array([
            [0.2627, 0.6780, 0.0593],
            [-0.139630, -0.360370, 0.5],
            [0.5, -0.459786, -0.040214]
        ])
    
    yuv = np.dot(rgb.reshape(-1, 3), matrix.T)
    yuv[..., 1:] += 128  # UV分量加偏移
    
    return yuv.reshape(rgb.shape).clip(0, 255).astype('uint8')

3. YUV 转 RGB (显示处理)

def yuv_to_rgb(yuv, version='bt601'):
    """YUV转RGB空间"""
    yuv = yuv.copy().astype('float32')
    yuv[..., 1:] -= 128  # UV分量减偏移
    
    if version == 'bt601':
        matrix = np.array([
            [1.0, 0.0, 1.402],
            [1.0, -0.344136, -0.714136],
            [1.0, 1.772, 0.0]
        ])
    elif version == 'bt709':
        matrix = np.array([
            [1.0, 0.0, 1.5748],
            [1.0, -0.187324, -0.468124],
            [1.0, 1.8556, 0.0]
        ])
    else:  # bt2020
        matrix = np.array([
            [1.0, 0.0, 1.4746],
            [1.0, -0.164553, -0.571353],
            [1.0, 1.8814, 0.0]
        ])
    
    rgb = np.dot(yuv.reshape(-1, 3), matrix.T)
    return rgb.reshape(yuv.shape).clip(0, 255).astype('uint8')

ISP专用颜色空间转换

1. 传感器RGB转标准RGB (Color Correction Matrix)

def apply_ccm(rgb, ccm):
    """
    应用色彩校正矩阵(CCM)
    :param rgb: 传感器RGB图像(0-255)
    :param ccm: 3x3色彩校正矩阵
    :return: 校正后的RGB图像
    """
    # 转换为浮点并归一化
    rgb_float = rgb.astype('float32') / 255.0
    
    # 重塑为(像素数, 3)并应用矩阵
    pixels = rgb_float.reshape(-1, 3)
    corrected = np.dot(pixels, ccm.T)
    
    # 裁剪并转换回原格式
    corrected = np.clip(corrected, 0, 1).reshape(rgb.shape)
    return (corrected * 255).astype('uint8')

# 示例CCM矩阵(需根据传感器校准)
ccm_matrix = np.array([
    [1.5, -0.3, -0.2],
    [-0.1, 1.2, -0.1],
    [0.1, -0.2, 1.1]
])

# 使用示例
corrected_rgb = apply_ccm(raw_rgb, ccm_matrix)

2. RGB转HSV用于ISP色彩分析

def rgb_to_hsv_isp(rgb):
    """
    ISP优化的RGB转HSV实现
    :param rgb: 输入RGB图像(0-255)
    :return: HSV图像(H:0-360, S:0-1, V:0-1)
    """
    rgb = rgb.astype('float32') / 255.0
    r, g, b = rgb[...,0], rgb[...,1], rgb[...,2]
    
    max_val = np.max(rgb, axis=-1)
    min_val = np.min(rgb, axis=-1)
    delta = max_val - min_val
    
    # 计算Hue
    h = np.zeros_like(max_val)
    mask = delta != 0
    
    # 红色为基准
    idx = (max_val == r) & mask
    h[idx] = (60 * ((g[idx] - b[idx]) / delta[idx]) + 360) % 360
    
    # 绿色为基准
    idx = (max_val == g) & mask
    h[idx] = 60 * ((b[idx] - r[idx]) / delta[idx] + 2)
    
    # 蓝色为基准
    idx = (max_val == b) & mask
    h[idx] = 60 * ((r[idx] - g[idx]) / delta[idx] + 4)
    
    # 计算Saturation
    s = np.where(max_val == 0, 0, delta / max_val)
    
    return np.stack([h, s, max_val], axis=-1)

def hsv_to_rgb_isp(hsv):
    """HSV转RGB(ISP优化版)"""
    h, s, v = hsv[...,0], hsv[...,1], hsv[...,2]
    
    c = v * s
    x = c * (1 - np.abs((h / 60) % 2 - 1))
    m = v - c
    
    rgb_prime = np.zeros_like(hsv)
    
    mask = (0 <= h) & (h < 60)
    rgb_prime[mask] = np.stack([c[mask], x[mask], np.zeros_like(c[mask])], axis=-1)
    
    mask = (60 <= h) & (h < 120)
    rgb_prime[mask] = np.stack([x[mask], c[mask], np.zeros_like(c[mask])], axis=-1)
    
    mask = (120 <= h) & (h < 180)
    rgb_prime[mask] = np.stack([np.zeros_like(c[mask]), c[mask], x[mask]], axis=-1)
    
    mask = (180 <= h) & (h < 240)
    rgb_prime[mask] = np.stack([np.zeros_like(c[mask]), x[mask], c[mask]], axis=-1)
    
    mask = (240 <= h) & (h < 300)
    rgb_prime[mask] = np.stack([x[mask], np.zeros_like(c[mask]), c[mask]], axis=-1)
    
    mask = (300 <= h) & (h < 360)
    rgb_prime[mask] = np.stack([c[mask], np.zeros_like(c[mask]), x[mask]], axis=-1)
    
    rgb = (rgb_prime + m[..., np.newaxis]) * 255
    return np.clip(rgb, 0, 255).astype('uint8')

ISP颜色空间转换优化

1. 定点数优化 (适合硬件实现)

def rgb_to_yuv_fixed_point(rgb, bits=8):
    """
    定点数实现的RGB转YUV
    :param bits: 定点数位数
    """
    scale = 1 << bits
    rgb_int = (rgb * (scale / 255.0)).astype('int32')
    
    # BT.601系数转换为定点数
    y = ((77 * rgb_int[...,0] + 150 * rgb_int[...,1] + 29 * rgb_int[...,2]) + 128) >> 8
    u = ((-43 * rgb_int[...,0] - 85 * rgb_int[...,1] + 128 * rgb_int[...,2]) >> 8) + (128 << bits)
    v = ((128 * rgb_int[...,0] - 107 * rgb_int[...,1] - 21 * rgb_int[...,2]) >> 8) + (128 << bits)
    
    yuv = np.stack([y, u, v], axis=-1)
    return (yuv / scale * 255).clip(0, 255).astype('uint8')

2. 查表法(LUT)优化

def build_rgb_to_yuv_lut(version='bt601'):
    """构建RGB到YUV的3D LUT"""
    lut = np.zeros((256, 256, 256, 3), dtype='float32')
    
    for r in range(256):
        for g in range(256):
            for b in range(256):
                rgb = np.array([r, g, b], dtype='float32')
                lut[r,g,b] = rgb_to_yuv(rgb[np.newaxis, np.newaxis], version)[0,0]
    
    return lut

# 预构建LUT(实际使用时应预计算保存)
yuv_lut = build_rgb_to_yuv_lut()

def rgb_to_yuv_lut(rgb, lut):
    """使用LUT进行RGB到YUV转换"""
    return lut[rgb[...,0], rgb[...,1], rgb[...,2]]

3. 多线程加速

from multiprocessing import Pool

def parallel_convert(args):
    """并行转换函数"""
    chunk, convert_func = args
    return convert_func(chunk)

def rgb_to_yuv_parallel(rgb, convert_func, workers=4):
    """多线程颜色空间转换"""
    # 分割图像
    chunks = np.array_split(rgb, workers)
    
    # 创建进程池
    with Pool(workers) as pool:
        results = pool.map(parallel_convert, [(chunk, convert_func) for chunk in chunks])
    
    return np.concatenate(results)

ISP颜色处理流水线示例

def isp_color_pipeline(raw_bayer, ccm, gamma=2.2):
    """
    简化的ISP颜色处理流水线
    :param raw_bayer: 原始Bayer数据
    :param ccm: 色彩校正矩阵
    :param gamma: 伽马值
    :return: 处理后的RGB图像
    """
    # 1. Bayer转RGB
    rgb = bayer_to_rgb(raw_bayer, 'RGGB')
    
    # 2. 应用色彩校正矩阵
    rgb = apply_ccm(rgb, ccm)
    
    # 3. 白平衡(简单灰度世界算法)
    rgb_float = rgb.astype('float32')
    avg_r = np.mean(rgb_float[...,0])
    avg_g = np.mean(rgb_float[...,1])
    avg_b = np.mean(rgb_float[...,2])
    rgb_float[...,0] *= avg_g / avg_r
    rgb_float[...,2] *= avg_g / avg_b
    rgb = np.clip(rgb_float, 0, 255).astype('uint8')
    
    # 4. 色彩空间转换(RGB->YUV用于降噪)
    yuv = rgb_to_yuv(rgb)
    
    # 5. 只在Y通道进行降噪(示例:简单均值滤波)
    yuv[...,0] = cv2.blur(yuv[...,0], (3,3))
    
    # 6. 转回RGB
    rgb = yuv_to_rgb(yuv)
    
    # 7. 伽马校正
    rgb = gamma_correction(rgb, gamma)
    
    return rgb

颜色空间转换的验证方法

1. 往返测试(Round-trip Testing)

def test_round_trip_conversion():
    """测试颜色空间转换的准确性"""
    test_img = np.random.randint(0, 256, (100, 100, 3), dtype='uint8')
    
    # RGB <-> YUV
    yuv = rgb_to_yuv(test_img)
    rgb_back = yuv_to_rgb(yuv)
    error = np.mean(np.abs(test_img - rgb_back))
    print(f"RGB<->YUV 平均误差: {error:.2f}")
    
    # RGB <-> HSV
    hsv = rgb_to_hsv_isp(test_img)
    rgb_back = hsv_to_rgb_isp(hsv)
    error = np.mean(np.abs(test_img - rgb_back))
    print(f"RGB<->HSV 平均误差: {error:.2f}")

test_round_trip_conversion()

2. 色彩一致性检查

def check_color_constancy():
    """检查色彩一致性"""
    # 创建测试色块
    colors = [
        ('Red', [255, 0, 0]),
        ('Green', [0, 255, 0]),
        ('Blue', [0, 0, 255]),
        ('White', [255, 255, 255]),
        ('Gray', [128, 128, 128])
    ]
    
    for name, color in colors:
        rgb = np.array(color).reshape(1, 1, 3)
        yuv = rgb_to_yuv(rgb)
        rgb_back = yuv_to_rgb(yuv)
        
        print(f"{name:6s} RGB: {rgb[0,0]} -> YUV: {yuv[0,0].astype(int)} -> RGB: {rgb_back[0,0]}")

check_color_constancy()

ISP中的颜色空间转换需要兼顾精度和性能,在实际实现中通常会根据具体硬件平台(如DSP、GPU或专用ISP)选择最优的实现方式。理解不同颜色空间的特性对于设计高效的ISP流水线至关重要。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值