在OpenCV + Python中使用色彩空间进行图像分割
什么是色彩空间?

在最常见的颜色空间RGB(红色绿色蓝色)中,颜色以红色,绿色和蓝色分量表示。用更专业的术语来说,RGB将颜色描述为三个组成部分的元组。每个分量可以取0到255之间的值,其中元组(0, 0, 0)代表黑色,(255, 255, 255)代表白色。

RGB被认为是三原色“加法”颜色空间,可以想象颜色是由大量红色,蓝色和绿色的光照射到黑色背景上产生的。

颜色 RGB值
红色 255,0,0
橙色 255,128,0
粉色 25,153,255

RGB是五个主要色彩空间模型之一,每个模型都有许多分支。颜色空间太多,因为不同的颜色空间可用于不同的目的。

在印刷领域,CMYK很有用,因为它描述了从白色背景产生颜色所需的颜色组合。RGB中的0元组是黑色,而CMYK中的0元组是白色。我们的打印机包含青色,品红色,黄色和黑色的墨水罐。

HSV和HSL是色相,饱和度和亮度/亮度的描述,对识别图像的对比度特别有用。这些色彩空间常用于软件的选色工具和网页设计中。

实际上,颜色是一种连续现象,意味着存在无限数量的颜色。但是,色彩空间通过离散结构(固定数量的整数整数值)表示颜色,这是可以接受的,因为人眼和感知也受到限制。颜色空间完全能够代表我们能够区分的所有颜色。

OpenCV中的色彩空间和读取图像

首先,您需要设置您的环境。本文将假定您在系统上安装了Python3.x。请注意,尽管当前的OpenCV版本是3.x,但是要导入的软件包的名称仍然是cv2:

import cv2

导入OpenCV之后,您可以查看OpenCV提供的所有色彩空间转换,并将它们全部保存到变量中:

flags = [i for i in dir(cv2) if i.startswith("COLOR_")]
# 查看OpenCV提供的所有色彩空间转换的数量
len(flags)
# 查找COLOR_RGB2HSV所在的索引
flags.index('COLOR_RGB2HSV')

您将需要matplotlib.pyplot查看图像,并需要NumPy进行一些图像处理。如果您还没有Matplotlib或NumPy的安装,您将需要pip3 install matplotlib和pip3 install numpy进行安装:

import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('nemo.jpg')
# cv中默认BGR格式,在matplotlib中需要转换为RGB进行显示图像
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
plt.imshow(img)
plt.show()
在RGB颜色空间中可视化Nemo

HSV是用于按颜色分割的颜色空间的不错选择,但是要了解为什么,让我们通过可视化其像素的颜色分布来比较RGB和HSV颜色空间中的图像。一个3D图很好地显示了这一点,每个轴代表色彩空间中的一个通道。

