文章目录
- 图像HSV模型简介
- RGB模型转HSV模型
- opencv关于HSV模型实验
- 随机增强图像HSV
图像HSV模型简介
HSV(Hue, Saturation, Value)是根据颜色的直观特性由A. R. Smith在1978年创建的一种颜色空间, 也称六角锥体模型(Hexcone Model)(参考百度)。在HSV模型中,颜色是由色度(Hue),饱和度(Saturation),明度(Value)共同组成。
如图所示,HSV模型中
- 色度(Hue)使用角度度量的,范围是从0°到360°(逆时针旋转),比如0°/360°代表红色, 120°代表原谅色,240°代表蓝色。
- 饱和度(Saturation)表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高(参考百度)。其范围是0到1。
- 明度(Value)颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关。其范围是0(暗)到1(明)。
RGB模型转HSV模型
参考opencv官方文档:https://docs.opencv.org/master/de/d25/imgproc_color_conversions.html#color_convert_rgb_hsv
首先将R,G,B分量数值缩放到范围0到1之间,即除以255. 接下来按如下公式进行转换即可。
V
=
m
a
x
(
R
,
G
,
B
)
S
=
{
V
−
min
(
R
,
G
,
B
)
V
i
f
V
≠
0
0
o
t
h
e
r
w
i
s
e
H
=
{
60
(
G
−
B
)
/
(
V
−
min
(
R
,
G
,
B
)
)
i
f
V
=
R
120
+
60
(
B
−
R
)
/
(
V
−
min
(
R
,
G
,
B
)
)
i
f
V
=
G
240
+
60
(
R
−
B
)
/
(
V
−
min
(
R
,
G
,
B
)
)
i
f
V
=
B
0
i
f
R
=
G
=
B
.
}
\begin{gathered} \mathrm{V~=max(R,G,B)} \\ \left.\mathrm{S}=\left\{\begin{matrix}\frac{\mathrm{V}-\min(\mathrm{R},\mathrm{G},\mathrm{B})}{\mathrm{V}}&\quad\mathrm{if~\mathrm{V}~\neq0}\\0&\quad\mathrm{otherwise}\end{matrix}\right.\right. \\ \\ \left.\mathrm{H=\left\{\begin{array}{ll}60(G-B)/(V-\min(R,G,B))&\mathrm{if~V=R}\\120+60(B-R)/(V-\min(R,G,B))&\mathrm{if~V=G}\\240+60(R-B)/(V-\min(R,G,B))&\mathrm{if~V=B}\\0&\mathrm{if~R=G=B}\end{array}\right. .}\right\} \end{gathered}
V =max(R,G,B)S={VV−min(R,G,B)0if V =0otherwiseH=⎩
⎨
⎧60(G−B)/(V−min(R,G,B))120+60(B−R)/(V−min(R,G,B))240+60(R−B)/(V−min(R,G,B))0if V=Rif V=Gif V=Bif R=G=B.⎭
⎬
⎫
转换之后V和S都是在0-1之间,H是在 0°到 360°之间(计算的结果可能小于0,如果小于0就加上360)。
假设要将像素(110, 20, 50)分别对应RGB分量,转换到HSV模型空间中。
那么转换后的V=0.4314,S=0.8183,由于H小于0所以加上360即H=340
opencv关于HSV模型实验
使用opencv将RGB模型图像转成HSV模型图像非常简单,直接使用cv2.cvtColor
函数,在code参数中传入cv2.COLOR_RGB2HSV
参数即可。 但需要注意一下,通过opencv转HSV后会根据传入的数据类型缩放到不同范围,如果输入的是Uint8类型的数据(一般读入的图片数据类型都是Uint8),默认缩放到0到255之间 。 那么对于饱和度和明度(默认0到1之间)而言直接乘以255然后取整即可。对于色度(默认是在0到360之间)由于超出了Uint8数据类型的范围,所以官方储存时是直接除以2即缩放到0到180之间。参考opencv官方文档:https://docs.opencv.org/master/de/d25/imgproc_color_conversions.html#color_convert_rgb_hsv
import cv2
import numpy as np
rgb = np.array([110, 20, 50], dtype=np.uint8).reshape((1, 1, 3))
hsv = cv2.cvtColor(rgb, cv2.COLOR_RGB2HSV)
print(hsv)
终端打印的结果是[[[170 209 110]]]
,和我们计算的是一样的,说明理解到位。
接下来在使用opencv来固定色度,饱和度,明度其中两个变量,渐变剩下一个变量来看看效果。
固定sat(饱和度)以及val(明度),渐变hue(色度)。从左到右数值从0到180(对应hue中 0 ° 0\degree 0°到 360 ° 360\degree 360°)
import cv2
import numpy as np
hue = np.tile(np.arange(0, 180, dtype=np.uint8).reshape((1, 180, 1)),
(50, 1, 1))
sat= np.ones((50, 180, 1), dtype=np.uint8) * 255
val = np.ones((50, 180, 1), dtype=np.uint8) * 255
img_hsv = cv2.merge((hue, sat, val))
img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
# img = cv2.resize(img, (720, 100))
cv2.imshow("img", img)
cv2.waitKey(0)
固定hue(色度)以及val(明度),渐变sat(饱和度)。从左到右数值从0到255(对应sat中 0 0 0到 1 1 1,饱和度越来越高)
import cv2
import numpy as np
hue = np.zeros((100, 256, 1), dtype=np.uint8)
sat = np.tile(np.arange(0, 256, dtype=np.uint8).reshape((1, 256, 1)),
(100, 1, 1))
val = np.ones((100, 256, 1), dtype=np.uint8) * 255
img_hsv = cv2.merge((hue, sat, val))
img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
# img = cv2.resize(img, (720, 100))
cv2.imshow("img", img)
cv2.waitKey(0)
固定hue(色度)以及sat(饱和度),渐变val(明度)。从左到右数值从0到255(对应val中0到 1,明度越来越高)
import cv2
import numpy as np
hue = np.zeros((100, 256, 1), dtype=np.uint8)
sat = np.ones((100, 256, 1), dtype=np.uint8) * 255
val = np.tile(np.arange(0, 256, dtype=np.uint8).reshape((1, 256, 1)),
(100, 1, 1))
img_hsv = cv2.merge((hue, sat, val))
img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
# img = cv2.resize(img, (720, 100))
cv2.imshow("img", img)
cv2.waitKey(0)
随机增强图像HSV
下面的代码来自之前讲的yolov3 spp
项目(增强方法并不唯一),这里结合以上讲的知识进行简单讲解。
- 首先传入图像
img
以及三个超参数h_gain,s_gain,v_gain
。 - 使用np.random.uniform增对h,s,v分别随机生成了一个[-1, 1]之间的随机数,然后分别乘上传入的
h_gain,s_gain,v_gain
,最后加上1。假设h_gain=0.5
那么会在[0.5, 1.5]之间随机生成一个倍率因子,后面会将所有hue
数值乘上这个倍率。s_gain,v_gain
同理不再赘述。 - 使用
cv2.cvtColor
函数将传入的图片由BGR格式(opencv读取图片的默认格式是BGR)转成HSV,在使用cv2.split
函数将HSV分量分开分别赋值给hue, sat, val
- 分别针对hue, sat以及val生成对应的Look-Up Table(LUT)查找表(记录变换前后数值的对应表)。就是将0-255范围内所有的数值都乘以刚刚生成的随机倍率因子构建LUT,后面针对每个元素直接查表无需再计算。注意,hue范围是在0到180之间的,所以有个取余的操作
%180
,sat和val范围是0到255之间,所以使用np.clip
防止越界。 - 使用
cv2.LUT
方法利用刚刚针对hue, sat以及val生成的Look-Up Table进行变换。变换后使用cv2.merge
方法再将hue, sat以及val分量合并个hsv图像。 - 最后使用
cv2.cvtColor
再将hsv图像转换回bgr图像。
import cv2
import numpy as np
def augment_hsv(img, h_gain=0.5, s_gain=0.5, v_gain=0.5):
r = np.random.uniform(-1, 1, 3) * [h_gain, s_gain, v_gain] + 1 # random gains
hue, sat, val = cv2.split(cv2.cvtColor(img, cv2.COLOR_BGR2HSV))
dtype = img.dtype # uint8
x = np.arange(0, 256, dtype=np.int16)
lut_hue = ((x * r[0]) % 180).astype(dtype)
lut_sat = np.clip(x * r[1], 0, 255).astype(dtype)
lut_val = np.clip(x * r[2], 0, 255).astype(dtype)
img_hsv = cv2.merge((cv2.LUT(hue, lut_hue), cv2.LUT(sat, lut_sat), cv2.LUT(val, lut_val))).astype(dtype)
aug_img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
return aug_img
下图是调用augment_hsv
随机增强前、后的效果,左图是随机增强前,右图是随机增强后。
LUT(val, lut_val).astype(dtype)
aug_img = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)
return aug_img
下图是调用augment_hsv
随机增强前、后的效果,左图是随机增强前,右图是随机增强后。