OpenCV-Python学习 <三> 颜色空间及其转换

我们常看到各种颜色空间类型,有RGB色彩空间, Gray(灰度)色彩空间,XYZ色彩空间,YCrCb色彩空间,HSV色彩空间,HLS色彩空间,Bayer色彩空间等。

不同的色彩空间都有其擅长处理的区域。所以就有了转换的需求。

1. 色彩空间的介绍:

1.1: Gray色彩空间:

Gray通常指8位灰度图,像素取值范围[0-255], 当图像由RG颜色空间转换为Gray色彩空间时,其处理方法如下:

Gray= 0.299*R + 0.587*G + .114*R

当Gray转换成RGB色彩空间时,则:

R= Gray

B = Gray

B = Gray

1.2: YCrCb色彩空间

人眼对颜色敏感度要低于对亮度的敏感度,在传统的RGB色彩空间,RGB三原色具有相同的重要性,当忽略了亮度信息。

YCrCb色彩空间中,Y代表光源的亮度,色彩信息保存在Cr(红色分量信息)和Cb(蓝色分量信息)中。

1.3:HSV色彩空间:

HSV是一种面向视觉感知的颜色模型。它从心理学和视觉的角度出发,之处人眼的色彩知觉主要包涵三要素:色调(Hue),饱和度(Saturation),亮度(Value).

这个色彩空间比较重要,后续会仔细讨论。

1.4: HLS色彩空间:

H(Hue), 光亮度 L(Lightness), 饱和度S(Saturation).

1.5:Bayer色彩空间:

被广泛应用于CCD和CMOS相机。

2.颜色空间的转换:

dst = cv2.cvtColor(src, code)

dst为输出图像.

src为输入图像。

code:色彩空间转换码。指出从何种色彩空间转换到何种色彩空间。

import cv2

data_bgr = cv2.imread("images/test1.webp", cv2.IMREAD_COLOR)

cv2.imshow("BGR", data_bgr)


rgb = cv2.cvtColor(data_bgr, cv2.COLOR_BGR2RGB)
cv2.imshow("RGB", rgb)

data_gray = cv2.cvtColor(data_bgr, cv2.COLOR_BGR2GRAY)
cv2.imshow("GRAY", data_gray)

cv2.waitKey()
cv2.destroyAllWindows()

3. Alpha通道:

在RGB色彩空间三通道的基础上,还可以增加一个A通道(alpha通道),表示透明度。

它叫做RBGA色彩空间。

alpha通道的取值范围是:[0,255]. 表示从透明到不透明。

img_bgr = cv2.imread("images/people.webp", cv2.IMREAD_COLOR)
img_BGRA = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2BGRA)
print(img_BGRA[:,:,3])

b,g,r,a = cv2.split(img_BGRA)
a[:,:] = 125
img_BGRA_125 = cv2.merge([b,g,r,a])
a[:,:] = 0
img_BGRA_0 = cv2.merge([b,g,r,a])


cv2.imshow("BGR", img_bgr)
cv2.imshow("255", img_BGRA)
cv2.imshow("125", img_BGRA_125)
cv2.imshow("0", img_BGRA_0)

cv2.waitKey()
cv2.destroyAllWindows()

cv2.imwrite("images/bgra_0.jpg", img_BGRA_0)
cv2.imwrite("images/bgra_125.jpg", img_BGRA_125)
cv2.imwrite("images/bgra_255.jpg", img_BGRA)

4. HSV色彩空间的使用

HSV色彩空间提供了通过其值直观的感知具体色彩的方式。

HSV色彩空间从心理学和视觉的角度出发,提出人类眼睛的色彩感知主要包括的三要素:

H:Hue, 色调。

S:Saturation. 饱和度

V: Value. 亮度

OpenCV-Python学习 <三> 颜色空间及其转换_第1张图片

4.1:HSV介绍:

H: Hue,色调:

在HSV色彩空间中,色调H的取值范围是[0,360].

用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°。它们的补色是:黄色为60°,青色为180°,紫色为300°;

为了能够在1个byte内存储,OpenCV把它的取值范围映射到[0,180].

0:红色。

30:黄色。

60:绿色

90:青色

120:蓝色

150:品红色。

(灰度图的H为0)

S: Saturation, 饱和度

饱和度S表示颜色接近光谱色的程度。一种颜色,可以看成是某种光谱色与白色混合的结果。其中光谱色所占的比例愈大,颜色接近光谱色的程度就愈高,颜色的饱和度也就愈高。饱和度高,颜色则深而艳。光谱色的白光成分为0,饱和度达到最高。通常取值范围为0%~100%,值越大,颜色越饱和。

