1. 程式人生 > >深入學習影象處理——影象相似度演算法

深入學習影象處理——影象相似度演算法

  最近一段時間學習並做的都是對影象進行處理,其實自己也是新手,各種嘗試,所以我這個門外漢想總結一下自己學習的東西,影象處理的流程。但是動起筆來想總結,一下卻不知道自己要寫什麼,那就把自己做過的相似圖片搜尋的流程整理一下,想到什麼說什麼吧。

  首先在進行圖片灰度化處理之前,我覺得有必要了解一下為什麼要進行灰度化處理。

影象灰度化的目的是什麼?

  將彩色影象轉化為灰度影象的過程是影象的灰度化處理。彩色影象中的每個畫素的顏色由R,G,B三個分量決定,而每個分量有255中值可取,這樣一個畫素點可以有1600多萬(255*255*255)的顏色的變化範圍。而灰度影象是R,G,B三個分量相同的一種特殊的彩色影象,其中一個畫素點的變化範圍為255種,所以在數字影象處理中一般將各種格式的影象轉化為灰度影象以使後續的影象的計算量少一些。灰度影象的描述與彩色影象一樣仍然反映了整副影象的整體和區域性的色度和高亮等級的分佈和特徵。

一:影象灰度化處理

  灰度化處理就是將一幅色彩影象轉化為灰度影象的過程。彩色影象分為R,G,B三個分量,分別顯示出紅綠藍等各種顏色,灰度化就是使彩色的R,G,B分量相等的過程。灰度值大的畫素點比較亮(畫素值最大為255,為白色),反之比較暗(畫素最下為0,為黑色)。

1.1   影象灰度化的演算法:

  1)最大值法:使轉化後的R,G,B得值等於轉化前3個值中最大的一個,即:R=G=B=max(R,G,B)。這種方法轉換的灰度圖亮度很高。
  2)平均值法:是轉化後R,G,B的值為轉化前R,G,B的平均值。即:R=G=B=(R+G+B)/3。這種方法產生的灰度影象比較柔和。
  3)加權平均值法

:按照一定權值,對R,G,B的值加權平均,即:這裡寫圖片描述分別為R,G,B的權值,取不同的值形成不同的灰度影象。由於人眼對綠色最為敏感,紅色次之,對藍色的敏感性最低,因此使將得到較易識別的灰度影象。一般時,得到的灰度影象效果最好。

1.2   程式碼實現(灰度化+二值化)

from PIL import Image

#  load a color image
im = Image.open('durant.jpg' )

#  convert to grey level image
Lim = im.convert('L' )
Lim.save('grey.jpg' )

#  setup a converting table with constant threshold
threshold = 185
table = []
for i in range(256):
    if i < threshold:
        table.append(0)
    else:
        table.append(1)

# convert to binary image by the table
bim = Lim.point(table, '1' )

bim.save('durant_grey.jpg' )

原圖圖片效果展示:

 

灰度化圖片效果展示:

二值化圖片效果展示:

 1.3 convert() 方法詳解

  Convert()會根據傳入引數的不同將影象變成不同的模式。PIL中有九種不同模式。分別為1,L,P,RGB,RGBA,CMYK,YCbCr,I,F。

    模式‘1’為二值影象,非黑即白。但是它每個畫素用8個bit表示,
0表示黑,255表示白。

    模式‘L’為灰色影象它的每個畫素用8個bit表示,0表示黑,
255表示白,其他數字表示不同的灰度。在PIL中,從模式“RGB”轉
換為“L”模式是按照下面的公式轉換的:
    L = R * 299/1000 + G * 587/1000+ B * 114/1000

    模式“P”為8位彩色影象,它的每個畫素用8個bit表示,其對應的
彩色值是按照調色盤查詢出來的。

    模式“RGBA”為32位彩色影象,它的每個畫素用32個bit表示,其
中24bit表示紅色、綠色和藍色三個通道,另外8bit表示alpha通道,
即透明通道。

    模式“CMYK”為32位彩色影象,它的每個畫素用32個bit表示。模
