1. 程式人生 > >Python3+OpenCV3影象處理(八)—— 影象直方圖

Python3+OpenCV3影象處理(八)—— 影象直方圖

直方圖簡介:影象的直方圖是用來表現影象中亮度分佈的直方圖,給出的是影象中某個亮度或者某個範圍亮度下共有幾個畫素.還不明白?就是統計一幅圖某個亮度畫素數量.比如對於灰度值12,一幅圖裡面有2000 個畫素其灰度值為12,那麼就能夠統計12這個亮度的畫素為2000個,其他類推。參考:https://blog.csdn.net/xierhacker/article/details/52605308

一、安裝matplotlib

要畫直方圖必須要安裝matplotlib庫,Matplotlib 是一個 Python 的 2D繪相簿。

安裝步驟:

執行cmd,然後在自己的python安裝路徑的Scripts資料夾目錄下,輸入命令: pip install matplotlib

二、畫直方圖

程式碼如下:

複製程式碼

#畫直方圖
import cv2 as cv
from matplotlib import pyplot as plt

def plot_demo(image):
    plt.hist(image.ravel(), 256, [0, 256])         #numpy的ravel函式功能是將多維陣列降為一維陣列
    plt.show()

def image_hist(image):     #畫三通道影象的直方圖
    color = ('b', 'g', 'r')   #這裡畫筆顏色的值可以為大寫或小寫或只寫首字母或大小寫混合
    for i , color in enumerate(color):
        hist = cv.calcHist([image], [i], None, [256], [0, 256])  #計算直方圖
        plt.plot(hist, color)
        plt.xlim([0, 256])
    plt.show()

src = cv.imread('E:/imageload/WindowsLogo.jpg')
cv.namedWindow('input_image', cv.WINDOW_NORMAL)
cv.imshow('input_image', src)

plot_demo(src)
image_hist(src)

cv.waitKey(0)
cv.destroyAllWindows()

複製程式碼

執行結果:

注意:

2.matplotlib.pyplot.hist函式主要是計算直方圖。

hist函式原型:hist(x, bins=None, range=None, density=None, weights=None, cumulative=False, bottom=None, histtype='bar', align='mid', orientation='vertical', rwidth=None, log=False, color=None, label=None, stacked=False, normed=None, hold=None, data=None, **kwargs)

x引數表示是一個數組或一個序列,是指定每個bin(箱子)分佈的資料

bins引數表示指定bin(箱子)的個數,也就是總共有幾條條狀圖

range引數表示箱子的下限和上限。即橫座標顯示的範圍,範圍之外的將被捨棄。

3.enumerate() 函式用於將一個可遍歷的資料物件(如列表、元組或字串)組合為一個索引序列,同時列出資料下標和資料,一般用在 for 迴圈當中。

4.cv2.calcHist的原型為:calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]]) -> hist

images引數表示輸入影象,傳入時應該用中括號[ ]括起來

channels引數表示傳入影象的通道,如果是灰度影象,那就不用說了,只有一個通道,值為0,如果是彩色影象(有3個通道),那麼值為0,1,2,中選擇一個,對應著BGR各個通道。這個值也得用[ ]傳入。

mask引數表示掩膜影象。如果統計整幅圖,那麼為None。主要是如果要統計部分圖的直方圖,就得構造相應的掩膜來計算。

histSize引數表示灰度級的個數,需要中括號,比如[256]

ranges引數表示畫素值的範圍,通常[0,256]。此外,假如channels為[0,1],ranges為[0,256,0,180],則代表0通道範圍是0-256,1通道範圍0-180。

hist引數表示計算出來的直方圖。

5.關於pyplot模組裡plot()函式、xlim()函式等的用法參考:

三、直方圖的應用

程式碼如下:

複製程式碼

#直方圖的應用    直方圖均衡化(即調整影象的對比度)   直方圖即統計各畫素點的頻次
import cv2 as cv
#全域性直方圖均衡化
def eaualHist_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)    #opencv的直方圖均衡化要基於單通道灰度影象
    cv.namedWindow('input_image', cv.WINDOW_NORMAL)
    cv.imshow('input_image', gray)
    dst = cv.equalizeHist(gray)                #自動調整影象對比度,把影象變得更清晰
    cv.namedWindow("eaualHist_demo", cv.WINDOW_NORMAL)
    cv.imshow("eaualHist_demo", dst)

#區域性直方圖均衡化
def clahe_demo(image):
    gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
    clahe = cv.createCLAHE(5, (8,8))
    dst = clahe.apply(gray)
    cv.namedWindow("clahe_demo", cv.WINDOW_NORMAL)
    cv.imshow("clahe_demo", dst)

src = cv.imread('E:/imageload/rice.png')

eaualHist_demo(src)
clahe_demo(src)

