为了分析区别其他图像的特征、用数学方法表示和描述特征,我们要对图像进行表示和描述。
图像的特征主要是指:
1、通过测量或处理能够抽取的数据
2、某一幅或一类图像区别于其他图像的本质特点或特性集合
3、将某一类图像的多个或多种特征组合在一起,形成一个特征向量来代表该类图像
4、一个图像的特征有很多种种类,每种都有不同的计算方法
图像中的区域可用其内部(如组成区域的像素)来表示,也可用外部(如组成区域边界的像素集合)表示
表示是直接具体的表示目标,好的表示方法应具有节省次年初空间、易于特征计算等优点
描述是较抽象的表示目标,好的描述应在尽可能区别不同目标的基础上对目标的尺度、平移、旋转等不敏感。
图像的颜色可通过其灰度特征,直方图特征,颜色矩等信息进行描述。
2.1 灰度特征
图像的灰度特征可以在图像的某些特定的像素点上或其邻域内测定也可以在某个区域内测定。如:平均值、均值、方差等特征。
2.2 直方图特征:平均值、方差、能量、熵
2.3 颜色矩:颜色矩是一种简单有效的颜色特征表示方法,有一阶矩(均值,mean)、二阶矩(方差,variance)和三阶矩(斜度,skewness)等,由于颜色信息主要分布于低阶矩中,所以用一阶矩,二阶矩和三阶矩足以表达图像的颜色分布,颜色矩已证明可有效地表示图像中的颜色分布。
img = cv2.imread(filename)
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
h, s, v = cv2.split(hsv)
# 一阶矩
h_mean = np.mean(h)
s_mean = np.mean(s)
v_mean = np.mean(v)
#二阶矩
h_std = np.std(h)
s_std = np.std(s)
v_std = np.std(v)
#三阶矩
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)
很难给纹理下一个确切的定义,纹理图像的特点:
1)在局部区域可能呈现不规则性
2)但整体上表现出一定的规律性
3)其灰度分布往往表现出某种周期性
纹理图像所表现出的这种特有的性质称为纹理, 实际中很多图像具有纹理型结构,对这种纹理图像可以通过纹理分析提取其宏观特征信息。
纹理可分为人工纹理和自然纹理两种,人工纹理往往是有规则地,而自然纹理往往是无规则的。
与颜色特征不同,纹理特征不是基于像素点的特征,它需要在包含多个像素点的区域中进行统计计算。在图像模式识别的模式匹配时,此类区域性的特征具有一定的优势,可以避免由于局部的偏差造成匹配失败。
常用的纹理特征表示方法有以下几种:1)统计法 2)模型法 3)几何法 4)频谱法
自相关函数法是表示图像纹理特征的方法中极为重要的一种。
设图像为f(m,n),它的自相关函数定义为c( ε \varepsilon ε, η \eta η, j , k j,k j,k)= ∑ m = j − w j + w ∑ n = k − w k + w f ( m , n ) f ( m − ε , n − η ) ∑ m = j − w j + w ∑ n = k − w k + w [ f ( m , n ) ] 2 \frac{\sum\limits^{j+w}_{m=j-w}\sum\limits^{k+w}_{n=k-w}f(m,n)f(m-\varepsilon,n-\eta)}{\sum\limits^{j+w}_{m=j-w}\sum\limits^{k+w}_{n=k-w}[f(m,n)]^2} m=j−w∑j+wn=k−w∑k+w[f(m,n)]2m=j−w∑j+wn=k−w∑k+wf(m,n)f(m−ε,n−η)
空间自相关函数可用于度量图像纹理结构的粗糙性,图形纹理结构的粗糙性与局部结构的空间重复周期有关,周期大的纹理粗糙,周期小的纹理细致。
取图像(N×N)中任意一点 (x,y)及偏离它的另一点 (x+a,y+b),设该点对的灰度值为 (g1,g2)。令点(x,y) 在整个画面上移动,则会得到各种 (g1,g2)值,设灰度值的级数为 k,则(g1,g2) 的组合共有 k 的平方种。对于整个画面,统计出每一种 (g1,g2)值出现的次数,然后排列成一个方阵,再用(g1,g2) 出现的总次数将它们归一化为出现的概率P(g1,g2) ,这样的方阵称为灰度共生矩阵。然后求出差分图像的已归一化的灰度直方图,取较小差值。
灰度共生矩阵有以下几个特征量:
1)对比度
对比度反映了某个像素值及其领域像素值的亮度的对比情况,反映了图像的清晰度和纹理沟纹深浅的程度。纹理沟纹越深,其对比度越大,视觉效果越清晰;反之,对比度小,则沟纹浅,效果模糊。
C= ∑ i ∑ j ( i − j ) 2 p ( i , j ) {\sum\limits_{i}\sum\limits_j(i-j)^2p(i,j)} i∑j∑(i−j)2p(i,j)
2)能量
灰度共生矩阵各元素值的平方和,度量了图像纹理的稳定程度,反应了图像灰度分布均匀程度和纹理粗细度。能量值大表明当前纹理是一种规则变化较为稳定的纹理。
A= ∑ i ∑ j p ( i , j ) 2 {\sum\limits_{i}\sum\limits_jp(i,j)}^2 i∑j∑p(i,j)2
3)熵
共生矩阵的熵是图像包含信息量的随机性度量。当共生矩阵中所有值均相等或者像素值表现出最大的随机性时,熵最大;熵值表明了图像灰度分布的复杂程度,熵值越大,图像越复杂。
E= - ∑ i ∑ j p ( i , j ) l o g p ( i , j ) {\sum\limits_{i}\sum\limits_jp(i,j)}logp(i,j) i∑j∑p(i,j)logp(i,j)
4) 相关性
相关性反应了图像纹理的一致性。它度量了空间灰度共生矩阵元素在行或列方向上的相似程度,相关值大小反映了图像中局部灰度相关性。当矩阵元素值均匀相等时,相关值就大;相反,如果矩阵像元值相差很大则相关值小。
R= ∑ i = 1 k ∑ j = 1 k ( i j ) G ( i , j ) − u i u j s i s j {\sum\limits^{k}_{i=1}\sum\limits^{k}_{j=1}\frac{(ij)G(i,j)-u_iu_j}{s_is_j}} i=1∑kj=1∑ksisj(ij)G(i,j)−uiuj
u i = ∑ i = 1 k ∑ j = 1 k i G ( i , j ) , u j = ∑ i = 1 k ∑ j = 1 k j G ( i , j ) u_i=\sum\limits^{k}_{i=1}\sum\limits^{k}_{j=1}iG(i,j),u_j=\sum\limits^{k}_{i=1}\sum\limits^{k}_{j=1}jG(i,j) ui=i=1∑kj=1∑kiG(i,j),uj=i=1∑kj=1∑kjG(i,j)
s i 2 = ∑ i = 1 k ∑ j = 1 k ( i − u i 2 ) G ( i , j ) , s j 2 = ∑ i = 1 k ∑ j = 1 k ( j − u j 2 ) G ( i , j ) s_i^2=\sum\limits^{k}_{i=1}\sum\limits^{k}_{j=1}(i-u_i^2)G(i,j),s_j^2=\sum\limits^{k}_{i=1}\sum\limits^{k}_{j=1}(j-u_j^2)G(i,j) si2=i=1∑kj=1∑k(i−ui2)G(i,j),sj2=i=1∑kj=1∑k(j−uj2)G(i,j)
那么下面我们对某一图像的上述信息进行计算:
import cv2
import math
gray_level = 16
def maxGrayLevel(img):
max_gray_level=0
(height,width)=img.shape
print ("图像的高宽分别为:height,width",height,width)
for y in range(height):
for x in range(width):
if img[y][x] > max_gray_level:
max_gray_level = img[y][x]
print("max_gray_level:",max_gray_level)
return max_gray_level+1
def getGlcm(input,d_x,d_y):
srcdata=input.copy()
ret=[[0.0 for i in range(gray_level)] for j in range(gray_level)]
(height,width) = input.shape
max_gray_level=maxGrayLevel(input)
if max_gray_level > gray_level:
for j in range(height):
for i in range(width):
srcdata[j][i] = srcdata[j][i]*gray_level / max_gray_level
for j in range(height-d_y):
for i in range(width-d_x):
rows = srcdata[j][i]
cols = srcdata[j + d_y][i+d_x]
ret[rows][cols]+=1.0
for i in range(gray_level):
for j in range(gray_level):
ret[i][j]/=float(height*width)
return ret
def feature_computer(p):
Con=0.0
Eng=0.0
Asm=0.0
Idm=0.0
for i in range(gray_level):
for j in range(gray_level):
Con+=(i-j)*(i-j)*p[i][j]
Asm+=p[i][j]*p[i][j]
Idm+=p[i][j]/(1+(i-j)*(i-j))
if p[i][j]>0.0:
Eng+=p[i][j]*math.log(p[i][j])
return Asm,Con,-Eng,Idm
def test(image_name):
img = cv2.imread(image_name)
try:
img_shape=img.shape
except:
print ('imread error')
return
img=cv2.resize(img,(img_shape[1]//2,img_shape[0]//2),interpolation=cv2.INTER_CUBIC)
img_gray=cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
glcm_0=getGlcm(img_gray, 1,0)
print(glcm_0)
asm,con,eng,idm=feature_computer(glcm_0)
return [asm,con,eng,idm]
if __name__=='__main__':
result = test('d:/imdata/coins.png')
print(result)
链码是对边界点的一种表示方法,利用一系列具有特定长度和方向的相连的直线段来表示目标的边界,每个线段的长度固定,而方向数目有限,只要边界的起点用坐标表示,其余点只用方向来代表偏移量。
链码主要有4—方向链码,6—方向链码,8—方向链码三种,其中,8—方向链码使用的较多。
例如,下面这副图像,其四链码为 003332221101。
使用链码时,起点的选择是很关键的,对同一边界,如果不同的边界点作为链码起点,得到的链码是不同的。将这些方向数沿一个方向循环以使它们所构成的自然数的值最小,将这样转换后所对应的链码起点作为这个边界的归一化链码的起点。
用相邻链码的差来代替原链码。
例如上图的4链码003332221101,其差分码为:303003003031
0-1=-1(3),0-0=0,3-1=3…
用链码表示给定目标的边界时,如果目标平移,链码不会发生变化,而如果目标旋转,则链码将会发生变化。用链码的1阶差分来重新构造一个序列,相当于把链码进行旋转归一化。 目标旋转后,原链码发生变化,但差分码没有变化。
1)边界的长度
2)曲率:描述边界上各点沿边界方向变化的情况,曲率的正负描述了边界在该点的凹凸性。
形状数是基于链码的一种边界形状描述符。根据链码的起点位置不同,一个用链码表达的边界可以有多个一阶差分,形状数是最小的差分码。
1)从所有满足给定阶要求的矩形中选取其长短轴比例最接近指定边界的矩形
2)根据给定阶将选出的矩形划分为多个等边正方形
3)求出与边界最吻合的多边形
4)计算链码、差分码以及形状数
那么我们采用findContours函数找出图像的边界,然后求出它的8-方向链码,方便大家观察。
import numpy as np
import cv2
img = cv2.imread('d:\imdata\coins.png')
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
ret, binary =cv2.threshold(gray,127,255,cv2.THRESH_BINARY)
contours, hierarchy =cv2.findContours(binary,cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
temp = np.ones(binary.shape,np.uint8)*255
cv2.drawContours(temp,contours,-1,(0,255,0),3)
cv2.imshow("contours",temp)
cv2.waitKey(0)
cv2.destroyAllWindows()
columns = []
for i in range(81):
columns.append(contours[0][i]-contours[0][i - 1])
a = []
for i in range(81):
if columns[i][0][0] == 0 and columns[i][0][1] == -1:
a.append(6)
elif columns[i][0][0] == 0 and columns[i][0][1] == 1:
a.append(2)
elif columns[i][0][0] == 1 and columns[i][0][1] == 1:
a.append(1)
elif columns[i][0][0] == 1 and columns[i][0][1] == 0:
a.append(0)
elif columns[i][0][0] == 1 and columns[i][0][1] == -1:
a.append(7)
elif columns[i][0][0] == -1 and columns[i][0][1] == 1:
a.append(3)
elif columns[i][0][0] == -1 and columns[i][0][1] == 0:
a.append(4)
elif columns[i][0][0] == -1 and columns[i][0][1] == -1:
a.append(5)
print(a)
原图:
它的8-方向链码为:
[4, 3, 4, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 3, 4, 3, 3, 3, 3, 2, 3, 3, 2, 3, 2, 3, 2, 3, 2, 2, 2, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 1, 2, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0]
根据结果我们可以发现用findContours函数寻找图像的边界时是用圆,矩形等形状来近似模拟图像的边界。
1)区域面积,描述区域的大小, 对属于区域的像素计数。
2)位置和方向
位置:用物体面积的中心来表示物体的位置(面积中心就是单位面积质量恒定的相同形状图形的质心)。
方向:如果物体是细长的,则可以将较长方向的轴定义物体的方向。
3)周长
计算周长的方法比较多,一般,可用边界所占面积表示。
4)长轴和短轴
用最小外接矩形法求物体的长轴和短轴。
对一个区域而言,常用的拓扑性质有1)孔数H 2)连通成分C 3)欧拉数E,其中, E=C-H
1、形状参数
根据区域的周长B及面积A计算, F = ∣ ∣ B ∣ ∣ 2 4 π A F=\frac{||B||^2}{4\pi A} F=4πA∣∣B∣∣2区域为圆形时F为1,其他形状时,F>1。
2、偏心度
区域的偏心度是区域形状的重要描述,常用区域主轴和辅轴的比来表示,另外一种方法是计算惯性主轴比。
当一个区域R只是以其内部点的形式绘出时,可以用矩特征描述,它对大小、旋转和平移的变化都是不变。
对数字图像,如果它分段连续且只在XY平面上的有限个点不为零,则可证明它的各阶矩存在。
区域的矩是用所有属于区域内的点计算出来的,而不太受噪声等的影响。
f(x,y)的p+q阶矩定义: m p q = ∑ x ∑ y x p y q f ( x , y ) m_{pq}=\sum\limits_{x}\sum\limits_{y}x^py^qf(x,y) mpq=x∑y∑xpyqf(x,y)
f(x,y)的p+q阶中心矩定义: u p q = ∑ x ∑ y ( x − x ˉ ) p ( y − y ˉ ) q f ( x , y ) u_{pq}=\sum\limits_{x}\sum\limits_{y}(x-\bar{x})^p(y-\bar{y})^qf(x,y) upq=x∑y∑(x−xˉ)p(y−yˉ)qf(x,y)
f(x,y)归一化中心距表示: η p q = u p q u 00 r \eta_{pq}=\frac{u_{pq}}{u_{00}^{r}} ηpq=u00rupq , r = p + q 2 + 1 r=\frac{p+q}{2}+1 r=2p+q+1
中心距是反映区域R中的灰度相对于灰度重心是如何分布的度量,例如 u 20 u_{20} u20和 u 02 u_{02} u02分别表示R围绕通过灰度重心的垂直和水平轴线的惯性矩,若 u 20 u_{20} u20> u 02 u_{02} u02,那么这可能是一个水平方向拉长的物体。
本章我们学习了图像描述的一些方法,对图像的边界、颜色、纹理等特征的描述方法进行了介绍。图像描述是最图像处理重要的一部分,对我们以后图像识别的学习有很大的帮助。