式“CMYK”就是印刷四分色模式,它是彩色印刷時採用的一種套色模
式,利用色料的三原色混色原理,加上黑色油墨,共計四種顏色混合
疊加,形成所謂“全綵印刷”。

    模式“YCbCr”為24位彩色影象,它的每個畫素用24個bit表示。
YCbCr其中Y是指亮度分量,Cb指藍色色度分量,而Cr指紅色色度分
量。人的肉眼對視訊的Y分量更敏感,因此在通過對色度分量進行子
取樣來減少色度分量後,肉眼將察覺不到的影象質量的變化。

    模式“RGB”轉換為“YCbCr”的公式如下:
        Y= 0.257R+0.504G+0.098B+16
        Cb = -0.148R-0.291G+0.439B+128
        Cr = 0.439R-0.368G-0.071*B+128

    模式“I”為32位整型灰色影象,它的每個畫素用32個bit表示,0表示黑,
255表示白,(0,255)之間的數字表示不同的灰度。在PIL中,從模式“RGB”
轉換為“I”模式是按照下面的公式轉換的:
    I = R * 299/1000 + G * 587/1000 + B * 114/1000

    模式“F”為32位浮點灰色影象,它的每個畫素用32個bit表示,0表示黑,
255表示白,(0,255)之間的數字表示不同的灰度。在PIL中,從模式“RGB”轉
換為“F”模式是按照下面的公式轉換的:
    F = R * 299/1000+ G * 587/1000 + B * 114/1000    

 

二:Python影象增強

2.1 圖片增強三大類別:點增強,空間增強,頻域增強

  影象增強是影象模式識別中非常重要的影象預處理過程。影象增強的目的是通過對影象中的資訊進行處理,使得有利於模式識別的資訊得到增強,不利於模式識別的資訊被抑制,擴大影象中不同物體特徵之間的差別,為影象的資訊提取及其識別奠定良好的基礎。影象增強按實現方法不同可分為點增強、空域增強和頻域增強。

點增強

  點增強主要指影象灰度變換和幾何變換。影象的灰度變換也稱為點運算、對比度增強或對比度拉伸,它是影象數字化軟體和影象顯示軟體的重要組成部分。

  灰度變換是一種既簡單又重要的技術,它能讓使用者改變影象資料佔據的灰度範圍。一幅輸入影象經過灰度變換後將產生一幅新的輸出影象,由輸入畫素點的灰度值決定相應的輸出畫素點的灰度值。灰度變換不會改變影象內的空間關係

  影象的幾何變換是影象處理中的另一種基本變換。它通常包括影象的平移、影象的映象變換、影象的縮放和影象的旋轉。通過影象的幾何變換可以實現影象的最基本的座標變換及縮放功能。

空域增強

  影象的空間資訊可以反映影象中物體的位置 、形狀、大小等特徵,而這些特徵可以通過一定的物理模式來描述。例如,物體的邊緣輪廓由於灰度值變化劇烈一般出現高頻率特徵,而一個比較平滑的物體內部由於灰度值比較均一則呈現低頻率特徵。因此,根據需要可以分別增強影象的高頻和低頻特徵。對影象的高頻增強可以突出物體的邊緣輪廓,從而起到銳化影象的作用。例如,對於人臉的比對查詢,就需要通過高頻增強技術來突出五宮的輪廓。相應地,對影象的低頻部分進行增強可以對影象進行平滑處理,一般用於影象的噪聲消除。

頻域增強

  影象的空域增強一般只是對數字影象進行區域性增強,而影象的頻域增強可以對影象進行全域性增強。頻域增強技術是在數字影象的頻率域空間對影象進行濾波,因此需要將影象從空間域變換到頻率域,一般通過傅立葉變換實現。在頻率域空間的濾波與空域濾波一樣可以通過卷積實現,因此傅立葉變換和和卷積理論是頻域濾波技術的基礎。