#%% 绘制彩色三维散点图
import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# from matplotlib import cm
from matplotlib import colors
img = cv2.imread('nemo.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
r,g,b = cv2.split(img)
fig = plt.figure(figsize=(8,6),dpi=80)
axis = fig.add_subplot(1,1,1,projection="3d")
# 像素颜色设置
pixel_colors = img.reshape((np.shape(img)[0]*np.shape(img)[1],3))
# print(pixel_colors)
# 归一化
norm = colors.Normalize(vmin=-1.,vmax=1.)
norm.autoscale(pixel_colors)
# 转换成list
pixel_colors = norm(pixel_colors).tolist()
# print('*'*20)
# print(pixel_colors)
# 显示三维散点图
axis.scatter(r.flatten(),g.flatten(),b.flatten(),facecolors=pixel_colors,marker='.')
axis.set_xlabel("Red")
axis.set_ylabel("Green")
axis.set_zlabel("Bule")
plt.show()

从该图可以看到,图像的橙色部分几乎覆盖了红色,绿色和蓝色值的整个范围。由于Nemo的各个部分在整个图上伸展,因此根据RGB值的范围在RGB空间中分割Nemo并不容易。

在HSV颜色空间中可视化Nemo

我们在RGB空间中看到了Nemo,所以现在让我们在HSV空间中查看他并进行比较。

如上所述,HSV代表色相,饱和度和值(或亮度),并且是圆柱形的色彩空间。颜色或色调建模为围绕中心垂直轴旋转的角度尺寸,该轴代表值通道。值从暗(底部为0)到顶部亮。第三个轴是饱和度,它定义了从垂直轴上的最小饱和度到离中心最远的最大饱和度的色调阴影:

#%% 在HSV中的图像生成彩色3D散点图
import cv2
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
# from matplotlib import cm
from matplotlib import colors
img = cv2.imread('nemo.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv_img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
h,s,v = cv2.split(hsv_img)
fig = plt.figure(figsize=(8,6),dpi=80)
axis = fig.add_subplot(1,1,1,projection="3d")
# 像素颜色设置
pixel_colors = img.reshape((np.shape(img)[0]*np.shape(img)[1],3))
# print(pixel_colors)
# 归一化
norm = colors.Normalize(vmin=-1.,vmax=1.)
norm.autoscale(pixel_colors)
# 转换成list
pixel_colors = norm(pixel_colors).tolist()
# print('*'*20)
# print(pixel_colors)
# 显示三维散点图
axis.scatter(h.flatten(),s.flatten(),v.flatten(),facecolors=pixel_colors,marker='.')
axis.set_xlabel("hue")
axis.set_ylabel("saturation")
axis.set_zlabel("value")
plt.show()

在HSV空间中,Nemo的橙色更加集中化并且在视觉上可分离。橙色的饱和度和值确实会有所不同,但是它们大多位于沿色相轴的较小范围内。

选择颜色范围

让我们根据一个简单的橙色阈值Nemo。您可以通过查看上面的图或在线使用颜色选择应用程序(例如RGB to HSV工具)来选择范围。此处选择的色板是浅橙色和几乎是红色的深橙色:

import matplotlib.pyplot as plt
from matplotlib.colors import hsv_to_rgb
import numpy as np
light_orange = (1,190,200)
dark_orange = (18,255,255)
lo_square = np.full((10,10,3),light_orange,dtype=np.uint8)/255.
do_square = np.full((10,10,3),dark_orange,dtype=np.uint8)/255.
plt.subplot(121)
plt.imshow(hsv_to_rgb(do_square))
plt.subplot(122)
plt.imshow(hsv_to_rgb(lo_square))
plt.show()

利用同样的方法选出白色的阈值

light_white = (0,0,200)
dark_white = (145,60,255)
利用彩色图像进行图像分割

一旦获得合适的色彩范围,您就可以cv2.inRange()尝试设定Nemo阈值。inRange()接受三个参数:图像,较低范围和较高范围。它返回ndarray图像大小的二进制mask(1和0),其中的值1表示范围内的值,0值表示范围外的值。

import cv2
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('nemo.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
hsv_img = cv2.cvtColor(img, cv2.COLOR_RGB2HSV)
light_orange = (1,190,200)
dark_orange = (18,255,255)
light_white = (0,0,200)
dark_white = (145,60,255)
orange_mask = cv2.inRange(hsv_img,light_orange,dark_orange)
white_mask = cv2.inRange(hsv_img,light_white,dark_white)
mask = orange_mask+white_mask
result = cv2.bitwise_and(img, img,mask=mask)
plt.subplot(121)
plt.imshow(mask,cmap="gray")
plt.subplot(122)
plt.imshow(result)
plt.show()

在本教程中,您已经了解了几种不同的色彩空间,如何在RGB和HSV色彩空间中分布图像,以及如何使用OpenCV在色彩空间之间进行转换并划分出范围。

总体而言,您已经了解了如何使用OpenCV中的色彩空间在图像中执行对象分割,并希望看到它也可以执行其他任务。这种分割技术简单,快速且可靠。

在OpenCV + Python中使用色彩空间进行图像分割什么是色彩空间?在最常见的颜色空间RGB(红色绿色蓝色)中,颜色以红色,绿色和蓝色分量表示。用更专业的术语来说,RGB将颜色描述为三个组成部分的元组。每个分量可以取0到255之间的值,其中元组(0, 0, 0)代表黑色,(255, 255, 255)代表白色。RGB被认为是三原色“加法”颜色空间,可以想象颜色是由大量红色,蓝色和绿色的...
全局阈值分割是一种简单而有效的图像分割方法,通过将图像的像素值与一个预先设定的阈值进行比较,将像素分为两个类别:背景和前景。在 OpenCV ,可以使用 cv2.threshold() 函数来进行全局阈值分割。 下面是一个基于 OpenCV + Python 的全局阈值分割的实现示例: ```python import cv2 # 读取图像 img = cv2.imread('test.jpg', 0) # 进行全局阈值分割 ret, thresh = cv2.threshold(img, 127, 255, cv2.THRESH_BINARY) # 显示原始图像和分割结果 cv2.imshow('original', img) cv2.imshow('threshold', thresh) cv2.waitKey(0) cv2.destroyAllWindows() 在这个例子,我们使用 cv2.imread() 函数读取名为 test.jpg 的图像,然后使用 cv2.threshold() 函数进行全局阈值分割。该函数的第一个参数是输入图像,第二个参数是阈值,第三个参数是将像素分为两个类别的最大像素值,第四个参数是阈值类型。在这个例子,我们使用 THRESH_BINARY 类型,表示将像素值大于阈值的像素设置为最大值,将像素值小于等于阈值的像素设置为 0。最后,使用 cv2.imshow() 函数显示原始图像和分割结果,并使用 cv2.waitKey() 函数等待用户按下任意键关闭窗口。 需要注意的是,阈值的选择需要根据具体的应用场景和图像特点进行调整,通常可以通过试验法来选择最佳的阈值。
winner069: 请问Warning 1: The definition of projected CRS EPSG:32650 got from GeoTIFF keys is not the same as the one from the EPSG registry, which may cause issues during reprojection operations. Set GTIFF_SRS_SOURCE configuration option to EPSG to use official parameters (overriding the ones from GeoTIFF keys), or to GEOKEYS to use custom values from GeoTIFF keys and drop the EPSG code. 这个提示不用处理也没关系吗 手动实现直方图匹配(python) chyikitty: 五通道的能直接用吗 土地覆盖/利用数据产品下载 陨星落云: 用qgis转