cv.waitKey(0)
cv.destroyAllWindows()

複製程式碼

執行結果:

注意:

1.cv2.equalizeHist函式原型:equalizeHist(src[, dst]) -> dst。函式equalizeHist的作用:直方圖均衡化,提高影象質量。

2.直方圖均衡化:如果一副影象的畫素佔有很多的灰度級而且分佈均勻,那麼這樣的影象往往有高對比度和多變的灰度色調。直方圖均衡化就是一種能僅靠輸入影象直方圖資訊自動達到這種效果的變換函式。它的基本思想是對影象中畫素個數多的灰度級進行展寬,而對影象中畫素個數少的灰度進行壓縮,從而擴充套件像元取值的動態範圍,提高了對比度和灰度色調的變化,使影象更加清晰。

3.全域性直方圖均衡化可能得到是一種全域性意義上的均衡化,但是有的時候這種操作並不是很好,會把某些不該調整的部分給調整了。Opencv中還有一種直方圖均衡化,它是一種區域性直方圖均衡化,也就是是說把整個影象分成許多小塊(比如按10*10作為一個小塊),那麼對每個小塊進行均衡化。

4.createCLAHE函式原型:createCLAHE([, clipLimit[, tileGridSize]]) -> retval

clipLimit引數表示對比度的大小。

tileGridSize引數表示每次處理塊的大小 。

5. 

clahe = cv.createCLAHE(5, (8,8))       

dst = clahe.apply(gray)      #猜測:把clahe這種區域性直方圖均衡化應用到灰度圖gray

這兩句程式碼只知道大概意思,百度了好久也沒找到詳細解釋,連help()也找不到,很絕望。。。。。如果以後知道了再來補充,也希望各位路過的大佬能解釋一波!

四、直方圖反向投影

程式碼如下:

複製程式碼

#直方圖反向投影技術(通過二維直方圖反映,必須先把原影象轉換為hsv)
import cv2 as cv

#計算H-S直方圖
def back_projection_demo():
    sample = cv.imread("E:/imageload/sample.jpg")
    target = cv.imread("E:/imageload/target.jpg")
    roi_hsv = cv.cvtColor(sample, cv.COLOR_BGR2HSV)
    target_hsv = cv.cvtColor(target, cv.COLOR_BGR2HSV)
    cv.namedWindow("sample", cv.WINDOW_NORMAL)
    cv.imshow("sample", sample)
    cv.namedWindow("target", cv.WINDOW_NORMAL)
    cv.imshow("target", target)
    roiHist = cv.calcHist([roi_hsv], [0, 1], None, [32, 30], [0, 180, 0, 256])#計算樣本直方圖   [32, 30]越小,效果越好
    cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX) #規劃到0-255之間
    dst = cv.calcBackProject([target_hsv], [0,1], roiHist, [0, 180, 0, 256], 1) #計算反向投影
    cv.namedWindow("back_projection_demo", cv.WINDOW_NORMAL)
    cv.imshow("back_projection_demo", dst)

back_projection_demo()
cv.waitKey(0)
cv.destroyAllWindows()

複製程式碼

執行結果:

注意:

1. 歸一化就是要把需要處理的資料經過處理後(通過某種演算法)限制在你需要的一定範圍內。

歸一化函式cv2.normalize原型:normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]) -> dst 

src引數表示輸入陣列。

dst引數表示輸出與src相同大小的陣列,支援原地運算。

alpha引數表示range normalization模式的最小值。

beta引數表示range normalization模式的最大值,不用於norm normalization(範數歸一化)模式。

norm_type引數表示歸一化的型別。

norm_type引數可以有以下的取值:

NORM_MINMAX:陣列的數值被平移或縮放到一個指定的範圍,線性歸一化,一般較常用。

NORM_INF:歸一化陣列的C-範數(絕對值的最大值)。

NORM_L1 :歸一化陣列的L1-範數(絕對值的和)。

NORM_L2 :歸一化陣列的(歐幾里德)L2-範數。

2.反向投影用於在輸入影象(通常較大)中查詢特定影象(通常較小或者僅1個畫素,以下將其稱為模板影象)最匹配的點或者區域,也就是定位模板影象出現在輸入影象的位置。

函式cv2.calcBackProject用來計算直方圖反向投影。

函式原型:calcBackProject(images, channels, hist, ranges, scale[, dst]) -> dst

images引數表示輸入影象(是HSV影象)。傳入時應該用中括號[ ]括起來。

channels引數表示用於計算反向投影的通道列表,通道數必須與直方圖維度相匹配。

hist引數表示輸入的模板影象直方圖。

ranges引數表示直方圖中每個維度bin的取值範圍 (即每個維度有多少個bin)。

scale引數表示可選輸出反向投影的比例因子,一般取1。