Python OpenCV 圖像處理之圖像直方圖,取經(jīng)之旅第 25

Python OpenCV 365 天學(xué)習(xí)計(jì)劃耸袜,與橡皮擦一起進(jìn)入圖像領(lǐng)域吧友多。

基礎(chǔ)知識(shí)鋪墊

截止到本篇博客,已經(jīng)第二次聽到直方圖這個(gè)概念了堤框,有必要將其搞懂域滥。

圖像直方圖(histogram)是圖像統(tǒng)計(jì)學(xué)特征纵柿,用來統(tǒng)計(jì)像素值出現(xiàn)的頻次,常用在分析圖像的基本特征启绰。

創(chuàng)建直方圖一般分為兩個(gè)步驟:

  1. 統(tǒng)計(jì)數(shù)據(jù)
  2. 繪制直方圖

直方圖的定義

  • 橫坐標(biāo):圖像中各個(gè)像素點(diǎn)的灰度級(jí)
  • 縱坐標(biāo):該灰度級(jí)的像素個(gè)數(shù)

繪制直方圖需要 matplotlib 庫昂儒,這個(gè)需要自行安裝一下。

matplotlib 中 pyplot 繪制直方圖

pyplot 中提供了一個(gè)繪制直方圖的函數(shù)委可,名稱為 hist荆忍。

函數(shù)原型介紹

matplotlib.pyplot.hist() 函數(shù)原型如下

(n, bins, patches)=matplotlib.pyplot.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, *, data=None, **kwargs)

參數(shù)非常多,實(shí)際應(yīng)用中只需掌握幾個(gè)重要參數(shù)撤缴。

最簡(jiǎn)單的測(cè)試代碼如下:

import numpy as np
import matplotlib.pyplot as plt

# 生成數(shù)據(jù)刹枉,以 10000 組均值為0,標(biāo)準(zhǔn)差為 1 的高斯分布數(shù)據(jù)為例
data = np.random.normal(0,1,10000)

n, bins, patches = plt.hist(data)
plt.show()

運(yùn)行效果如下:


20210125165332331[1].png

其中屈呕,np.random.normal(0,1,10000) 函數(shù)說明如下微宝,np.random.normal() 是一個(gè)正態(tài)分布,normal這里是正態(tài)的意思虎眨。

該函數(shù)原型為:

numpy.random.normal(loc=0.0, scale=1.0, size=None)

參數(shù)說明如下:

  • loc:概率分布的均值蟋软,對(duì)應(yīng)著整個(gè)分布的中心 center
  • scale:概率分布的標(biāo)準(zhǔn)差,對(duì)應(yīng)于分布的寬度嗽桩,scale 越大岳守,越矮胖,scale 越小碌冶,越瘦高
  • size:數(shù)據(jù)類型為 int or tuple of ints湿痢, 輸出的 shape,默認(rèn)為 None扑庞,只輸出一個(gè)值

其實(shí)該函數(shù)的目的就是譬重,輸出為高斯分布的一組數(shù)或一個(gè)值。
簡(jiǎn)單案例:

data = np.random.normal(loc=0, scale=1, size=2)
print(data)

繼續(xù)回顧 matplotlib.pyplot.hist() 函數(shù)的相關(guān)參數(shù)(官網(wǎng)說明):

只選取其中比較重要的幾個(gè)參數(shù)如下:

  • x:(n,) array or sequence of (n,) arrays
    指定要繪制直方圖的數(shù)據(jù),必須是一維數(shù)組.使用.ravel()將你的通道值轉(zhuǎn)為一維數(shù)組
  • bins:integer or sequence or ‘a(chǎn)uto’, optional
    指定直方圖條形的個(gè)數(shù)罐氨,integer 或 auto,也可以不設(shè)置.舉例[1,2,3,4],則第一個(gè)柱為取值[1,2),一次類推,最后一個(gè)是取值[3,4].默認(rèn) taken from the rcParam hist.bins.
  • range:tuple or None, optional
    數(shù)組或者不給.給出數(shù)組將指定直方圖數(shù)據(jù)的上下界臀规,超出范圍的舍棄.不設(shè)置的話包含繪圖數(shù)據(jù)的最大值和最小值;默認(rèn)為 None

