Python OpenCV 365 天學習計劃,與橡皮擦一起進入影像領域吧,本篇博客是這個系列的第 50 篇,
該系列文章導航參考:https://blog.csdn.net/hihell/category_10688961.html
Python OpenCV
- 學在前面
- 直方圖繪制
- Python OpenCV 中的直方圖繪制
- 掩膜繪制直方圖
- 直方圖均衡化相關知識補充
- 橡皮擦的小節
學在前面
直方圖在之前的博客中已經學習過一部分內容了,具體可以自行去回顧,

直方圖是影像處理程序中的一個分析工具,是使用灰度值或者從灰度級的角度統計影像的特征,
如果從統計的角度看,直方圖統計了影像各個灰度級出現的次數,直方圖橫坐標是像素灰度級,縱坐標是該灰度級的個數,
如果存在一個 5x5 的灰度圖,那直方圖就是對其中的各個像素值進行統計,


上面 2 張圖就是關于直方圖統計的說明,但直方圖直觀的呈現不是表格,而是圖形,所以將上述資料進行繪制,即可得到直方圖,
直方圖中 x 軸表示的是 8 位位圖的 256 個灰度級,y 軸表示的是對應灰度級的像素點格式,
基于此還要補充一個知識,叫做歸一化的直方圖,在很多時候,直方圖中 x 軸表示灰度級,但是 y 軸表示灰度級出現的頻率,具體就是將次數/總數,例如上表可以修改為:

直方圖概念理解之后,還有幾個新詞需要注意下,DIMS、BINS、RANGE,
DIMS:基于目前知識,只有一個灰度值,該值為 1,它表示的是收集直方圖時,收集的引數數量;RANGE:統計灰度級范圍,對于灰度圖,范圍是[0,255];BINS:引數子級數目,大概含義可以理解為,將剛才的灰度級做分組處理,一般保持默認即可,
對于 BINS 引數在細說一下,對于灰度影像,灰度級的區間是 [0,255],其 BINS 默認是 256,如果按照 16 個灰度級為一組,可以分為 16 個 BINS,
直方圖繪制
Python OpenCV 影像處理之影像直方圖,取經之旅第 25 天 本篇博客已經對直方圖的繪制進行了說明,先來整體回顧一下,
代碼基于 plt.hist() 函式實作直方圖,該函式原型為 plt.hist(X,BINS)
運行下述代碼,找圖片的時候,盡量找顏色分布比較平均的,不要白色或者黑色所占區域特別大,否則得到的直方圖效果不明顯,
import cv2 as cv
import matplotlib.pyplot as plt
src = cv.imread("./2.png", 0)
cv.imshow("src", src)
plt.hist(src.ravel(), 256)
plt.show()
cv.waitKey()
cv.destroyAllWindows()

上述代碼還有一個需要注意的就是 src.ravel() 函式了,該函式用于將二維陣列降成一維陣列,例如下圖所示,

如果將 BINS 設定為 16 得到的結果如下,

Python OpenCV 中的直方圖繪制
在 OpenCV 中使用 cv.calcHist 函式計算影像的直方圖,本文重點說明一下該函式的回傳值,
import cv2 as cv
import matplotlib.pyplot as plt
src = cv.imread("./2.png", 0)
cv.imshow("src", src)
hist = cv.calcHist([src], [0], None, [256], [0, 255])
print(hist)
print(len(hist))
cv.waitKey()
cv.destroyAllWindows()
hist 輸出格式如下:
# 省略一部分輸出資料
……
[ 115.]
[ 122.]
[ 115.]
[ 142.]
[ 148.]
[ 152.]
[ 61.]
[ 6.]
[ 0.]]
256
可以看到最后回傳的 hist 是 256 個數字組成的陣列,該陣列內的元素是各個灰度級的統計個數,
得到 hist 之后,就可以通過 plt.plot 函式將其繪制出來啦,
import cv2 as cv
import matplotlib.pyplot as plt
src = cv.imread("./2.png", 0)
cv.imshow("src", src)
ret_hist = cv.calcHist([src], [0], None, [256], [0, 255])
print(ret_hist)
print(len(ret_hist))
plt.plot(ret_hist)
plt.show()
cv.waitKey()
cv.destroyAllWindows()

掩膜繪制直方圖
接下來說明一下掩膜繪制直方圖,通過掩膜就是選擇影像的一部磁區域進行繪制,掩膜白色區域表示透明,可顯示圖片,黑色區域表示不透明,無法顯示圖片,
掩膜的原理也可以翻閱以前的博客進行學習,總結下來就是下面兩句話
- 原影像與掩膜中黑色位置對應的部分,這部分就不再顯示了,灰度值被置為 0;
- 原影像與掩膜中白色位置對應的部分,保留原值,
import cv2 as cv
import matplotlib.pyplot as plt
import numpy as np
src = cv.imread("./2.png", 0)
cv.imshow("src", src)
print(src.shape)
mask = np.zeros(src.shape, np.uint8)
# 前面是行,后面是列
mask[10:150, 40: 200] = 255
mask_img = cv.bitwise_and(src, mask)
cv.imshow("mask", mask_img)
ret_hist = cv.calcHist([src], [0], None, [256], [0, 255])
mask_hist = cv.calcHist([src], [0], mask, [256], [0, 255])
plt.plot(ret_hist)
plt.plot(mask_hist)
plt.show()
cv.waitKey()
cv.destroyAllWindows()

直方圖均衡化相關知識補充
直方圖均衡化,可以使影像擁有全部可能的灰度級,讓像素值的灰度均勻分布,實作的具體步驟如下,
- 計算累計直方圖
- 對累計直方圖進行轉換
可以參考下述灰度矩陣,該影像大小為 5x5,具有 8 個灰度級,范圍是 [0,7],計算歸一化的統計直方圖與累計統計直方圖分別如下,

基于上圖,可以對原有灰度級空間進行轉換,分為兩種一種是在原有的灰度空間范圍,即 [0,7],第二種是在更大范圍進行轉換,
首先看一下在原有范圍內實作均衡化,用當前的累計概率乘以 7(灰度級的最大值),得到新的灰度級,

新灰度級與原灰度級個數可以對比得出,
未均衡化之前,灰度級如果區分成 2 組,資料如下:
0~3:4 個像素點,統計的像素個數是 19;4~7:4 個像素點,統計的像素個數是 6,
均衡化之后,灰度級如果區分成 2 組,資料如下:0~3:4 個像素點,統計的像素個數是 11;4~7:4 個像素點,統計的像素個數是 14,
如果希望得到更大范圍的直方圖,只需要將累計概率乘以更大的灰度級即可,具體可以自行嘗試,
橡皮擦的小節
希望今天的 1 個小時你有所識訓,我們下篇博客見~
相關閱讀
技術專欄
- Python 爬蟲 100 例教程,超棒的爬蟲教程,立即訂閱吧
- Python 爬蟲小課,精彩 9 講
今天是持續寫作的第 94 / 100 天,
如果你想跟博主建立親密關系,可以關注同名公眾號 夢想橡皮擦,近距離接觸一個逗趣的互聯網高級網蟲,
博主 ID:夢想橡皮擦,希望大家點贊、評論、收藏,
CSDN認證博客專家
高級產品經理
互聯網從業者
業余編程愛好者
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/265346.html
標籤:AI
