color_correction.py
# 本作品采用MIT许可证授权。
# 版权所有 (c) 2013-2024 OpenMV LLC。保留所有权利。
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# 色彩校正示例
#
# 此示例展示了如何使用色彩校正矩阵乘法
# 方法对图像应用通用矩阵乘法。
#
# 在下面的示例中,我们将:
# 1. 将图像从RGB转换为YUV。
# 2. 对UV分量应用旋转矩阵以引起色调偏移。
# 3. 对UV分量应用缩放值以引起饱和度偏移。
# 4. 将图像从YUV转换回RGB。
#
# 然而,我们不必依次对图像应用这4个步骤,而是可以
# 预先将它们相互结合,生成一个适合输入到
# 色彩校正矩阵方法的3x3矩阵。
#
# 通过转换色彩空间至YUV,可将像素"值"从
# 它们的“色调”和“饱和度”。“色调”就是U/V分量给出的旋转角度,
# 而“饱和度”是它们的幅值。
#
# |Y| | 0.299, 0.587, 0.114| |R|
# |U| = |-0.168736, -0.331264, 0.5| * |G|
# |V| | 0.5, -0.418688, -0.081312| |B|
#
# |Y_rot| |1, 0, 0| |Y|
# |U_rot| = |0, math.cos(a), -math.sin(a)| * |U|
# |V_rot| |0, math.sin(a), math.cos(a)| |V|
#
# |Y_rot_scaled| |1, 0, 0| |Y|
# |U_rot_scaled| = |0, s, 0| * |U|
# |V_rot_scaled| |0, 0, s| |V|
#
# |R_rot_scaled| | 0.299, 0.587, 0.114| |Y_rot_scaled|
# |R_rot_scaled| = 逆矩阵|-0.168736, -0.331264, 0.5| * |U_rot_scaled|
# |R_rot_scaled| | 0.5, -0.418688, -0.081312| |V_rot_scaled|
#
# 注意:ccm()方法可以接受3x3和3x4矩阵。3x4矩阵用于
# 需要应用偏移量的情况。此时公式如下:
#
# |Y| | 0.299, 0.587, 0.114, y_offset| |R|
# |U| = |-0.168736, -0.331264, 0.5, u_offset| * |G|
# |V| | 0.5, -0.418688, -0.081312, v_offset| |B|
# |1|
#
# 请记住,CCM方法只是执行以下操作:
#
# |R'| |R| |R'| |R|
# |G'| = 3x3 矩阵 * |G| 或 |G'| = 3x4 矩阵 * |G|
# |B'| |B| |B'| |B|
# |1|
#
# 如果您使用矩阵运算创建中间值,最终传给CCM()的矩阵
# 必须回到RGB值。
#
# 最后,您也可以使用4x4矩阵来构造矩阵。如果传入4x4矩阵,
# 最后一行将被忽略(即按3x4处理)。
from ulab import numpy as np
import csi
import time
import math
# 设为0得到灰度图像。设为大于1.0可提升饱和度。
UV_SCALE = 1.0
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
csi0.snapshot(time=2000)
# 这些是RGB转YUV的标准系数。
rgb2yuv = np.array([[ 0.299, 0.587, 0.114], # noqa
[-0.168736, -0.331264, 0.5], # noqa
[ 0.5, -0.418688, -0.081312]], dtype=np.float) # noqa
# 现在求逆矩阵,以便从YUV转回RGB。
yuv2rgb = np.linalg.inv(rgb2yuv)
clock = time.clock()
# r是我们在UV平面上旋转颜色的角度。
r = 0
while True:
clock.tick()
# 在循环中递增。
r = (r + 1) % 360
a = math.radians(r)
# 这是我们将应用于YUV值中UV分量的旋转矩阵。
# https://en.wikipedia.org/wiki/Rotation_matrix
rot = np.array([[1, 0, 0], # noqa
[0, math.cos(a), -math.sin(a)], # noqa
[0, math.sin(a), math.cos(a)]], dtype=np.float) # noqa
# 这是缩放矩阵
scale = np.array([[1, 0, 0], # noqa
[0, UV_SCALE, 0], # noqa
[0, 0, UV_SCALE]], dtype=np.float) # noqa
# 现在用矩阵乘法计算最终矩阵。
m = np.dot(yuv2rgb, np.dot(scale, np.dot(rot, rgb2yuv)))
# 应用颜色变换(m.flatten().tolist()也可以)
img = csi0.snapshot().ccm(m.tolist())
print(clock.fps())