图像颜色特征提取

图像颜色特征提取(颜色直方图,颜色矩)–python

颜色直方图

颜色直方图用以反映图像颜色的组成分布,即各种颜色出现的概率。Swain和Ballard最先提出了应用颜色直方图进行图像特征提取的方法,首先利用颜色空间三个分量的剥离得到颜色直方图,之后通过观察实验数据发现将图像进行旋转变换、缩放变换、模糊变换后图像的颜色直方图改变不大,即图像直方图对图像的物理变换是不敏感的。因此常提取颜色特征并用颜色直方图应用于衡量和比较两幅图像的全局差。另外,如果图像可以分为多个区域,并且前景与背景颜色分布具有明显差异,则颜色直方图呈现双峰形。

颜色直方图也有其缺点:由于颜色直方图是全局颜色统计的结果,因此丢失了像素点间的位置特征。可能有几幅图像具有相同或相近的颜色直方图,但其图像像素位置分布完全不同。因此,图像与颜色直方图得多对一关系使得颜色直方图在识别前景物体上不能获得很好的效果。

考虑到颜色直方图的以上问题,主色调直方图便产生了。所谓主色调直方图基于假设少数几个像素的值能够表示图像中的绝大部分像素,即出现频率最高的几个像素被选为主色,仅用主色构成的主色调直方图描述一幅图像。这样的描述子并不会降低通过颜色特征进行匹配的效果,因为从某种角度将,频度出现很小的像素点可以被视为噪声。

颜色矩

颜色矩是一种有效的颜色特征,由Stricker和Orengo提出,该方法利用线性代数中矩的概念,将图像中的颜色分布用其矩表示。利用颜色一阶矩(平均值Average)、颜色二阶矩(方差Variance)和颜色三阶矩(偏斜度Skewness)来描述颜色分布。与颜色直方图不同,利用颜色矩进行图像描述无需量化图像特征。由于每个像素具有颜色空间的三个颜色通道,因此图像的颜色矩有9个分量来描述。

颜色直方图代码实现

颜色直方图一般用于统计图片不同通道像素强度的分布,并可以基于此来实现对比度提升、以及简单的目标识别、跟踪以及分割等任务。在openCV中集成了函数cv2.calcHist()来实现直方图的计算。
函数定义如下:

1
2
3
4
5
6
7
8
9
10
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) → hist
其中images 可为单张或多张图像的array
channels 为要计算的通道数
mask 为图像掩膜
histSize 为直方图的柱子数量,即将数据分布在多少个区间上计数
range 为直方图取值范围
hist为返回值,不用填
accumulate 多张图的时候是否叠加
所以一般调用的时候只需要填上面四个参数,掩膜为None,范围0.0-255.0,数量255个:
hist = cv2.calcHist(img, [0], None,[256], [0.0,255.0])
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# import the necessary packages
import numpy as np
import cv2

class ColorDescriptor:
def __init__(self, bins):
# 存储 3D 直方图的数量
self.bins = bins

def describe(self, image):
# 将图像转换为 HSV 色彩空间并初始化
# 用于量化图像的特征
image = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
features = []
# 获取尺寸并计算图像的中心
(h, w) = image.shape[:2]
(cX, cY) = (int(w * 0.5), int(h * 0.5))
# 将图像分成四份 rectangles/segments (top-left,top-right, bottom-right, bottom-left)
segments = [(0, cX, 0, cY), (cX, w, 0, cY), (cX, w, cY, h), (0, cX, cY, h)]
# 构建代表图像中心的椭圆蒙版
(axesX, axesY) = (int(w * 0.75) // 2, int(h * 0.75) // 2)
ellipMask = np.zeros(image.shape[:2], dtype="uint8")
cv2.ellipse(ellipMask, (cX, cY), (axesX, axesY), 0, 0, 360, 255, -1)
# loop over the segments
for (startX, endX, startY, endY) in segments:
# 为图像的每个角构建一个掩码,从中减去椭圆中心
cornerMask = np.zeros(image.shape[:2], dtype="uint8")
cv2.rectangle(cornerMask, (startX, startY), (endX, endY), 255, -1)
cv2.ellipse(ellipMask, (cX, cY), (axesX, axesY), 0, 0, 360, 255, -1)
# 从图像中提取颜色直方图,然后更新特征向量
hist = self.histogram(image, cornerMask)
features.extend(hist)
# 从椭圆区域提取颜色直方图并更新特征向量
hist = self.histogram(image, ellipMask)
features.extend(hist)
# 返回特征向量
return features

def histogram(self, image, mask):
# 使用提供的每个通道的 bin 数量,从图像的遮罩区域中提取 3D 颜色直方图
hist = cv2.calcHist([image], [0, 1, 2], mask, self.bins, [0, 180, 0, 256, 0, 256])
hist = cv2.normalize(hist, hist).flatten()
# 返回直方图
return hist

颜色矩代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# import the necessary packages
import numpy as np
import cv2

def color_moments(filename):
img = cv2.imread(filename)
if img is None:
return
# Convert BGR to HSV colorspace
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
# Split the channels - h,s,v
h, s, v = cv2.split(hsv)
# Initialize the color feature
color_feature = []
# N = h.shape[0] * h.shape[1]
# The first central moment - average
h_mean = np.mean(h) # np.sum(h)/float(N)
s_mean = np.mean(s) # np.sum(s)/float(N)
v_mean = np.mean(v) # np.sum(v)/float(N)
color_feature.extend([h_mean, s_mean, v_mean])
# The second central moment - standard deviation
h_std = np.std(h) # np.sqrt(np.mean(abs(h - h.mean())**2))
s_std = np.std(s) # np.sqrt(np.mean(abs(s - s.mean())**2))
v_std = np.std(v) # np.sqrt(np.mean(abs(v - v.mean())**2))
color_feature.extend([h_std, s_std, v_std])
# The third central moment - the third root of the skewness
h_skewness = np.mean(abs(h - h.mean())**3)
s_skewness = np.mean(abs(s - s.mean())**3)
v_skewness = np.mean(abs(v - v.mean())**3)
h_thirdMoment = h_skewness**(1./3)
s_thirdMoment = s_skewness**(1./3)
v_thirdMoment = v_skewness**(1./3)
color_feature.extend([h_thirdMoment, s_thirdMoment, v_thirdMoment])
return color_feature

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!