2.2  python影象增強的目的是什麼?

  影象增強的主要目的有:改變影象的灰度等級,提高影象對比度,消除邊緣和噪聲,平滑影象;突出邊緣或者線性地物,銳化影象;合成彩色影象;壓縮影象資料量,突出主要資訊等。

  影象增強的主要內容有:空間域增強、頻率域增強、彩色增強、多影象代數運算、多光譜影象增強等。

  在影象分類任務中,影象資料增強一般是大多數人會採用的方法之一,這是由於深度學習對資料集的大小有一定的要求,若原始的資料集比較小,無法很好地滿足網路模型的訓練,從而影響模型的效能,而影象增強是對原始影象進行一定的處理以擴充資料集,能夠在一定程度上提升模型的效能。

 

2.3  亮度,色度,對比度,銳度增強

from PIL import Image
from PIL import ImageEnhance
# 原始影象
image = Image.open('deal_with/A1.jpg')
image.show()

#亮度增強
enh_bri = ImageEnhance.Brightness(image)
brightness = 1.5
image_brightened = enh_bri.enhance(brightness)
image_brightened.show()
image_brightened.save("image_brightened.jpg")

#色度增強
enh_col = ImageEnhance.Color(image)
color = 1.5
image_colored = enh_col.enhance(color)
image_colored.show()
image_colored.save("image_colored.jpg")

#對比度增強
enh_con = ImageEnhance.Contrast(image)
contrast = 1.5
image_contrasted = enh_con.enhance(contrast)
image_contrasted.show()
image_contrasted.save("image_contrasted.jpg")

#銳度增強
enh_sha = ImageEnhance.Sharpness(image)
sharpness = 3.0
image_sharped = enh_sha.enhance(sharpness)
image_sharped.show()
image_sharped.save("image_sharped.jpg")

 原圖:

 

亮度增強:

 

色度增強:

 

對比度增強:

 

銳度增強:

 2.4  對影象進行翻轉Flipping

  對影象進行翻轉是最流行的影象資料增強方法之一,這主要是由於翻轉影象操作的程式碼簡單,以及對於大多數問題而言,對影象進行翻轉操作能夠提升模型的效能。下面的模型可以看到人是朝右而不是朝左邊。

 三:圖片相似度演算法(對畫素求方差並比對)的學習

3.1 演算法邏輯

3.1.1  縮放圖片

  將需要處理的圖片所放到指定尺寸,縮放後圖片大小由圖片的資訊量和複雜度決定。譬如,一些簡單的圖示之類影象包含的資訊量少,複雜度低,可以縮放小一點。風景等複雜場景資訊量大,複雜度高就不能縮放太小,容易丟失重要資訊。根據自己需求,彈性的縮放。在效率和準確度之間維持平衡。

3.1.2  灰度處理

  通常對比影象相似度和顏色關係不是很大,所以處理為灰度圖,減少後期計算的複雜度。如果有特殊需求則保留影象色彩。

3.1.3 計算平均值

  此處開始,與傳統的雜湊演算法不同:分別依次計算影象每行畫素點的平均值,記錄每行畫素點的平均值。每一個平均值對應著一行的特徵。

3.1.4  計算方差

  對得到的所有平均值進行計算方差,得到的方差就是影象的特徵值。方差可以很好的反應每行畫素特徵的波動,既記錄了圖片的主要資訊。

3.1.5  比較方差

  經過上面的計算之後,每張圖都會生成一個特徵值(方差)。到此,比較影象相似度就是比較影象生成方差的接近成程度。
  一組資料方差的大小可以判斷穩定性,多組資料方差的接近程度可以反應資料波動的接近程度。我們不關注方差的大小,只關注兩個方差的差值的大小。方差差值越小影象越相似!

 

3.2  程式碼:

import cv2
import matplotlib.pyplot as plt

#計算方差
def getss(list):
    #計算平均值
    avg=sum(list)/len(list)
    #定義方差變數ss,初值為0
    ss=0
    #計算方差
    for l in list:
        ss+=(l-avg)*(l-avg)/len(list)
    #返回方差
    return ss

