Python圖像運(yùn)算之圖像掩膜直方圖和HS直方圖詳解
一.圖像掩膜直方圖
如果要統(tǒng)計(jì)圖像的某一部分直方圖,就需要使用掩碼(蒙板)來(lái)進(jìn)行計(jì)算。假設(shè)將要統(tǒng)計(jì)的部分設(shè)置為白色,其余部分設(shè)置為黑色,然后使用該掩膜進(jìn)行直方圖繪制,其完整代碼如下所示。
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib
#讀取圖像
img = cv2.imread('luo.png')
#轉(zhuǎn)換為RGB圖像
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#設(shè)置掩膜
mask = np.zeros(img.shape[:2], np.uint8)
mask[100:300, 100:300] = 255
masked_img = cv2.bitwise_and(img, img, mask=mask)
#圖像直方圖計(jì)算
hist_full = cv2.calcHist([img], [0], None, [256], [0,256]) #通道[0]-灰度圖
#圖像直方圖計(jì)算(含掩膜)
hist_mask = cv2.calcHist([img], [0], mask, [256], [0,256])
plt.figure(figsize=(8, 6))
#設(shè)置字體
matplotlib.rcParams['font.sans-serif']=['SimHei']
#原始圖像
plt.subplot(221)
plt.imshow(img_rgb, 'gray')
plt.axis('off')
plt.title("(a)原始圖像")
#繪制掩膜
plt.subplot(222)
plt.imshow(mask, 'gray')
plt.axis('off')
plt.title("(b)掩膜")
#繪制掩膜設(shè)置后的圖像
plt.subplot(223)
plt.imshow(masked_img, 'gray')
plt.axis('off')
plt.title("(c)圖像掩膜處理")
#繪制直方圖
plt.subplot(224)
plt.plot(hist_full)
plt.plot(hist_mask)
plt.title("(d)直方圖曲線(xiàn)")
plt.xlabel("x")
plt.ylabel("y")
plt.show()
其運(yùn)行結(jié)果如圖1所示,它使用了一個(gè)200×200像素的掩膜進(jìn)行實(shí)驗(yàn)。其中圖1(a)表示原始圖像,圖1(b)表示200×200像素的掩膜,圖1©表示原始圖像進(jìn)行掩膜處理,圖1(d)表示直方圖曲線(xiàn),藍(lán)色曲線(xiàn)為原始圖像的灰度值直方圖分布情況,綠色波動(dòng)更小的曲線(xiàn)為掩膜直方圖曲線(xiàn)。

二.圖像HS直方圖
為了刻畫(huà)圖像中顏色的直觀特性,常常需要分析圖像的HSV空間下的直方圖特性。HSV空間是由色調(diào)(Hue)、飽和度(Saturation)、以及亮度(Value)構(gòu)成,因此在進(jìn)行直方圖計(jì)算時(shí),需要先將源RGB圖像轉(zhuǎn)化為HSV顏色空間圖像,然后將對(duì)應(yīng)的H和S通道進(jìn)行單元?jiǎng)澐?,再其二維空間上計(jì)算相對(duì)應(yīng)直方圖,再計(jì)算直方圖空間上的最大值并歸一化繪制相應(yīng)的直方圖信息,從而形成色調(diào)-飽和度直方圖(或H-S直方圖)。該直方圖通常應(yīng)用在目標(biāo)檢測(cè)、特征分析以及目標(biāo)特征跟蹤等場(chǎng)景[1-2]。
由于H和S分量與人感受顏色的方式是緊密相連,V分量與圖像的彩色信息無(wú)關(guān),這些特點(diǎn)使得HSV模型非常適合于借助人的視覺(jué)系統(tǒng)來(lái)感知彩色特性的圖像處理算法。
下面的代碼是具體的實(shí)現(xiàn)代碼,使用matplotlib.pyplot庫(kù)中的imshow()函數(shù)來(lái)繪制具有不同顏色映射的2D直方圖。
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#讀取圖像
img = cv2.imread('luo.png')
#轉(zhuǎn)換為RGB圖像
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#圖像HSV轉(zhuǎn)換
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
#計(jì)算H-S直方圖
hist = cv2.calcHist(hsv, [0,1], None, [180,256], [0,180,0,256])
#原始圖像
plt.figure(figsize=(8, 6))
plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.title("(a)"), plt.axis('off')
#繪制H-S直方圖
plt.subplot(122), plt.imshow(hist, interpolation='nearest'), plt.title("(b)")
plt.xlabel("x"), plt.ylabel("y")
plt.show()
圖2(a)表示原始輸入圖像,圖2(b)是原圖像對(duì)應(yīng)的彩色直方圖,其中X軸表示飽和度(S),Y軸表示色調(diào)(H)。在直方圖中,可以看到H=140和S=130附近的一些高值,它對(duì)應(yīng)于艷麗的色調(diào)。

