Example: 02-Image-Processing/01-Image-Filters/color_correction.py
# 本作品采用MIT许可证授权。
# 版权所有 (c) 2013-2024 OpenMV LLC。保留所有权利。
# https://github.com/openmv/openmv/blob/master/LICENSE
#
# 色彩校正示例
#
# 此示例展示了如何使用色彩校正矩阵乘法
# 方法对图像应用通用矩阵乘法。
#
# 在下面的示例中,我们将:
# 1. Convert the image to YUV from RGB.
# 2. Apply a rotation matrix to the UV components to cause a Hue Shift.
# 3. Apply a scaling value to the UV components to cause a Saturation Shift.
# 4. Convert the image back from YUV to RGB.
#
# 然而,我们不必依次对图像应用这4个步骤,而是可以
# 预先将它们相互结合,生成一个适合输入到
# 色彩校正矩阵方法的3x3矩阵。
#
# 通过转换色彩空间至YUV,可将像素"值"从
# their "hue" and "saturation". The "hue" then is just the rotation angle given
# the U/V components and the "saturation" is their magnitude.
#
# |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|
#
# If you are creating intermediate values using matrix math you need to end
# up back at RGB values for the final matrix you pass to CCM().
#
# Finally, you are free to do the matrix formation using 4x4 matrices. The last
# row will be ignored if you pass a 4x4 matrix (e.g. it will be treated as 3x4).
from ulab import numpy as np
import sensor
import time
import math
# Set to 0 for a grayscale image. Set above 1.0 to pump-up the saturation.
UV_SCALE = 1.0
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
# These are the standard coefficents for converting RGB to 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
# Now get the inverse so we can get back to RGB from YUV.
yuv2rgb = np.linalg.inv(rgb2yuv)
clock = time.clock()
# r will be the angle by which we rotate the colors on the UV plane by.
r = 0
while True:
clock.tick()
# Increment in a loop.
r = (r + 1) % 360
a = math.radians(r)
# This is a rotation matrix which we will apply on the UV components of YUV values.
# 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
# This is the scale matrix
scale = np.array([[1, 0, 0], # noqa
[0, UV_SCALE, 0], # noqa
[0, 0, UV_SCALE]], dtype=np.float) # noqa
# Now compute the final matrix using matrix multiplication.
m = np.dot(yuv2rgb, np.dot(scale, np.dot(rot, rgb2yuv)))
# Apply the color transformation (m.flatten().tolist() also works)
img = sensor.snapshot().ccm(m.tolist())
print(clock.fps())