基于上述內(nèi)容栅隐,將一副圖像的直方圖顯示出來塔嬉。

做一些準(zhǔn)備工作

  • x: 圖像,必須是一維數(shù)組
  • 其中函數(shù) ravel b = a.ravel()
    功能: 將多維數(shù)組降為一維數(shù)組
    格式: 一維數(shù)組=多維數(shù)組.revel()
  • bins: 一般是 256租悄,指[0, 255]

以上內(nèi)容掌握之后谨究,就可以處理圖像的直方圖了,代碼如下:

import cv2
from matplotlib import pyplot as plt


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


if __name__ == "__main__":
    img = cv2.imread("./106.jpg")
    cv2.namedWindow("input image", cv2.WINDOW_AUTOSIZE)
    cv2.imshow("input image", img)
    plot_demo(img)

    cv2.waitKey(0)
    cv2.destroyAllWindows()
20210125171053391[1].png

python opencv 直方圖(histogram)

函數(shù)原型介紹

在 Python OpenCV 中實(shí)現(xiàn)直方圖的函數(shù)為cv2.calcHist恰矩,原型如下:

# 返回 hist
cv2.calcHist(img, channels, mask, histSize, ranges[, hist[, accumulate ]])

參數(shù)說明:

  • img:圖像记盒,方括號(hào)方式傳入,即[img]外傅;
  • channels:選取圖像的哪個(gè)通道纪吮,用方括號(hào)給出的,計(jì)算直方圖的 channel 的索引萎胰,如果輸入時(shí)灰度圖碾盟,值就是 [0],對(duì)于彩色圖片技竟,你可以傳 [0] 冰肴,[1][2] 來分別計(jì)算藍(lán)色,綠色和紅色通道的直方圖榔组;
  • mask:掩膜熙尉,如果要找整個(gè)圖像的直方圖,這里傳入"None"搓扯。如果你想找到特定區(qū)域圖片的直方圖检痰,需要使用掩膜,只計(jì)算值>0 的位置上像素的顏色直方圖
  • histSize:直方圖大小锨推,BINS 數(shù)量(BINS 是啥铅歼,下面細(xì)說),要方括號(hào)傳入换可,對(duì)于全刻度椎椰,傳入 [256]
  • ranges:直方圖范圍,一般來說是[0,256]

關(guān)于上文提及的 BINS 等內(nèi)容涉及直方圖如下概念:

  • BINS: 在上面的直方圖當(dāng)中沾鳄,如果像素值是 0 到 255慨飘,則需要 256 個(gè)值來顯示直方圖。
    但是译荞,如果不需要知道每個(gè)像素值的像素?cái)?shù)目套媚,只想知道兩個(gè)像素值范圍內(nèi)的像素點(diǎn)數(shù)目即可?首先像素值在 0--15 之間的像素點(diǎn)數(shù)目磁椒,然后是 16--31 ……直到 240--255堤瘤,即每次間隔 16 個(gè)數(shù)字,將 256 個(gè)值分成 16 份浆熔,每份計(jì)算綜合本辐。每個(gè)分成的小組就是一個(gè) BIN(箱)。在 opencv 中使用 histSize 表示 BINS医增。

彩色圖像慎皱,不同通道的直方圖

首先繪制藍(lán)色通道的直方圖,代碼如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./106.jpg')
hist = cv.calcHist([img], [0], None, [256], [0,256])

plt.plot(hist, label='B', color='b')
plt.show()

運(yùn)行結(jié)果如下:

20210125202235780[1].png

三個(gè)通道同時(shí)繪制代碼如下:

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img = cv.imread('./106.jpg')
color = ('b', 'g', 'r')
for i, col in enumerate(color):

    hist = cv.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(hist, color=col)
    plt.xlim([0, 256])
