使用Python+OpenCV的色彩过滤和色彩流行效果

使用Python+OpenCV的色彩过滤和色彩流行效果

你曾经想过从图像中分离单一色调吗?本文介绍了使用OpenCV python从常规RGB图像中过滤特定颜色的过程。让我们开始吧。

色调

在开始过滤颜色之前,最好对色调有一个基本的了解。这是维基百科上关于色调的定义之一。

在颜色理论中,色调是一种颜色的主要属性(称为颜色外观参数),在CIECAM02模型中技术上定义为“刺激可描述为与红色调似或不同的程度” ,橙色,黄色,绿色,蓝色,紫色”,在某些色觉理论中被称为独特的色调。

我知道这听起来很难以理解,但让我给你解释一下。“刺激”这个词在这里的意思是当我们看到一个物体时到达我们眼睛的光。

现在让我重新定义一下。我们看到的所有颜色,都可以被解释为红、橙、黄、绿、蓝、紫这些颜色的变体,在某些色彩视觉理论中,这些颜色被称为独特的色调。

总而言之,色调是原色和次色最纯粹的形式。一般来说,色调是按颜色圈的360度来衡量的,但在OpenCV中,色调尺度只有180度。

HSV(色调,饱和度,值)

就像我们用来表示RGB和BGR等图像的最常见颜色空间一样,HSV也是一个颜色空间,其中H表示色调,S表示饱和度,V表示值。因为我们已经知道什么是色调,让我们看看饱和度和值。

饱和度

饱和度使颜色变得纯净。纯色中没有灰色。颜色中混合的灰色越多,饱和度越低。饱和度值通常从0到100%测量,但在OpenCV中,饱和度的范围是从0到255。

这是一种颜色亮度的量度。当亮度值最大时,颜色变为白色,当亮度值最小时,颜色变为黑色。这通常是0到100%,但在OpenCV中,值的范围是从0到255。

现在让我们采取一些实际行动。

过滤颜色

为了使用OpenCV过滤颜色,我们必须指定颜色的色调范围,我们需要过滤,并为颜色创建一个遮罩。然后利用遮罩对原始图像阵列(本文将详细讨论)进行按位与运算,得到滤波后的颜色结果。

让我们尝试从下图中过滤出绿色:

从上图中滤除绿色的代码为:

#import the libraries
import cv2 as cv
import numpy as np
#read the image
img = cv.imread("D://medium_blogs//flower.jpg")
#convert the BGR image to HSV colour space
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
#set the lower and upper bounds for the green hue
lower_green = np.array([50,100,50])
upper_green = np.array([70,255,255])
#create a mask for green colour using inRange function
mask = cv.inRange(hsv, lower_green, upper_green)
#perform bitwise and on the original image arrays using the mask
res = cv.bitwise_and(img, img, mask=mask)
#create resizable windows for displaying the images
cv.namedWindow("res", cv.WINDOW_NORMAL)
cv.namedWindow("hsv", cv.WINDOW_NORMAL)
cv.namedWindow("mask", cv.WINDOW_NORMAL)
#display the images
cv.imshow("mask", mask)
cv.imshow("hsv", hsv)
cv.imshow("res", res)
if cv.waitKey(0):
    cv.destroyAllWindows()

上述代码片段的结果是:

HSV图像

蒙版

只有绿色的最终图像

使用色彩过滤的概念创建色彩流行效果

现在我们知道了如何创建颜色过滤器,让我们看看如何使用OpenCV创建彩色流行效果。让我们使用下面的图像来演示这一点。

创建红色弹出滤镜的流程如下:

  1. 读取图像并将其转换为HSV格式。
  2. 设置要过滤的红色HSV的下界和上界。查找颜色的HSV颜色空间值的一种方法是运行以下代码片段。
img = np.uint8([[[0,0,255]]])
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
print(hsv)

OpenCV以BGR格式读取图像,这就是为什么红色是[0,0,255]。上面的代码片段打印如下:

[[0 255 255]]

它是红色的HSV值(色调- 0,饱和度- 255(100%),值- 255(100%)。你还可以对图像中的特定像素做同样的工作,以找到该像素的HSV值。

pixel = img[3124, 2342]
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
print(hsv)

因为我们知道我们现在试图过滤的颜色的HSV值,我们可以根据我们的需要分别调整色调,饱和度和值来设置上界和下界。

  1. 使用OpenCV的inRange函数为红色色调创建一个遮罩。
  2. 使用遮罩上的bitwise_not操作创建遮罩的逆遮罩。
  3. 使用遮罩(前景)只过滤原始图像的红色部分。
  4. 使用cv.cvtColor函数获取原始图像的灰度格式。
  5. 现在使用遮罩的反面从灰度图像(背景)中只过滤原始图像中包含红色以外的颜色的区域。
  6. 在将背景添加到前景之前,必须使用numpy.stack()函数将只有一个通道的灰度背景图像转换为三个通道的灰度图像。这一步应该做,因为OpenCV的add函数只有在要添加的图像的形状相同时才能工作。
  7. 添加前景和背景以得到最终的图像,只有红色从灰度背景中突出。

创建红色弹出滤镜的代码是:

#import the libraries
import cv2 as cv
import numpy as np
#read the image
img = cv.imread("D://medium_blogs//red_coat.jpg")
#convert the BGR image to HSV colour space
hsv = cv.cvtColor(img, cv.COLOR_BGR2HSV)
#obtain the grayscale image of the original image
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
#set the bounds for the red hue
lower_red = np.array([160,100,50])
upper_red = np.array([180,255,255])
#create a mask using the bounds set
mask = cv.inRange(hsv, lower_red, upper_red)
#create an inverse of the mask
mask_inv = cv.bitwise_not(mask)
#Filter only the red colour from the original image using the mask(foreground)
res = cv.bitwise_and(img, img, mask=mask)
#Filter the regions containing colours other than red from the grayscale image(background)
background = cv.bitwise_and(gray, gray, mask = mask_inv)
#convert the one channelled grayscale background to a three channelled image
background = np.stack((background,)*3, axis=-1)
#add the foreground and the background
added_img = cv.add(res, background)
#create resizable windows for the images
cv.namedWindow("res", cv.WINDOW_NORMAL)
cv.namedWindow("hsv", cv.WINDOW_NORMAL)
cv.namedWindow("mask", cv.WINDOW_NORMAL)
cv.namedWindow("added", cv.WINDOW_NORMAL)
cv.namedWindow("back", cv.WINDOW_NORMAL)
cv.namedWindow("mask_inv", cv.WINDOW_NORMAL)
cv.namedWindow("gray", cv.WINDOW_NORMAL)
#display the images
cv.imshow("back", background)
cv.imshow("mask_inv", mask_inv)
cv.imshow("added",added_img)
cv.imshow("mask", mask)