摘要:本章主要講解影像直方圖相關知識點,包括掩膜直方圖和HS直方圖,并通過直方圖判斷黑夜與白天,通過案例分享直方圖的實際應用,
本文分享自華為云社區《[Python從零到壹] 五十二.影像增強及運算篇之影像掩膜直方圖和HS直方圖》,作者: eastmount,
一.影像掩膜直方圖
如果要統計影像的某一部分直方圖,就需要使用掩碼(蒙板)來進行計算,假設將要統計的部分設定為白色,其余部分設定為黑色,然后使用該掩膜進行直方圖繪制,其完整代碼如下所示,
# -*- coding: utf-8 -*- # By:Eastmount import cv2 import numpy as np import matplotlib.pyplot as plt import matplotlib #讀取影像 img = cv2.imread('luo.png') #轉換為RGB影像 img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #設定掩膜 mask = np.zeros(img.shape[:2], np.uint8) mask[100:300, 100:300] = 255 masked_img = cv2.bitwise_and(img, img, mask=mask) #影像直方圖計算 hist_full = cv2.calcHist([img], [0], None, [256], [0,256]) #通道[0]-灰度圖 #影像直方圖計算(含掩膜) hist_mask = cv2.calcHist([img], [0], mask, [256], [0,256]) plt.figure(figsize=(8, 6)) #設定字體 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)掩膜") #繪制掩膜設定后的影像 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)直方圖曲線") plt.xlabel("x") plt.ylabel("y") plt.show()
其運行結果如圖1所示,它使用了一個200×200像素的掩膜進行實驗,其中圖1(a)表示原始影像,圖1(b)表示200×200像素的掩膜,圖1?表示原始影像進行掩膜處理,圖1(d)表示直方圖曲線,藍色曲線為原始影像的灰度值直方圖分布情況,綠色波動更小的曲線為掩膜直方圖曲線,
二.影像HS直方圖
為了刻畫影像中顏色的直觀特性,常常需要分析影像的HSV空間下的直方圖特性,HSV空間是由色調(Hue)、飽和度(Saturation)、以及亮度(Value)構成,因此在進行直方圖計算時,需要先將源RGB影像轉化為HSV顏色空間影像,然后將對應的H和S通道進行單元劃分,再其二維空間上計算相對應直方圖,再計算直方圖空間上的最大值并歸一化繪制相應的直方圖資訊,從而形成色調-飽和度直方圖(或H-S直方圖),該直方圖通常應用在目標檢測、特征分析以及目標特征跟蹤等場景[1-2],
由于H和S分量與人感受顏色的方式是緊密相連,V分量與影像的彩色資訊無關,這些特點使得HSV模型非常適合于借助人的視覺系統來感知彩色特性的影像處理演算法,
下面的代碼是具體的實作代碼,使用matplotlib.pyplot庫中的imshow()函式來繪制具有不同顏色映射的2D直方圖,
# -*- coding: utf-8 -*- # By:Eastmount import cv2 import numpy as np import matplotlib.pyplot as plt #讀取影像 img = cv2.imread('luo.png') #轉換為RGB影像 img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #影像HSV轉換 hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV) #計算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)是原影像對應的彩色直方圖,其中X軸表示飽和度(S),Y軸表示色調(H),在直方圖中,可以看到H=140和S=130附近的一些高值,它對應于艷麗的色調,
三.直方圖判斷白天黑夜
接著講述一個應用直方圖的案例,通過直方圖來判斷一幅影像是黑夜或白天,常見的方法是通過計算影像的灰度平均值、灰度中值或灰度標準差,再與自定義的閾值進行對比,從而判斷是黑夜還是白天[3-4],
- 灰度平均值:該值等于影像中所有像素灰度值之和除以影像的像素個數,
- 灰度中值:對影像中所有像素灰度值進行排序,然后獲取所有像素最中間的值,即為灰度中值,
- 灰度標準差:又常稱均方差,是離均差平方的算術平均數的平方根,標準差能反映一個資料集的離散程度,是總體各單位標準值與其平均數離差平方的算術平均數的平方根,如果一幅圖看起來灰蒙蒙的, 那灰度標準差就小;如果一幅圖看起來很鮮艷,那對比度就很大,標準差也大,
下面的代碼是計算灰度“Lena”圖的灰度平均值、灰度中值和灰度標準差,
# -*- coding: utf-8 -*- # By:Eastmount import cv2 import numpy as np import matplotlib.pyplot as plt #函式: 獲取影像的灰度平均值 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 #函式: 獲取中位數 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') #影像灰度轉換 grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #獲取影像高度和寬度 height = grayImage.shape[0] width = grayImage.shape[1] #計算影像的灰度平均值 mean = fun_mean(grayImage, height, width) print("灰度平均值:", mean) #計算影像的灰度中位數 value = grayImage.ravel() #獲取所有像素值 median = fun_median(value) print("灰度中值:", median) #計算影像的灰度標準差 std = np.std(value, ddof = 1) print("灰度標準差", std)
其運行結果如圖3所示,圖3(a)為原始影像,圖3(b)為處理結果,其灰度平均值為123,灰度中值為129,灰度標準差為48.39,
下面講解另一種用來判斷影像是白天還是黑夜的方法,其基本步驟如下:
- (1)讀取原始影像,轉換為灰度圖,并獲取影像的所有像素值;
- (2)設定灰度閾值并計算該閾值以下的像素個數,比如像素的閾值設定為50,統計低于50的像素值個數;
- (3)設定比例引數,對比該引數與低于該閾值的像素占比,如果低于引數則預測為白天,高于引數則預測為黑夜,比如該引數設定為0.8,像素的灰度值低于閾值50的個數占整幅影像所有像素個數的90%,則認為該影像偏暗,故預測為黑夜;否則預測為白天,
具體實作的代碼如下所示,
# -*- coding: utf-8 -*- # By:Eastmount import cv2 import numpy as np import matplotlib.pyplot as plt #函式: 判斷黑夜或白天 def func_judge(img): #獲取影像高度和寬度 height = grayImage.shape[0] width = grayImage.shape[1] piexs_sum = height * width dark_sum = 0 #偏暗像素個數 dark_prop = 0 #偏暗像素所占比例 for i in range(height): for j in range(width): if img[i, j] < 50: #閾值為50 dark_sum += 1 #計算比例 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') #轉換為RGB影像 img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) #影像灰度轉換 grayImage = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) #計算256灰度級的影像直方圖 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()
第一張測驗圖輸出的結果如圖4所示,其中圖4(a)為原始影像,圖4(b)為對應直方圖曲線,
最終輸出結果為“(‘This picture is bright!’, 0.010082704388303882)”,該預測為白天,
第二張測驗圖輸出的結果如圖6所示,其中圖6(a)為原始影像,圖6(b)為對應直方圖曲線,
最終輸出結果為“(‘This picture is dark!’, 0.8511824175824175)”,該預測為黑夜,
四.總結
本章主要講解影像直方圖相關知識點,包括掩膜直方圖和HS直方圖,并通過直方圖判斷黑夜與白天,通過案例分享直方圖的實際應用,希望對您有所幫助,后續將進入影像增強相關知識點,
參考文獻:
- [1]岡薩雷斯. 數字影像處理(第3版)[M]. 北京:電子工業出版社, 2013.
- [2]張恒博, 歐宗瑛. 一種基于色彩和灰度直方圖的影像檢索方法[J]. 計算機工程, 2004.
- [3]Eastmount. [數字影像處理] 四.MFC對話框繪制灰度直方圖[EB/OL]. (2015-05-31). https://blog.csdn.net/eastmount/article/details/46237463.
- [4]ZJE_ANDY. python3+opencv 利用灰度直方圖來判斷圖片的亮暗情況[EB/OL]. (2018-06-20). https://blog.csdn.net/u014453898/article/details/80745987.
- [5]阮秋琦. 數字影像處理學(第3版)[M]. 北京:電子工業出版社, 2008.
- [6]Eastmount. [Python影像處理] 十一.灰度直方圖概念及OpenCV繪制直方圖[EB/OL]. (2018-11-06). https://blog.csdn.net/Eastmount/article/details/83758402.
點擊關注,第一時間了解華為云新鮮技術~
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/542679.html
標籤:Python
上一篇:PEG parser——為什么python不再使用LL(1)
下一篇:爬蟲學習1——request使用