灰度颜色所包含的R,G,B的成分相同相当于一种极不饱和的颜色。所以灰度颜色的饱和度为0.

如果颜色的饱和度很低,则它计算出的色调就不可靠。(如上图靠近圆锥轴心的地方)。

同样为了适应1byte的存储空间,OpenCV把其取值范围从[0,1]映射到[0,255].

V: Value,亮度

亮度表示颜色明亮的程度,对于光源色,明度值与发光体的光亮度有关;对于物体色,此值和物体的透射比或反射比有关。通常取值范围为0%(黑)到100%(白)。

4.2: HSV具体使用

4.2.1:查看指定颜色的HSV值。

主要是看H色调。

blue_point = np.zeros([1,1,3], dtype=np.uint8)
blue_point[0,0,0] = 255
print("Blue:\n", blue_point)
blue_hsv = cv2.cvtColor(blue_point, cv2.COLOR_BGR2HSV)
print("HSV:\n", blue_hsv)

green_point = np.zeros([1,1,3], dtype=np.uint8)
green_point[0,0,1] = 255
green_hsv = cv2.cvtColor(green_point, cv2.COLOR_BGR2HSV)
print("Green:\n", green_point)
print("Green HSV:\n", green_hsv)

red_point = np.zeros([1, 1, 3], dtype=np.uint8)
red_point[0, 0, 2] = 255
red_hsv = cv2.cvtColor(red_point, cv2.COLOR_BGR2HSV)
print("Red:\n", red_point)
print("Red HSV:\n", red_hsv)

创建了Blue, Green, Red三个点,并查看其HSV值。

Blue:
 [[[255   0   0]]]
HSV:
 [[[120 255 255]]]
Green:
 [[[  0 255   0]]]
Green HSV:
 [[[ 60 255 255]]]
Red:
 [[[  0   0 255]]]
Red HSV:
 [[[  0 255 255]]]

可以看到。对应颜色的H值和之前定义的相同。

4.2.2:利用HSV筛选指定颜色

在HSV色彩空间中,H通道对应的是不同的颜色。所以可以通过对H通道进行筛选,以找出特定的颜色的区域。

A. 利用cv2.inRange()判断像素的像素值是否处于指定的范围内. 获取掩码mask.

B. 利用位运算与cv2.bitwise_and(img, img, mask)把需要的像素提取出来。其它点置0.

C. 筛选颜色时,并不是只找H为指定值的,而是找一个区间。例如:蓝色H为120. 则找110-130之间的值。

S,V通道则通常取50-255之间,因为若饱和度和亮度太低时,色调就不可靠了。

例如:分别采集一张图像中的Red, Blue, Green元素并显示出来。

data_bgr = cv2.imread("images/opencv.webp", cv2.IMREAD_COLOR)
if(data_bgr is None):
    print("Read Image File Error.")
    sys.exit()

data_hsv = cv2.cvtColor(data_bgr, cv2.COLOR_BGR2HSV)

blue_min = np.array([110, 50, 50])
blue_max = np.array([130, 255, 255])
blue_mask = cv2.inRange(data_hsv, blue_min, blue_max)
blue_bgr = cv2.bitwise_and(data_bgr,data_bgr, mask=blue_mask)


green_mix = np.array([50, 50, 50])
green_max = np.array([70, 255, 255])
green_mask = cv2.inRange(data_hsv, green_mix, green_max)

green_bgr = cv2.bitwise_and(data_bgr, data_bgr, mask=green_mask)

red_mix = np.array([0, 50, 50])
red_max = np.array([30, 255, 255])
red_mask = cv2.inRange(data_hsv, red_mix, red_max)

red_bgr = cv2.bitwise_and(data_bgr, data_bgr, mask=red_mask)

cv2.imshow("BGR", data_bgr)
cv2.imshow('Blue', blue_bgr)
cv2.imshow("Green", green_bgr)
cv2.imshow("Red", red_bgr)
cv2.waitKey()
cv2.destroyAllWindows()

找肤色:

假定肤色区间为: H:[5-170]  S:[25,166]

#找肤色
data_bgr = cv2.imread("images/people.webp", cv2.IMREAD_COLOR)
if(data_bgr is None):
    print("Read File Error")
    sys.exit()

print("Image shape:", data_bgr.shape)
cv2.imshow("Orz", data_bgr)

data_hsv = cv2.cvtColor(data_bgr, cv2.COLOR_BGR2HSV)