#獲取每行畫素平均值
def getdiff(img):
    #定義邊長
    Sidelength=30
    #縮放影象
    img=cv2.resize(img,(Sidelength,Sidelength),interpolation=cv2.INTER_CUBIC)
    #灰度處理
    gray=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    #avglist列表儲存每行畫素平均值
    avglist=[]
    #計算每行均值,儲存到avglist列表
    for i in range(Sidelength):
        avg=sum(gray[i])/len(gray[i])
        avglist.append(avg)
    #返回avglist平均值
    return avglist

#讀取測試圖片
img1=cv2.imread("james.jpg")
diff1=getdiff(img1)
print('img1:',getss(diff1))

#讀取測試圖片
img11=cv2.imread("durant.jpg")
diff11=getdiff(img11)
print('img11:',getss(diff11))

ss1=getss(diff1)
ss2=getss(diff11)
print("兩張照片的方差為:%s"%(abs(ss1-ss2)))

x=range(30)

plt.figure("avg")
plt.plot(x,diff1,marker="*",label="$jiames$")
plt.plot(x,diff11,marker="*",label="$durant$")
plt.title("avg")
plt.legend()
plt.show()


cv2.waitKey(0)
cv2.destroyAllWindows()

 兩張原圖:

 

影象結果如下:

img1: 357.03162469135805
img11: 202.56193703703704
兩張照片的方差為:154.469687654321

 

   實驗環境開始設定了圖片畫素值,而且進行灰度化處理,此方法比對影象相似對不同的圖片方差很大,結果很明顯,但是對比比較相似,特別相似的圖片不適應。

四:圖片相似度演算法(感知雜湊演算法)的學習

  "感知雜湊演算法"(Perceptual hash algorithm),它的作用是對每張圖片生成一個"指紋"(fingerprint)字串,然後比較不同圖片的指紋。結果越接近,就說明圖片越相似。

4.1  演算法步驟

4.1.1 縮小尺寸

  將圖片縮小到8x8的尺寸,總共64個畫素。這一步的作用是去除圖片的細節,只保留結構、明暗等基本資訊,摒棄不同尺寸、比例帶來的圖片差異。

4.1.2  簡化色彩

  將縮小後的圖片,轉為64級灰度。也就是說,所有畫素點總共只有64種顏色。

4.1.3  計算平均值

  計算所有64個畫素的灰度平均值

4.1.4  比較畫素的灰度平均值

  將每個畫素的灰度,與平均值進行比較。大於或等於平均值,記為1;小於平均值,記為0。

4.1.5 計算雜湊值

  將上一步的比較結果,組合在一起,就構成了一個64位的整數,這就是這張圖片的指紋。組合的次序並不重要,只要保證所有圖片都採用同樣次序就行了。

  得到指紋以後,就可以對比不同的圖片,看看64位中有多少位是不一樣的。在理論上,這等同於計算"漢明距離"(Hamming distance)。如果不相同的資料位不超過5,就說明兩張圖片很相似;如果大於10,就說明這是兩張不同的圖片。

    此演算法參考部落格:http://www.ruanyifeng.com/blog/2011/07
    /principle_of_similar_image_search.html
    
但是未實現程式碼,程式碼如下:

 

#!/usr/bin/python

import glob
import os
import sys

from PIL import Image

EXTS = 'jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'

def avhash(im):
    if not isinstance(im, Image.Image):
        im = Image.open(im)
    im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
    avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
    return reduce(lambda x, (y, z): x | (z << y),
                  enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())),
                  0)

def hamming(h1, h2):
    h, d = 0, h1 ^ h2
    while d:
        h += 1
        d &= d - 1
    return h