三.直方圖判斷白天黑夜
接著講述一個(gè)應(yīng)用直方圖的案例,通過(guò)直方圖來(lái)判斷一幅圖像是黑夜或白天。常見(jiàn)的方法是通過(guò)計(jì)算圖像的灰度平均值、灰度中值或灰度標(biāo)準(zhǔn)差,再與自定義的閾值進(jìn)行對(duì)比,從而判斷是黑夜還是白天[3-4]。
灰度平均值:該值等于圖像中所有像素灰度值之和除以圖像的像素個(gè)數(shù)。
灰度中值:對(duì)圖像中所有像素灰度值進(jìn)行排序,然后獲取所有像素最中間的值,即為灰度中值。
灰度標(biāo)準(zhǔn)差:又常稱(chēng)均方差,是離均差平方的算術(shù)平均數(shù)的平方根。標(biāo)準(zhǔn)差能反映一個(gè)數(shù)據(jù)集的離散程度,是總體各單位標(biāo)準(zhǔn)值與其平均數(shù)離差平方的算術(shù)平均數(shù)的平方根。如果一幅圖看起來(lái)灰蒙蒙的, 那灰度標(biāo)準(zhǔn)差就?。蝗绻环鶊D看起來(lái)很鮮艷,那對(duì)比度就很大,標(biāo)準(zhǔn)差也大。
下面的代碼是計(jì)算灰度“Lena”圖的灰度平均值、灰度中值和灰度標(biāo)準(zhǔn)差。
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#函數(shù): 獲取圖像的灰度平均值
def fun_mean(img, height, width):
sum_img = 0
for i in range(height):
for j in range(width):
sum_img = sum_img + int(img[i,j])
mean = sum_img / (height * width)
return mean
#函數(shù): 獲取中位數(shù)
def fun_median(data):
length = len(data)
data.sort()
if (length % 2)== 1:
z = length // 2
y = data[z]
else:
y = (int(data[length//2]) + int(data[length//2-1])) / 2
return y
#讀取圖像
img = cv2.imread('lena-hd.png')
#圖像灰度轉(zhuǎn)換
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#獲取圖像高度和寬度
height = grayImage.shape[0]
width = grayImage.shape[1]
#計(jì)算圖像的灰度平均值
mean = fun_mean(grayImage, height, width)
print("灰度平均值:", mean)
#計(jì)算圖像的灰度中位數(shù)
value = grayImage.ravel() #獲取所有像素值
median = fun_median(value)
print("灰度中值:", median)
#計(jì)算圖像的灰度標(biāo)準(zhǔn)差
std = np.std(value, ddof = 1)
print("灰度標(biāo)準(zhǔn)差", std)
其運(yùn)行結(jié)果如圖3所示,圖3(a)為原始圖像,圖3(b)為處理結(jié)果。其灰度平均值為123,灰度中值為129,灰度標(biāo)準(zhǔn)差為48.39。

下面講解另一種用來(lái)判斷圖像是白天還是黑夜的方法,其基本步驟如下:
(1)讀取原始圖像,轉(zhuǎn)換為灰度圖,并獲取圖像的所有像素值;
(2)設(shè)置灰度閾值并計(jì)算該閾值以下的像素個(gè)數(shù)。比如像素的閾值設(shè)置為50,統(tǒng)計(jì)低于50的像素值個(gè)數(shù);
(3)設(shè)置比例參數(shù),對(duì)比該參數(shù)與低于該閾值的像素占比,如果低于參數(shù)則預(yù)測(cè)為白天,高于參數(shù)則預(yù)測(cè)為黑夜。比如該參數(shù)設(shè)置為0.8,像素的灰度值低于閾值50的個(gè)數(shù)占整幅圖像所有像素個(gè)數(shù)的90%,則認(rèn)為該圖像偏暗,故預(yù)測(cè)為黑夜;否則預(yù)測(cè)為白天。
具體實(shí)現(xiàn)的代碼如下所示。
# -*- coding: utf-8 -*-
# By:Eastmount
import cv2
import numpy as np
import matplotlib.pyplot as plt
#函數(shù): 判斷黑夜或白天
def func_judge(img):
#獲取圖像高度和寬度
height = grayImage.shape[0]
width = grayImage.shape[1]
piexs_sum = height * width
dark_sum = 0 #偏暗像素個(gè)數(shù)
dark_prop = 0 #偏暗像素所占比例
for i in range(height):
for j in range(width):
if img[i, j] < 50: #閾值為50
dark_sum += 1
#計(jì)算比例
print(dark_sum)
print(piexs_sum)
dark_prop = dark_sum * 1.0 / piexs_sum
if dark_prop >=0.8:
print("This picture is dark!", dark_prop)
else:
print("This picture is bright!", dark_prop)
#讀取圖像
img = cv2.imread('day.png')
#轉(zhuǎn)換為RGB圖像
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
#圖像灰度轉(zhuǎn)換
grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#計(jì)算256灰度級(jí)的圖像直方圖
hist = cv2.calcHist([grayImage], [0], None, [256], [0,255])
#判斷黑夜或白天
func_judge(grayImage)
#顯示原始圖像和繪制的直方圖
plt.subplot(121), plt.imshow(img_rgb, 'gray'), plt.axis('off'), plt.title("(a)")
plt.subplot(122), plt.plot(hist, color='r'), plt.xlabel("x"), plt.ylabel("y"), plt.title("(b)")
plt.show()
第一張測(cè)試圖輸出的結(jié)果如圖4所示,其中圖4(a)為原始圖像,圖4(b)為對(duì)應(yīng)直方圖曲線(xiàn)。

最終輸出結(jié)果為“(‘This picture is bright!’, 0.010082704388303882)”,該預(yù)測(cè)為白天。

第二張測(cè)試圖輸出的結(jié)果如圖6所示,其中圖6(a)為原始圖像,圖6(b)為對(duì)應(yīng)直方圖曲線(xiàn)。

最終輸出結(jié)果為“(‘This picture is dark!’, 0.8511824175824175)”,該預(yù)測(cè)為黑夜。

四.總結(jié)
本章主要講解圖像直方圖相關(guān)知識(shí)點(diǎn),包括掩膜直方圖和HS直方圖,并通過(guò)直方圖判斷黑夜與白天,通過(guò)案例分享直方圖的實(shí)際應(yīng)用。希望對(duì)您有所幫助,后續(xù)將進(jìn)入圖像增強(qiáng)相關(guān)知識(shí)點(diǎn)。
以上就是Python圖像運(yùn)算之圖像掩膜直方圖和HS直方圖詳解的詳細(xì)內(nèi)容,更多關(guān)于Python直方圖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
OpenCV目標(biāo)檢測(cè)Meanshif和Camshift算法解析
這篇文章主要為大家介紹了OpenCV目標(biāo)檢測(cè)Meanshif和Camshift算法解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-04-04
編寫(xiě)自定義的Django模板加載器的簡(jiǎn)單示例
這篇文章主要介紹了編寫(xiě)自定義的Django模板加載器的簡(jiǎn)單示例,Django是各色人氣Python框架中最為著名的一個(gè),需要的朋友可以參考下2015-07-07
python讀寫(xiě)excel數(shù)據(jù)--pandas詳解
這篇文章主要為大家詳細(xì)介紹了python操作EXCEL讀數(shù)據(jù)、寫(xiě)數(shù)據(jù)的實(shí)例源碼,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09
給Python學(xué)習(xí)者的文件讀寫(xiě)指南(含基礎(chǔ)與進(jìn)階)
今天,貓貓跟大家一起,好好學(xué)習(xí)Python文件讀寫(xiě)的內(nèi)容,這部分內(nèi)容特別常用,掌握后對(duì)工作和實(shí)戰(zhàn)都大有益處,學(xué)習(xí)是循序漸進(jìn)的過(guò)程,欲速則不達(dá)2020-01-01
Python中將兩個(gè)或多個(gè)list合成一個(gè)list的方法小結(jié)
python中,list這種數(shù)據(jù)結(jié)構(gòu)很常用到,如果兩個(gè)或者多個(gè)list結(jié)構(gòu)相同,內(nèi)容類(lèi)型相同,我們通常會(huì)將兩個(gè)或者多個(gè)list合并成一個(gè),這樣我們?cè)傺h(huán)遍歷的時(shí)候就可以一次性處理掉了2019-05-05
python?opencv實(shí)現(xiàn)灰度圖和彩色圖的互相轉(zhuǎn)換
這篇文章主要給大家介紹了關(guān)于python?opencv實(shí)現(xiàn)灰度圖和彩色圖的互相轉(zhuǎn)換,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2022-01-01
Python Tornado框架輕松寫(xiě)一個(gè)Web應(yīng)用的全過(guò)程
Tornado全稱(chēng)Tornado Web Server,是一個(gè)用Python語(yǔ)言寫(xiě)成的Web服務(wù)器兼Web應(yīng)用框架,Tornado走的是少而精的方向,注重的是性能優(yōu)越,它最出名的是異步非阻塞的服務(wù)器方式,這篇文章主要給大家介紹了關(guān)于Python Tornado框架輕松寫(xiě)一個(gè)Web應(yīng)用的相關(guān)資料,需要的朋友可以參考下2021-08-08
解決TensorFlow訓(xùn)練內(nèi)存不斷增長(zhǎng),進(jìn)程被殺死問(wèn)題
今天小編就為大家分享一篇解決TensorFlow訓(xùn)練內(nèi)存不斷增長(zhǎng),進(jìn)程被殺死問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-02-02
了解一下python內(nèi)建模塊collections
這篇文章主要介紹了Python內(nèi)建模塊——collections的相關(guān)資料,幫助大家更好的理解和使用python,感興趣的朋友可以了解下2020-09-09

