灰度共生矩陣(附python代碼)

理論內容引自https://blog.csdn.net/qq_37059483/article/details/78292869


最近在研究機器學習相關內容,後面會盡量花時間整理成一個系列的博客,然後朋友讓我幫他實現一種基於SVR支持向量迴歸的圖像質量評價方法,然而在文章的開頭竟然發現
灰度共生矩陣這個陌生的傢伙,於是便有此文。

主要參考博客1:http://blog.csdn.net/jialeheyeshu/article/details/51337225
主要參考博客2:http://blog.csdn.net/guanyuqiu/article/details/53117507
主要參考博客3:http://www.cnblogs.com/rong86/p/3695621.html
主要參考博客4:http://blog.csdn.net/lingtianyulong/article/details/53032034

1.灰度共生矩陣生成原理
  灰度共生矩陣(GLDM)的統計方法是20世紀70年代初由R.Haralick等人提出的,它是在假定圖像中各像素間的空間分佈關係包含了圖像紋理信息的前提下,提出的具有廣泛性的紋理分析方法。

   灰度共生矩陣被定義爲從灰度爲i的像素點出發,離開某個固定位置(相隔距離爲d,方位爲)的點上灰度值爲的概率,即,所有估計的值可以表示成一個矩陣的形式,以此被稱爲灰度共生矩陣。對於紋理變化緩慢的圖像,其灰度共生矩陣對角線上的數值較大;而對於紋理變化較快的圖像,其灰度共生矩陣對角線上的數值較小,對角線兩側的值較大。由於灰度共生矩陣的數據量較大,一般不直接作爲區分紋理的特徵,而是基於它構建的一些統計量作爲紋理分類特徵。Haralick曾提出了14種基於灰度共生矩陣計算出來的統計量:即:能量、熵、對比度、均勻性、相關性、方差、和平均、和方差、和熵、差方差、差平均、差熵、相關信息測度以及最大相關係數。

  在網上看了很多灰度共生矩陣生成的例子感覺都沒有說明白,要不就直接上結果要不就給一堆看不懂的代碼和公式,後來看了matlab中的介紹就明白了,其實很簡單,仔細把下面的看三遍就理解怎麼來的了!(我是第三篇看明白的,當時很緊張,相信你們沒問題)
  下圖顯示瞭如何求解灰度共生矩陣,以(1,1)點爲例,GLCM(1,1)值爲1說明只有一對灰度爲1的像素水平相鄰。GLCM(1,2)值爲2,是因爲有兩對灰度爲1和2的像素水平相鄰。(MatLab說明文檔)
這裏寫圖片描述

GLCM表其實就是所有像素可能的組合,比如,GLCM(1,1)就是I中像素值爲1和1的組合,GLCM(4,5)就是I中像素4和像素5的組合,GLCM(i,j)的值呢就是I中像素爲i,像素爲j的有有多少和相鄰的成對點。這個相鄰有個規則:就是f(x,y),f(x+a,y+b)相鄰,就是隻有x相隔a的單位,y相隔b個單位,我們認爲是相鄰的。
平時我們說相鄰:B點在A點右邊,其實就是這裏的a=1,b=0,也就是f(x,y)和f(x+1,y+0)相鄰。
於是就有了:
a=1,b=0 時我們就說水平相鄰:也就是0度的時候
a=1,b=1 時我們就說對角相鄰,也就是45度的時候
a=-1,b=1時 即135度
其他角度類似。
在a=1,b=0時:GLCM(1,1)=1;其實就是I中有幾個1和1相鄰(1個)(按上面的規則)GLCM(1,2)=2,幾個1和2相鄰(2個)。ok!
後面好多的性質,都是在把這個矩陣計算出來之後再在這個基礎上運算的,那些就不難了!

附加理解2:
共生矩陣用兩個位置的像素的聯合概率密度來定義,它不僅反映亮度的分佈特徵,也反映具有同樣亮度或者接近亮度的像素之間的位置分佈特性,是有關圖像亮度變化的二階統計特徵。它是定義一組紋理特徵的基礎。

由於紋理是由灰度在空間位置上反覆出現而形成的,因而在圖像空間中像個某距離的兩像素之間會存在一定的灰度關係,即圖像中灰度的空間相關特性。灰度共生矩陣就是一種通過研究灰度的空間相關特性來描述紋理的常用方法。

灰度直方圖是對圖像上單個像素具有某個灰度進行統計的結果,

而灰度共生矩陣是對圖像上保持某距離的兩像素分別具有某灰度的狀況進行統計得到的。