if __name__ == '__main__':
    if len(sys.argv) <= 1 or len(sys.argv) > 3:
        print "Usage: %s image.jpg [dir]" % sys.argv[0]
    else:
        im, wd = sys.argv[1], '.' if len(sys.argv) < 3 else sys.argv[2]
        h = avhash(im)

        os.chdir(wd)
        images = []
        for ext in EXTS:
            images.extend(glob.glob('*.%s' % ext))

        seq = []
        prog = int(len(images) > 50 and sys.stdout.isatty())
        for f in images:
            seq.append((f, hamming(avhash(f), h)))
            if prog:
                perc = 100. * prog / len(images)
                x = int(2 * perc / 5)
                print '\rCalculating... [' + '#' * x + ' ' * (40 - x) + ']',
                print '%.2f%%' % perc, '(%d/%d)' % (prog, len(images)),
                sys.stdout.flush()
                prog += 1

        if prog: print
        for f, ham in sorted(seq, key=lambda i: i[1]):
            print "%d\t%s" % (ham, f)

 

五:marking——對OpenCV中cvWaitKey函式的學習

  用OpenCV來顯示影象或者視訊時,如果後面不加cvWaitKey這個函式,基本上是顯示不出來的。

  顯示影象,一般要在cvShowImage()函式後面加一句cvWaitKey(0);否則影象無法正常顯示。

  

def waitKey(delay=None): # real signature unknown; restored from __doc__
    """
    waitKey([, delay]) -> retval
    .   @brief Waits for a pressed key.
    .   
    .   The function waitKey waits for a key event infinitely (when \f$\texttt{delay}\leq 0\f$ ) or for delay
    .   milliseconds, when it is positive. Since the OS has a minimum time between switching threads, the
    .   function will not wait exactly delay ms, it will wait at least delay ms, depending on what else is
    .   running on your computer at that time. It returns the code of the pressed key or -1 if no key was
    .   pressed before the specified time had elapsed.
    .   
    .   @note
    .   
    .   This function is the only method in HighGUI that can fetch and handle events, so it needs to be
    .   called periodically for normal event processing unless HighGUI is used within an environment that
    .   takes care of event processing.
    .   
    .   @note
    .   
    .   The function only works if there is at least one HighGUI window created and the window is active.
    .   If there are several HighGUI windows, any of them can be active.
    .   
    .   @param delay Delay in milliseconds. 0 is the special value that means "forever".
    """
    pass

 

 

六:marking——影象增強中一階微分和二階微分的區別

1,斜坡面上,一階微分一直不為0 ;二階微分只有終點和起點不為0

2,一階微分產生較粗的邊緣,二階微分則細得多

3,一階微分處理一般對灰度階梯有較強的響應;二階微分處理細節有較強的響應

 

七:關於OpenCV

  OpenCV的全稱open Sourse Computer Vision Library ,是一個跨平臺的計算機視覺庫,OpenCV可用於開發實時的影象處理,計算機視覺以及模式識別的程式。

  OpenCV是用C++語言編寫,它的主要介面也是C++語言,但是依然保留了大量的C語言介面,該庫也有大量的Python,Java和MATLAB的介面,另外,一個使用CUDA的GPU介面也用於2010.9 開始實現。

7.1  為什麼使用Python+OpenCV

  雖然python很強大,而且也有自己的影象處理庫PIL,但是相對於OpenCV來講,它還是弱小很多。跟很多開源軟體一樣OpenCV也提供了完善的python介面,非常便於呼叫。OpenCV 的穩定版是2.4.8,最新版是3.0,包含了超過2500個演算法和函式,幾乎任何一個能想到的成熟演算法都可以通過呼叫OpenCV的函式來實現,超級方便。

 

 7.2  import cv2發生錯誤的解決方案

   錯誤如下:

1,進入cmd控制檯,檢視python版本

2 根據自己用的python版本,下載對應的OpenCV

https://www.lfd.uci.edu/~gohlke/pythonlibs/

 

 3,下載numpy,對應的版本

https://pypi.python.org/pypi/numpy 

 cp36代表著匹配python3.6版本。

win32、amd64代表著32位、64位系統。

  

4,安裝OpenCV,下載下來是一個whl格式檔案,把此檔案放在安裝的檔名下,直接安裝。

 

  就這樣安裝成功。

 

 

參考文獻:https://blog.csdn.net/wsp_1138886114/article/details/81368890