OpenCVChapter10.色彩转换与图像绘制

Posted zstar-_

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCVChapter10.色彩转换与图像绘制相关的知识,希望对你有一定的参考价值。

最近想对OpenCV进行系统学习,看到网上这份教程写得不错,于是跟着来学习实践一下。
【youcans@qq.com, youcans 的 OpenCV 例程, https://youcans.blog.csdn.net/article/details/125112487
程序仓库:https://github.com/zstar1003/OpenCV-Learning

色彩转换

颜色空间转换

常见的色彩空间包括:GRAY 色彩空间(灰度图像)、XYZ 色彩空间、YCrCb 色彩空间、HSV 色彩空间、HLS 色彩空间、CIELab 色彩空间、CIELuv 色彩空间、Bayer 色彩空间等。

色彩空间名词解释:

  • RGB:红色(Red)、绿色(Green)、蓝色(Blue);
  • HSV/HSB:色调(Hue)、饱和度(Saturation)和明度(Value/Brightness);
  • HSl:色调(Hue)、饱和度(Saturation)和灰度(Intensity);
  • HSL:包括色调(Hue)、饱和度(Saturation)和亮度(Luminance/Lightness)

常见色彩空间转换,这里只列举两个常见的。

  • RGB -> GRAY
    注意RGB可以转灰度,灰度不能转RGB
    转换公式:gray = 0.299 x R + 0.587 x G + 0.114 x B

  • RGB -> HSV
    RGB转HSV公式为

OpenCV提供了函数cv.cvtColor()可以将图像从一个颜色空间转换为另一个颜色空间。

cv.cvtColor(src, code [, dst, dstCn]]) → dst

参数说明:

  • src:输入图像,nparray 多维数组,8位无符号/ 16位无符号/单精度浮点数格式
  • code:颜色空间转换代码,详见 ColorConversionCodes
  • dst:输出图像,大小和深度与 src 相同
  • dstCn:输出图像的通道数,0 表示由src和code自动计算

示例程序:

"""
颜色空间转换
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

imgBGR = cv.imread("../img/img.jpg", flags=1)

imgRGB = cv.cvtColor(imgBGR, cv.COLOR_BGR2RGB)  # BGR 转换为 RGB, 用于 PyQt5, matplotlib
imgGRAY = cv.cvtColor(imgBGR, cv.COLOR_BGR2GRAY)  # BGR 转换为灰度图像
imgHSV = cv.cvtColor(imgBGR, cv.COLOR_BGR2HSV)  # BGR 转换为 HSV 图像
imgYCrCb = cv.cvtColor(imgBGR, cv.COLOR_BGR2YCrCb)  # BGR转YCrCb
imgHLS = cv.cvtColor(imgBGR, cv.COLOR_BGR2HLS)  # BGR 转 HLS 图像
imgXYZ = cv.cvtColor(imgBGR, cv.COLOR_BGR2XYZ)  # BGR 转 XYZ 图像
imgLAB = cv.cvtColor(imgBGR, cv.COLOR_BGR2LAB)  # BGR 转 LAB 图像
imgYUV = cv.cvtColor(imgBGR, cv.COLOR_BGR2YUV)  # BGR 转 YUV 图像

# 调用matplotlib显示处理结果
titles = ['BGR', 'RGB', 'GRAY', 'HSV', 'YCrCb', 'HLS', 'XYZ', 'LAB', 'YUV']
images = [imgBGR, imgRGB, imgGRAY, imgHSV, imgYCrCb,
          imgHLS, imgXYZ, imgLAB, imgYUV]
plt.figure(figsize=(10, 8))
for i in range(9):
    plt.subplot(3, 3, i + 1), plt.imshow(images[i], 'gray')
    plt.title(titles[i])
    plt.xticks([]), plt.yticks([])
plt.tight_layout()
plt.show()

颜色反转

图像颜色反转也称为反色变换,是像素颜色的逆转,将黑色像素点变白色,白色像素点变黑色,像素位置不变。
RGB图片实现颜色反转非常容易,一种简单的思路就是对每个像素点用255-颜色值。但是这样处理的效率不高。

OpenCV提供了一个查表函数cv.LUT可以快速实现像素值的改变。其本质就是先对每个0-255的像素灰度值建立一个变换字典,这样处理像素值就只需要从字典里去查找对应的数据进行替换,而无需再去运算。

下面的示例程序比较了两种方法的执行效率。

"""
图像颜色反转
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread("../img/img.jpg", flags=1)
h, w, ch = img.shape  # 图片的高度, 宽度 和通道数

timeBegin = cv.getTickCount()
imgInv = np.empty((w, h, ch), np.uint8)  # 创建空白数组
for i in range(h):
    for j in range(w):
        for k in range(ch):
            imgInv[i][j][k] = 255 - img[i][j][k]
timeEnd = cv.getTickCount()
time = (timeEnd - timeBegin) / cv.getTickFrequency()
print("图像反转(for 循环实现):  s".format(round(time, 4)))