p_min = np.array([5, 25, 50], dtype=np.uint8)
p_max = np.array([170, 166, 255], dtype=np.uint8)

p_mask = cv2.inRange(data_hsv, p_min, p_max)

p_roi = cv2.bitwise_and(data_bgr, data_bgr, mask=p_mask)

cv2.imshow("ROI", p_roi)


cv2.waitKey()
cv2.destroyAllWindows()

更改亮度:

#修改图像亮度
img_bgr= cv2.imread("images/people.webp", cv2.IMREAD_COLOR)

img_hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)

for i in range(img_bgr.shape[0]):
    for j in range(img_bgr.shape[1]):
        img_hsv[i,j,2] = 255
img_after = cv2.cvtColor(img_hsv, cv2.COLOR_HSV2BGR)

cv2.imshow("Before", img_bgr)
cv2.imshow("After", img_after)
cv2.waitKey()
cv2.destroyAllWindows()

再以找红色为例,理解HSV和cv2.inRange()

原图如下:

OpenCV-Python学习 <三> 颜色空间及其转换_第2张图片

若想把所有红色的像素提取出来。则可以利用cv2.inRange()

但红色的区域比较特殊,它的Hue以0为中心。所以可以把区域定为两个部分。

import cv2
import numpy as np
import sys


if __name__ == '__main__':
    img = cv2.imread("../images/red.png")
    if(img is None):
        sys.exit()

    img_hsv = cv2.cvtColor(img,code=cv2.COLOR_BGR2HSV)
    low_red1 = np.array([0, 150, 150])
    high_red1 = np.array([20, 255, 255])

    low_red2 = np.array([160, 150, 150])
    high_red2 = np.array([180, 255, 255])

    mask1 = cv2.inRange(img_hsv, low_red1, high_red1)
    mask2 = cv2.inRange(img_hsv, low_red2, high_red2)

    mask = cv2.bitwise_or(mask1, mask2)
    # print("mask shape:",mask.shape)
    # print("Image shape:", img_hsv.shape)


    cv2.imshow("Img", img)
    cv2.imshow("mask1", mask1)
    cv2.imshow("mask2", mask2)
    cv2.imshow("mask", mask)
    img_red = cv2.bitwise_and(img, img, mask=mask)
    cv2.imshow("Red", img_red)


    cv2.waitKey(0)
    cv2.destroyAllWindows()

产生两个mask, 利用cv2.bitwise_or()运算把他们合并到一起。

import cv2
import numpy as np
import sys


if __name__ == '__main__':
    img = cv2.imread("../images/red.png")
    if(img is None):
        sys.exit()

    img_hsv = cv2.cvtColor(img,code=cv2.COLOR_BGR2HSV)
    low_red1 = np.array([0, 150, 150])
    high_red1 = np.array([20, 255, 255])

    low_red2 = np.array([160, 150, 150])
    high_red2 = np.array([180, 255, 255])

    mask1 = cv2.inRange(img_hsv, low_red1, high_red1)
    mask2 = cv2.inRange(img_hsv, low_red2, high_red2)

    mask = cv2.bitwise_or(mask1, mask2)
    # print("mask shape:",mask.shape)
    # print("Image shape:", img_hsv.shape)


    cv2.imshow("Img", img)
    cv2.imshow("mask1", mask1)
    cv2.imshow("mask2", mask2)
    cv2.imshow("mask", mask)
    img_red = cv2.bitwise_and(img, img, mask=mask)
    cv2.imshow("Red", img_red)


    cv2.waitKey(0)
    cv2.destroyAllWindows()

结果如下:

OpenCV-Python学习 <三> 颜色空间及其转换_第3张图片

可以看到,mask1, mask2都没能取全。只有把他们俩or起来。才算取全了红色。

 

 

附录:

1. cv2.inRange()

dst = cv2.inRange(src, lowerb, upperb)

src: 输入的array, 表示要检查的数组或图像。

lowerb: 下边界。 ( array or a scalar)

upperb:上边界。( array or a scalar)

dst: 输出array. 和src相同。 CV_8U type。在lowerb~upperb之间的值变成255。 否则变为0.

2.按位逻辑运算:

cv2.bitwise_and()

cv2.bitwise_or()

cv2.bitwise_xor()

cv2.bitwise_not()

dst = cv2.bitwise_and(src1,src2 [, mask] )

src1和src2按位与。

如果由mask, 操作只会在掩码值为非空的像素点上执行。 并将其它像素点置0.

你可能感兴趣的:(OpenCV,Python,python)