plt.show()

BGR 直方圖如下:


2021012520254698[1].png

直方圖均衡化 (Histogram Equalization)

如果圖像的灰度分布不均勻叶骨,集中在一個(gè)比較窄的范圍內(nèi)茫多,這樣圖像的細(xì)節(jié)就會(huì)不清晰,對(duì)比度低忽刽。

這種情況可以使用直方圖均衡化天揖,對(duì)圖像進(jìn)行非線性拉伸夺欲,重新分配圖像的灰度值,使一定范圍內(nèi)圖像的灰度值大致相等今膊。

執(zhí)行之后些阅,直方圖中間峰值部分對(duì)比度增強(qiáng),兩側(cè)谷底部分對(duì)比度降低斑唬。圖像的灰度范圍拉伸之后市埋,灰度均勻分布,反差增大恕刘,增強(qiáng)圖像細(xì)節(jié)缤谎。

理論的東西就是上面那些了,實(shí)操起來才可以看到效果褐着。

函數(shù)原型介紹

使用 cv2.equalizeHist 方法來得到直方圖均衡化之后的圖像坷澡,函數(shù)原型如下:

cv2.equalizeHist(src[, dst])

參數(shù)說明:

  • src:源圖像。圖像必須是灰度圖献起。
  • dst:目標(biāo)圖像洋访。

測(cè)試代碼如下:

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

image = cv.imread("2o.jpg")
# 將圖片轉(zhuǎn)換為灰度圖
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)

# 直方圖繪制
hist = cv.calcHist([gray], [0], None, [256], [0, 256])
plt.plot(hist)
plt.show()

# 應(yīng)用直方圖均衡化
dst = cv.equalizeHist(gray)
cv.imshow("dst", dst)

# 直方圖繪制
hist = cv.calcHist([dst], [0], None, [256], [0, 256])
plt.plot(hist)
plt.show()

運(yùn)行結(jié)果與直方圖:

20210125205905178[1].png

運(yùn)行直方圖均衡化之后的圖像如下:


20210125205936297[1].png

上述案例為灰度圖直方圖均衡化,對(duì)于彩色圖像一樣可以進(jìn)行圖像增強(qiáng)操作谴餐。

import cv2 as cv
import numpy as np
img = cv.imread('th.jpeg')
cv.imshow('img', img)
b, g, r = cv.split(img)
bH = cv.equalizeHist(b)
gH = cv.equalizeHist(g)
rH = cv.equalizeHist(r)
dst = cv.merge((bH, gH, rH))
cv.imshow('dst', dst)
cv.waitKey(0)

使用cv2.split函數(shù)分離圖像的顏色通道姻政,分別得到各個(gè)通道的直方圖,再使用cv2.merge函數(shù)合并各通道岂嗓,得到彩色圖像的直方圖均衡化汁展。

20210125210633576[1].png

以上提及的叫做全局直方圖均衡化,下面為大家在介紹一下局部直方圖均衡化厌殉。

局部直方圖均衡化在有的地方也被叫做 CLAHE 有限對(duì)比適應(yīng)性直方圖均衡化食绿。

大概實(shí)現(xiàn)過程如下:
整幅圖像會(huì)被分成很多小塊,這些小塊被稱為 “tiles”(tiles 的默認(rèn)大小是 8x8)公罕,然后再對(duì)每一個(gè)小塊分別進(jìn)行直方圖均衡化器紧。

函數(shù)原型如下:

cv2.createCLAHE(clipLimit, tileGridSize)

參數(shù)說明:

  • clipLimit:對(duì)比度限制的閾值
  • tileGridSize:圖像分割每塊的尺寸,默認(rèn) 8x8

運(yùn)行下述代碼楼眷,得到的結(jié)果可以與全局直方圖均衡化做一下比較铲汪。

import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt

image = cv.imread("2o.jpg")
# 將圖片轉(zhuǎn)換為灰度圖
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
cv.imshow("gray", gray)