timeBegin = cv.getTickCount()
transTable = np.array([(255 - i) for i in range(256)]).astype("uint8")
invLUT = cv.LUT(img, transTable)
timeEnd = cv.getTickCount()
time = (timeEnd - timeBegin) / cv.getTickFrequency()
print("图像反转(LUT 查表实现):  s".format(round(time, 4)))

plt.figure(figsize=(9, 6))
plt.subplot(131), plt.title("img"), plt.axis('off')
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(132), plt.title("imgInv"), plt.axis('off')
plt.imshow(cv.cvtColor(imgInv, cv.COLOR_BGR2RGB))
plt.subplot(133), plt.title("invLUT"), plt.axis('off')
plt.imshow(cv.cvtColor(invLUT, cv.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()

输出

图像反转(for 循环实现): 1.9181 s
图像反转(LUT 查表实现): 0.0326 s

由此可见两者速度差异还是比较明显的。

色彩风格滤镜

色彩风格滤镜就是OpenCV提供了一些色彩搭配方案,通过函数cv.applyColorMap可以进行调用。

OpenCV 提供了 22 种色彩风格类型:

ColorMaps[] =  
    "Autumn", "Bone", "Jet", "Winter", "Rainbow", "Ocean", "Summer", "Spring",
    "Cool", "HSV", "Pink", "Hot", "Parula", "Magma", "Inferno", "Plasma", "Viridis",
    "Cividis", "Twilight", "Twilight Shifted", "Turbo", "Deep Green";

示例程序:

"""
色彩风格滤镜
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread("../img/img.jpg", flags=1)

# 伪彩色处理
pseudo1 = cv.applyColorMap(img, colormap=cv.COLORMAP_PINK)
pseudo2 = cv.applyColorMap(img, colormap=cv.COLORMAP_JET)
pseudo3 = cv.applyColorMap(img, colormap=cv.COLORMAP_WINTER)
pseudo4 = cv.applyColorMap(img, colormap=cv.COLORMAP_RAINBOW)
pseudo5 = cv.applyColorMap(img, colormap=cv.COLORMAP_HOT)

plt.figure(figsize=(9, 6))
plt.subplot(231), plt.axis('off'), plt.title("Origin")
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(232), plt.axis('off'), plt.title("cv.COLORMAP_PINK")
plt.imshow(cv.cvtColor(pseudo1, cv.COLOR_BGR2RGB))
plt.subplot(233), plt.axis('off'), plt.title("cv.COLORMAP_JET")
plt.imshow(cv.cvtColor(pseudo2, cv.COLOR_BGR2RGB))
plt.subplot(234), plt.axis('off'), plt.title("cv.COLORMAP_WINTER")
plt.imshow(cv.cvtColor(pseudo3, cv.COLOR_BGR2RGB))
plt.subplot(235), plt.axis('off'), plt.title("cv.COLORMAP_RAINBOW")
plt.imshow(cv.cvtColor(pseudo4, cv.COLOR_BGR2RGB))
plt.subplot(236), plt.axis('off'), plt.title("cv.COLORMAP_HOT")
plt.imshow(cv.cvtColor(pseudo5, cv.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()

调节色彩

通过cv.LUT可以在RGB色彩范围内调节三通道的数值,从而调节色彩。
下面的示例程序将各通道的最大值设置为maxG,将某颜色通道的色阶从 0-255 映射到 0-maxG,就可以使该颜色通道的色彩衰减。

示例程序:

"""
调节色彩
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread("../img/img.jpg", flags=1)

maxG = 128  # 修改颜色通道最大值,0<=maxG<=255
lutHalf = np.array([int(i * maxG / 255) for i in range(256)]).astype("uint8")
lutEqual = np.array([i for i in range(256)]).astype("uint8")

lut3HalfB = np.dstack((lutHalf, lutEqual, lutEqual))  # (1,256,3), B_half/BGR
lut3HalfG = np.dstack((lutEqual, lutHalf, lutEqual))  # (1,256,3), G_half/BGR
lut3HalfR = np.dstack((lutEqual, lutEqual, lutHalf))  # (1,256,3), R_half/BGR

blendHalfB = cv.LUT(img, lut3HalfB)  # B 通道衰减 50%
blendHalfG = cv.LUT(img, lut3HalfG)  # G 通道衰减 50%
blendHalfR = cv.LUT(img, lut3HalfR)  # R 通道衰减 50%


plt.figure(figsize=(9, 5))
plt.subplot(131), plt.axis('off'), plt.title("B half decayed")
plt.imshow(cv.cvtColor(blendHalfB, cv.COLOR_BGR2RGB))
plt.subplot(132), plt.axis('off'), plt.title("G half decayed")
plt.imshow(cv.cvtColor(blendHalfG, cv.COLOR_BGR2RGB))
plt.subplot(133), plt.axis('off'), plt.title("R half decayed")
plt.imshow(cv.cvtColor(blendHalfR, cv.COLOR_BGR2RGB))
plt.tight_layout()
plt.show()

调节饱和度和明度

将RGB颜色空间转换到HSV空间,可以调整图片的饱和度和明度。

示例程序:

"""
调节饱和度和明度
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

img = cv.imread("../img/img.jpg", flags=1)
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)  # 色彩空间转换, BGR->HSV

# 调节通道强度
lutWeaken = np.array([int(0.6 * i) for i in range(256)]).astype("uint8")
lutEqual = np.array([i for i in range(256)]).astype("uint8")
lutRaisen = np.array([int(102 + 0.6 * i) for i in range(256)]).astype("uint8")
# 调节饱和度
lutSWeaken = np.dstack((lutEqual, lutWeaken, lutEqual))  # Saturation weaken
lutSRaisen = np.dstack((lutEqual, lutRaisen, lutEqual))  # Saturation raisen
# 调节明度
lutVWeaken = np.dstack((lutEqual, lutEqual, lutWeaken))  # Value weaken
lutVRaisen = np.dstack((lutEqual, lutEqual, lutRaisen))  # Value raisen

blendSWeaken = cv.LUT(hsv, lutSWeaken)  # 饱和度降低
blendSRaisen = cv.LUT(hsv, lutSRaisen)  # 饱和度增大
blendVWeaken = cv.LUT(hsv, lutVWeaken)  # 明度降低
blendVRaisen = cv.LUT(hsv, lutVRaisen)  # 明度升高

plt.figure(figsize=(9, 6))
plt.subplot(231), plt.axis('off'), plt.title("Saturation weaken")
plt.imshow(cv.cvtColor(blendSWeaken, cv.COLOR_HSV2RGB))
plt.subplot(232), plt.axis('off'), plt.title("Normal saturation")
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(233), plt.axis('off'), plt.title("Saturation raisen")
plt.imshow(cv.cvtColor(blendSRaisen, cv.COLOR_HSV2RGB))
plt.subplot(234), plt.axis('off'), plt.title("Value weaken")
plt.imshow(cv.cvtColor(blendVWeaken, cv.COLOR_HSV2RGB))
plt.subplot(235), plt.axis('off'), plt.title("Normal value")
plt.imshow(cv.cvtColor(img, cv.COLOR_BGR2RGB))
plt.subplot(236), plt.axis('off'), plt.title("Value raisen")
plt.imshow(cv.cvtColor(blendVRaisen, cv.COLOR_HSV2RGB))
plt.tight_layout()
plt.show()

图像绘制

绘制直线

函数cv.line()绘制图像中点pt1与点pt2之间的线段
函数cv.arrowedLine()绘制图像中点pt1与点pt2之间的带箭头线段

cv.line(img, pt1, pt2, color[, thickness=1, lineType=LINE_8, shift=0]) → img
cv.arrowedLine(img, pt1, pt2, color[, thickness=1, line_type=8, shift=0, tipLength=0.1]) → img

参数说明:

  • img:输入输出图像,允许单通道灰度图像或多通道彩色图像
  • pt1:线段第一个点的坐标,(x1, y1)
  • pt2:线段第二个点的坐标,(x2, y2)
  • tipLength:箭头部分长度与线段长度的比例,默认为 0.1

示例程序:

"""
绘制直线
"""
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np

height, width, channels = 200, 120, 3
img = np.ones((height, width, channels), np.uint8) * 160  # 创建黑色图像 RGB=0

# 注意 pt1, pt2 坐标的格式是 (x,y) 而不是 (y,x)
img1 = img.copy()
cv.line(img1, (0, 0), (200, 150), (0, 0, 255), 1)  # 红色 R=255
cv.line(img1, (0, 0), (150, 200), (0, 255, 0), 1)  # 绿色 G=255
cv.line(img1, (0, 50), (200, 50), (128, 0, 0), 2)  # 深蓝色 B = 128
cv.line(img1, (0, 100), (200, 100), 128, 2)  # color=128 等效于 (128,0,0)
cv.line(img1, (0, 150), (200, 150), 255, 2)  # color=255 等效于 (255,0,0)

# img2 = img.copy()
# tipLength 指箭头部分长度与整个线段长度的比例
img2 = cv.arrowedLine(img.copy(), (10, 0), (100, 30), (0, 0, 255), tipLength=0.05)  # 从 pt1 指向 pt2
img2 = cv.arrowedLine(img2, (10, 50), (100, 80), (0, 0, 255), tipLength=0.1)
img2 = cv.arrowedLine(img2, (10, 100), (100, 130OpenCVChapter9.边缘检测与图像分割

OpenCVChapter9.边缘检测与图像分割

OpenCVChapter7.图像噪声与滤波器

图像色彩空间转换

Java - 将图像转换为黑白 - 色彩鲜艳失败

python opencv:色彩空间