取圖像(N×N)中任意一點 (x,y)及偏離它的另一點 (x+a,y+b),設該點對的灰度值爲(g1,g2)。令點(x,y) 在整個畫面上移動,則會得到各種 (g1,g2)值,設灰度值的級數爲 k,則(g1,g2) 的組合共有 k^2;種。對於整個畫面,統計出每一種(g1,g2)值出現的次數,然後排列成一個方陣,在用(g1,g2) 出現的總次數將它們歸一化爲出現的概率P(g1,g2),這樣的方陣稱爲灰度共生矩陣。距離差分值(a,b) 取不同的數值組合,可以得到不同情況下的聯合概率矩陣。(a,b)取值要根據紋理週期分佈的特性來選擇,對於較細的紋理,選取(1,0)、(1,1)、(2,0)等小的差分值。  當 a=1,b=0時,像素對是水平的,即0度掃描;當a=0,b=1 時,像素對是垂直的,即90度掃描;當 a=1,b=1時,像素對是右對角線的,即45度掃描;當 a=-1,b=-1時,像素對是左對角線,即135度掃描。
這樣,兩個象素灰度級同時發生的概率,就將 (x,y)的空間座標轉化爲“灰度對” (g1,g2)的描述,形成了灰度共生矩陣。(百度百科)
一幅圖象的灰度共生矩陣能反映出圖象灰度關於方向、相鄰間隔、變化幅度的綜合信息,它是分析圖象的局部模式和它們排列規則的基礎。

感覺差不多了吧!

2.灰度共生矩陣特徵量(字寫的不好,請見諒)

2.1對比度

度量 矩陣的值是如何分佈和圖像中局部變化的多少,反應了圖像的清晰度和紋理的溝紋深淺。紋理的溝紋越深,反差越大,效果越清晰;反之,對比值小,則溝紋淺,效果模糊。
在這裏插入圖片描述

2.2 能量

能量變換反映了圖像灰度分佈均勻程度和紋理粗細度。若灰度共生矩陣的元素值相近,則能量較小,表示紋理細緻;若其中一些值大,而其它值小,則能量值較大。能量值大表明一種較均一和規則變化的紋理模式。

在這裏插入圖片描述

2.3 熵

圖像包含信息量的隨機性度量。當共生矩陣中所有值均相等或者像素值表現出最大的隨機性時,熵最大;因此熵值表明了圖像灰度分佈的複雜程度,熵值越大,圖像越複雜。

在這裏插入圖片描述

2.4 逆方差

逆方差反映了圖像紋理局部變化的大小,若圖像紋理的不同區域間較均勻,變化緩慢,逆方差會較大,反之較小。

在這裏插入圖片描述

2.5相關性

用來度量圖像的灰度級在行或列方向上的相似程度,因此值得大小反應了局部灰度相關性,值越大,相關性也越大。

在這裏插入圖片描述
3、代碼

#!/usr/bin/python
# -*- coding: UTF-8 -*-
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)
    #若灰度級數大於gray_level,則將圖像的灰度級縮小至gray_level,減小灰度共生矩陣的大小
    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:對比度反應了圖像的清晰度和紋理的溝紋深淺。紋理越清晰反差越大對比度也就越大。
    #eng:熵(Entropy, ENT)度量了圖像包含信息量的隨機性,表現了圖像的複雜程度。當共生矩陣中所有值均相等或者像素值表現出最大的隨機性時,熵最大。
    #agm:角二階矩(能量),圖像灰度分佈均勻程度和紋理粗細的度量。當圖像紋理均一規則時,能量值較大;反之灰度共生矩陣的元素值相近,能量值較小。
    #idm:反差分矩陣又稱逆方差,反映了紋理的清晰程度和規則程度,紋理清晰、規律性較強、易於描述的,值較大。
    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

    #這裏如果用‘/’會報錯TypeError: integer argument expected, got float
    #其實主要的錯誤是因爲 因爲cv2.resize內的參數是要求爲整數
    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)
    #glcm_1=getGlcm(src_gray, 0,1)
    #glcm_2=getGlcm(src_gray, 1,1)
    #glcm_3=getGlcm(src_gray, -1,1)
    print(glcm_0)

    asm,con,eng,idm=feature_computer(glcm_0)

    return [asm,con,eng,idm]

if __name__=='__main__':
    result = test("/home/images/2019-05-27/8/20190527_17_29_03_X1_Y2.jpg")
    print(result)


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章