图像分割就是把图像分成若干个特定的、具有独特性质的区域并提出感兴趣目标的技术和过程。它是由图像处理到图像分析的关键步骤。现有的图像分割方法主要分以下几类:基于阈值的分割方法、基于区域的分割方法、基于边缘的分割方法以及基于特定理论的分割方法等。从数学角度来看,图像分割是将数字图像划分成互不相交的区域的过程。图像分割的过程也是一个标记过程,即把属于同一区域的像素赋予相同的编号。
HSI颜色空间中的分割
HSI颜色空间是面向颜色处理的,用色调(H),饱和度(S)描述色彩,用亮度(I)描述光的强度。
HSI模型的建立基于两个重要的事实: ① I分量与图像的彩色信息无关;② H和S分量与人感受颜色的方式是紧密相联的。这些特点使得HSI模型非常适合彩色特性检测与分析。
假定感兴趣区域是原始RGB图像中的红色。观察H分量可以发现感兴趣区域具有较高的色调值。观察S分量图像可以发现感兴趣区域色彩饱和度较高。饱和度图像中选择门限等于最大饱和度30%,对于任何比门限大的像素赋值1(白),其他为0(黑)。可产生分割图像效果。
from skimage import data,io
from matplotlib import pyplot as plt
import math
import numpy as np
import sys
# 定义RGB图像转换为HSI图像函数
def rgb2hsi(r, g, b):
r = r / 255
g = g / 255
b = b / 255
num = 0.5 * ((r - g) + (r - b))
den = ((r - g) * (r - g) + (r - b) * (g - b)) ** 0.5
if b <= g:
if den == 0:
den = sys.float_info.min
h = math.acos(num / den)
elif b > g:
if den == 0:
den = sys.float_info.min
h = (2 * math.pi) - math.acos(num / den)
s = 1 - (3 * min(r, g, b) / (r + g + b))
i = (r + g + b) / 3
return int(h), int(s * 100), int(i * 255)
img=io.imread("F.jpg")
hsi = np.zeros(img.shape, dtype='uint8')
for ii in range(img.shape[0]):
for jj in range(img.shape[1]):
r, g, b = img[ii, jj, :]
h, s, i = rgb2hsi(r, g, b)
hsi[ii, jj:] = (h, s, i)
H = hsi[:, :, 0]
S = hsi[:, :, 1]
I = hsi[:, :, 2]
# 生成二值饱和度模板
S_template = np.zeros(S.shape, dtype='uint8')
for i in range(S.shape[0]):
for j in range(S.shape[1]):
if S[i, j] > 0.3 * S.max():
S_template[i, j] = 1
# 色调图像与二值饱和度模板相乘可得分割结果F
F = np.zeros(H.shape, dtype='uint8')
for i in range(F.shape[0]):
for j in range(F.shape[1]):
F[i, j] = H[i, j] * S_template[i, j]
# 显示结果
plt.figure()
plt.axis('off')
plt.imshow(img)
# 显示H S I分量
plt.figure()
plt.axis('off')
plt.imshow(H, cmap='gray')
plt.figure()
plt.axis('off')
plt.imshow(S, cmap='gray')
plt.figure()
plt.axis('off')
plt.imshow(I, cmap='gray')
plt.figure()
plt.axis('off')
plt.imshow(S_template, cmap='gray') # 二值饱和度模板
plt.figure()
plt.axis('off')
plt.imshow(F, cmap='gray') # 分割结果
plt.show()
RGB图像:
H分量:
S分量:
I分量:
二值饱和度模板:
分割结果:
RGB颜色空间中的分割
RGB是常用的描述彩色图像的颜色空间。RGB是颜色空间中分割算法是最直接的,得到的分割效果通常较好。假定感兴趣区域是红色伞,则可以选取一些可以代表红色伞的像素点组成样本集合,通过样本集对待分割的颜色的“平均”进行估计。用向量a表示平均颜色,向量z表示RGB空间任意像素颜色特征。若z与a的欧式距离小于给定阈值,则认为z与a相似。欧式距离需要开方,为了简化计算,使用边界盒,盒子中心在a处,盒子在RGB这三个维度长度和样本集在每个维度标准差成正比。z在盒子内,颜色特征为z在感兴趣区域,否则在不感兴趣区域。
from skimage import io
from matplotlib import pyplot as plt
import math
import numpy as np
img = io.imread("F.jpg")
r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]
# RGB颜色空间分割
# 选择样本区域
r1 = r[128:255, 85:169]
# 计算该区域彩色点平均向量a的红色分量
r1_u = np.mean(r1)
# 计算样本红色分量标准差
r1_d = 0.0
for i in range(r1.shape[0]):
for j in range(r1.shape[1]):
r1_d = r1_d + (r1[i, j] - r1_u) * (r1[i, j] - r1_u)
r1_d = math.sqrt(r1_d / r1.shape[0] / r1.shape[1])
# 寻找符合条件的点 r2为红色分割图像
r2 = np.zeros(r.shape, dtype='uint8')
for i in range(r.shape[0]):
for j in range(r.shape[1]):
if r[i, j] >= (r1_u - 1.25 * r1_d) and r[i, j] <= (r1_u + 1.25 * r1_d):
r2[i, j] = 1
# img2根据红色分割后图像
img2 = np.zeros(img.shape, dtype='uint8')
for i in range(r.shape[0]):
for j in range(r.shape[1]):
if r2[i, j] == 1:
img2[i, j, :] = img[i, j, :]
plt.subplot(121)
plt.title("RGB")
plt.imshow(img)
plt.subplot(122)
plt.title("R")
plt.imshow(r, cmap='gray')
plt.show()
plt.subplot(121)
plt.title("G")
plt.imshow(g, cmap='gray')
plt.subplot(122)
plt.title("B")
plt.imshow(b, cmap='gray')
plt.show()
plt.subplot(121)
plt.title("RED")
plt.imshow(r2, cmap='gray')
plt.subplot(122)
plt.title('split RGB')
plt.imshow(img2)
plt.show()
RGB与R分量:
G与B分量:
红色分割图像与分割后RGB图像:
观察可以发现R分量红色区域亮度值较高,并且在R分量中红伞区域与背景比较明显,因此选取R分量作为分析对象。选取红伞一小块区域作为样本集,计算该区域的平均向量a的红色分量。当z的红色分量和平均向量的红色分量差值在一定范围内,判定z的像素点为感兴趣像素点,否则就是不感兴趣像素点。将感兴趣像素点保持原始亮度值,不感兴趣像素点亮度设为0(黑色),显示红色伞,弱化背景。
使用skimage库函数
skimage是一个Python图像处理库,它提供了许多用于图像分析和处理的工具。你可以使用skimage来进行颜色分割,这意味着将图像中的不同颜色分开,以便进一步处理。
为了进行颜色分割,你可以使用skimage中的color module。这个module提供了许多函数,可以用于转换颜色空间,提取颜色特征,进行颜色校正等。
from skimage import io, color
from skimage.filters import threshold_otsu
from matplotlib import pyplot as plt
# 读取RGB图像
image = io.imread('demo.jpg')
# 将图像转换为灰度图像
gray_image = color.rgb2gray(image)
# 对灰度图像进行二值化处理
threshold = threshold_otsu(gray_image)
binary_image = gray_image > threshold
# 将二值图像保存到文件
io.imsave('binary_image.jpg', binary_image)
# 读取RGB图像
img = io.imread('demo.jpg')
img1=io.imread("binary_image.jpg")
plt.subplot(121)
plt.title("RGB")
plt.imshow(img)
plt.subplot(122)
plt.title("Binary")
plt.imshow(img1,cmap='gray')
plt.show()
其中,你可以使用rgb2gray函数将RGB图像转换为灰度图像,然后使用threshold_otsu函数对灰度图像进行二值化处理,从而进行颜色分割。