# 直方圖繪制
hist = cv.calcHist([gray], [0], None, [256], [0, 256])
plt.plot(hist)
plt.show()

# 應(yīng)用直方圖均衡化
# 1. 實(shí)例化自適應(yīng)直方圖均衡化函數(shù)
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
# 2. 進(jìn)行自適應(yīng)直方圖均衡化
dst = clahe.apply(gray)
cv.imshow("dst", dst)

# 直方圖繪制
hist = cv.calcHist([dst], [0], None, [256], [0, 256])
plt.plot(hist)
plt.show()
20210125211452816[1].png

橡皮擦的小節(jié)

今天重點(diǎn)學(xué)習(xí)了一下直方圖,寫了這么多罐柳,只有一個(gè)原因掌腰,就是這是第二次碰到了,當(dāng)一個(gè)知識(shí)點(diǎn)再次出現(xiàn)時(shí)张吉,就要在進(jìn)一步的學(xué)習(xí)下齿梁,因?yàn)榇蟾怕仕侵攸c(diǎn)知識(shí)。

相關(guān)閱讀


  1. Python 爬蟲 100 例教程肮蛹,超棒的爬蟲教程勺择,立即訂閱吧
  2. Python 爬蟲小課创南,精彩 9 講

今天是持續(xù)寫作的第 <font color="red">65</font> / 100 天。
如果你有想要交流的想法酵幕、技術(shù)扰藕,歡迎在評(píng)論區(qū)留言缓苛。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末芳撒,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子未桥,更是在濱河造成了極大的恐慌笔刹,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,843評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件冬耿,死亡現(xiàn)場(chǎng)離奇詭異舌菜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)亦镶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,538評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門日月,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人缤骨,你說我怎么就攤上這事爱咬。” “怎么了绊起?”我有些...
    開封第一講書人閱讀 163,187評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵精拟,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我虱歪,道長(zhǎng)蜂绎,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,264評(píng)論 1 292
  • 正文 為了忘掉前任笋鄙,我火速辦了婚禮师枣,結(jié)果婚禮上症见,老公的妹妹穿的比我還像新娘株婴。我一直安慰自己,他們只是感情好彤委,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,289評(píng)論 6 390
  • 文/花漫 我一把揭開白布铐尚。 她就那樣靜靜地躺著拨脉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪宣增。 梳的紋絲不亂的頭發(fā)上玫膀,一...
    開封第一講書人閱讀 51,231評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音爹脾,去河邊找鬼帖旨。 笑死箕昭,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的解阅。 我是一名探鬼主播落竹,決...
    沈念sama閱讀 40,116評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼货抄!你這毒婦竟也來了述召?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,945評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤蟹地,失蹤者是張志新(化名)和其女友劉穎积暖,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體怪与,經(jīng)...
    沈念sama閱讀 45,367評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡夺刑,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,581評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了分别。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片遍愿。...
    茶點(diǎn)故事閱讀 39,754評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖耘斩,靈堂內(nèi)的尸體忽然破棺而出沼填,到底是詐尸還是另有隱情,我是刑警寧澤煌往,帶...
    沈念sama閱讀 35,458評(píng)論 5 344
  • 正文 年R本政府宣布倾哺,位于F島的核電站,受9級(jí)特大地震影響刽脖,放射性物質(zhì)發(fā)生泄漏羞海。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,068評(píng)論 3 327
  • 文/蒙蒙 一曲管、第九天 我趴在偏房一處隱蔽的房頂上張望却邓。 院中可真熱鬧,春花似錦院水、人聲如沸腊徙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,692評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽撬腾。三九已至,卻和暖如春恢恼,著一層夾襖步出監(jiān)牢的瞬間民傻,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,842評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留漓踢,地道東北人牵署。 一個(gè)月前我還...
    沈念sama閱讀 47,797評(píng)論 2 369
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喧半,于是被迫代替她去往敵國(guó)和親奴迅。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,654評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容