youcans 的 OpenCV 学习课—6.灰度变换与直方图处理
youcans 的 OpenCV 學(xué)習(xí)課—6.灰度變換與直方圖處理
本系列面向 Python 小白,從零開始實(shí)戰(zhàn)解說 OpenCV 項目實(shí)戰(zhàn)。
空間域的圖像處理方法直接對圖像的像素點(diǎn)進(jìn)行處理,空間域圖像處理技術(shù)主要是灰度變換和空間濾波。
本節(jié)介紹圖像的灰度變化與直方圖處理,提供完整例程和運(yùn)行結(jié)果:二值處理,反色變換,線性變換,分段線性變換,對比度拉伸,灰度級分層,非線性變換,直方圖處理,直方圖均衡化,直方圖匹配,局部直方圖處理,統(tǒng)計量增強(qiáng),反向投影。
歡迎關(guān)注 『youcans 的 OpenCV 學(xué)習(xí)課』 系列,持續(xù)更新
文章目錄
- youcans 的 OpenCV 學(xué)習(xí)課—6.灰度變換與直方圖處理
- 1. 圖像增強(qiáng)技術(shù)
- 2. 圖像的灰度化處理和二值化處理
- 例程:1.47 圖像的二值變換(固定閾值)
- 3. 圖像的灰度變換
- 3.1 反色變換(圖像反轉(zhuǎn))
- 例程:1.48 圖像的反色變換
- 3.2 線性灰度變換
- 例程:1.49 圖像的線性灰度變換
- 3.3 分段線性灰度變換
- 例程:1.50 分段線性灰度變換(對比度拉伸)
- 例程:1.53 分段線性灰度變換(灰度級分層)
- 例程:1.54 分段線性灰度變換(比特平面分層)
- 3.4 非線性灰度變換:對數(shù)變換和指數(shù)變換
- 例程:1.55 圖像的對數(shù)變換
- 3.5 非線性灰度變換:冪律變換(伽馬變換)
- 例程:1.56 圖像的冪律變換
- 4. 圖像的直方圖處理
- 4.1 灰度直方圖
- 例程:1.57 圖像的灰度直方圖
- 4.2 直方圖均衡化
- 例程:1.58 直方圖均衡
- 4.3 直方圖匹配
- 例程:1.59 灰度圖像直方圖匹配
- 例程:1.60 彩色圖像直方圖匹配
- 4.4 局部直方圖處理
- 基本例程:1.61 自適應(yīng)的局部直方圖均衡
- 4.5 直方圖統(tǒng)計量圖像增強(qiáng)
- 基本例程:1.63 直方圖統(tǒng)計量圖像增強(qiáng)
- 4.6 直方圖反向投影(反向追蹤)
- 基本例程:1.64 直方圖反向投影追蹤
1. 圖像增強(qiáng)技術(shù)
圖像增強(qiáng)(Image Enhancement)的方法主要有空間域變換、頻率域變換和偽彩色處理。
- 空間域變換:空間域是指圖像平面,空間域的圖像處理方法直接對圖像的像素點(diǎn)進(jìn)行處理。空間域圖像處理技術(shù)主要是灰度變換和空間濾波。
- 頻率域變換: 通過傅立葉變換,在頻率域進(jìn)行處理,然后再轉(zhuǎn)換回空間域。
- 偽彩色處理:把灰度圖像映射到彩色空間,常用于遙感圖像、醫(yī)學(xué)影像處理。
2. 圖像的灰度化處理和二值化處理
按照顏色對圖像進(jìn)行分類,可以分為二值圖像、灰度圖像和彩色圖像。
- 二值圖像:只有黑色和白色兩種顏色的圖像。每個像素點(diǎn)可以用 0/1 表示,0 表示黑色,1 表示白色。
- 灰度圖像:只有灰度的圖像。每個像素點(diǎn)用 8bit 數(shù)字 [0,255] 表示灰度,如:0 表示純黑,255 表示純白。
- 彩色圖像:彩色圖像通常采用紅色(R)、綠色(G)和藍(lán)色(B)三個色彩通道的組合表示。
OpenCV 中彩色圖像使用 BGR 格式。彩色圖像進(jìn)行灰度化處理,可以在讀取圖像文件時直接讀取為灰度圖像,也可以通過顏色空間轉(zhuǎn)換函數(shù) cv2.cvtColor 將彩色圖像轉(zhuǎn)換為灰度圖像。
灰度化處理相關(guān)函數(shù)和例程介紹,詳見 [OpenCV 學(xué)習(xí)課-2.圖像讀取與顯示]。
# 1.1 圖像的讀取imgFile = "../images/imgLena.tif" # 讀取文件的路徑img1 = cv2.imread(imgFile, flags=1) # flags=1 讀取彩色圖像(BGR)img2 = cv2.imread(imgFile, flags=0) # flags=0 讀取為灰度圖像# 1.10 圖像顯示(plt.imshow)imgRGB = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB) # 圖片格式轉(zhuǎn)換:BGR(OpenCV) -> RGB(PyQt5)imGray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # 圖片格式轉(zhuǎn)換:BGR(OpenCV) -> Gray進(jìn)一步地,通過函數(shù) cv2.threshold 可以對圖像進(jìn)行二值化處理。
函數(shù)說明:
cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dst函數(shù) threshold() 可以將灰度圖像轉(zhuǎn)換為二值圖像,圖像完全由像素 0 和 255 構(gòu)成,呈現(xiàn)出只有黑白兩色的視覺效果。
灰度閾值化通過選取的灰度閾值 thresh,將每個像素的灰度值與閾值進(jìn)行比較,將灰度大于閾值的像素點(diǎn)置為最大灰度,小于閾值的像素點(diǎn)置為最小灰度,得到二值圖像,可以突出圖像輪廓,把目標(biāo)從背景中分割出來。
參數(shù)說明:
- scr:變換操作的輸入圖像,nparray 二維數(shù)組,必須是單通道灰度圖像!
- thresh:閾值,取值范圍 0~255
- maxval:填充色,取值范圍 0~255,一般取 255
- type:變換類型
- cv2.THRESH_BINARY:大于閾值時置 255,否則置 0
- cv2.THRESH_BINARY_INV:大于閾值時置 0,否則置 255
- cv2.THRESH_TRUNC:大于閾值時置為閾值 thresh,否則不變(保持原色)
- cv2.THRESH_TOZERO:大于閾值時不變(保持原色),否則置 0
- cv2.THRESH_TOZERO_INV:大于閾值時置 0,否則不變(保持原色)
- cv2.THRESH_OTSU:使用 OTSU 算法選擇閾值
- 返回值 retval:返回二值化的閾值
- 返回值 dst:返回閾值變換的輸出圖像
注意:
- 函數(shù) cv2.threshold 進(jìn)行固定閾值的二值化處理;函數(shù) cv2.adaptiveThreshold 為自適應(yīng)閾值的二值化處理函數(shù),可以通過比較像素點(diǎn)與周圍像素點(diǎn)的關(guān)系動態(tài)調(diào)整閾值。
- 確切地說,只有 type 為 cv2.THRESH_BINARY 或 cv2.THRESH_BINARY_INV 時輸出為二值圖像,其它變換類型時進(jìn)行閾值處理但并不是二值處理。
例程:1.47 圖像的二值變換(固定閾值)
# 1.47 固定閾值二值變換img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)imgGray = cv2.imread("../images/imgLena.tif", flags=0) # flags=0 讀取為灰度圖像# imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顏色轉(zhuǎn)換:BGR(OpenCV) -> Gray# cv2.threshold(src, thresh, maxval, type[, dst]) → retval, dstret1, img1 = cv2.threshold(imgGray, 63, 255, cv2.THRESH_BINARY) # 轉(zhuǎn)換為二值圖像, thresh=63ret2, img2 = cv2.threshold(imgGray, 127, 255, cv2.THRESH_BINARY) # 轉(zhuǎn)換為二值圖像, thresh=127ret3, img3 = cv2.threshold(imgGray, 191, 255, cv2.THRESH_BINARY) # 轉(zhuǎn)換為二值圖像, thresh=191ret4, img4 = cv2.threshold(imgGray, 127, 255, cv2.THRESH_BINARY_INV) # 逆二值圖像,BINARY_INVret5, img5 = cv2.threshold(imgGray, 127, 255, cv2.THRESH_TRUNC) # TRUNC 閾值處理,THRESH_TRUNCret6, img6 = cv2.threshold(imgGray, 127, 255, cv2.THRESH_TOZERO) # TOZERO 閾值處理,THRESH_TOZEROplt.figure(figsize=(9, 6))titleList = ["1. BINARY(thresh=63)", "2. BINARY(thresh=127)", "3. BINARY(thresh=191)", "4. THRESH_BINARY_INV", "5. THRESH_TRUNC", "6. THRESH_TOZERO"]imageList = [img1, img2, img3, img4, img5, img6]for i in range(6):plt.subplot(2, 3, i+1), plt.title(titleList[i]), plt.axis('off')plt.imshow(imageList[i], 'gray') # 灰度圖像 ndim=2plt.show()3. 圖像的灰度變換
灰度變換是圖像增強(qiáng)的重要方法,可以使圖像動態(tài)范圍擴(kuò)大、圖像對比度增強(qiáng),圖像更清晰,特征更明顯,從而改善圖像的顯示效果。
灰度變換就是按一定規(guī)則(灰度映射函數(shù))修改圖像每一個像素的灰度值,從而改變圖像灰度的動態(tài)范圍。按照灰度映射函數(shù)的性質(zhì),灰度變換可以分為線性變換、分段線性和非線性變換,非線性變換中對數(shù)變換、指數(shù)變換和冪律變換(n次冪、n次根)最為常用。常見的灰度變換函數(shù)的形狀如下圖所示。
3.1 反色變換(圖像反轉(zhuǎn))
圖像的反色變換,即圖像反轉(zhuǎn),將黑色像素點(diǎn)變白色,白色像素點(diǎn)變黑色。廣義的反色變換也可以應(yīng)用于彩色圖像,即對所有像素點(diǎn)取補(bǔ)。
圖像的反轉(zhuǎn)處理可以增強(qiáng)暗色區(qū)域中的白色或灰色細(xì)節(jié)。
注意圖像反轉(zhuǎn)(Invert)與圖像翻轉(zhuǎn)(Flip)的區(qū)別:圖像翻轉(zhuǎn)是沿對稱軸的幾何變換,像素值不變;圖像反轉(zhuǎn)是像素顏色的逆轉(zhuǎn),像素位置不變。
例程:1.48 圖像的反色變換
# 1.48 圖像的反色變換img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顏色轉(zhuǎn)換:BGR(OpenCV) -> Grayh, w = img.shape[:2] # 圖片的高度和寬度# imgInv = np.zeros_like(img) # 創(chuàng)建與 img 相同形狀的黑色圖像imgInv = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組for i in range(h):for j in range(w):imgInv[i][j] = 255 - imgGray[i][j]plt.figure(figsize=(10,6))plt.subplot(131), plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)), plt.title("imgBGR"), plt.axis('off')plt.subplot(132), plt.imshow(imgGray, cmap='gray'), plt.title("imgGray"), plt.axis('off')plt.subplot(133), plt.imshow(imgInv, cmap='gray'), plt.title("imgInv"), plt.axis('off')plt.show()3.2 線性灰度變換
線性灰度變換將原始圖像灰度值的動態(tài)范圍按線性關(guān)系擴(kuò)展到指定范圍或整個動態(tài)范圍。
線性灰度變化對圖像的每一個像素作線性拉伸,可以凸顯圖像的細(xì)節(jié),提高圖像的對比度。
線性灰度變換可以由以下公式描述 :
KaTeX parse error: No such environment: align at position 8: \begin{?a?l?i?g?n?}? Dt &= \frac{d-…
式中,D 為原始圖像的灰度值,Dt 為線性灰度變換后的圖像灰度值。
- 當(dāng) α=1,β=0\alpha = 1,\beta = 0α=1,β=0 時,保持原始圖像不變
- 當(dāng) α=1,β>0\alpha = 1,\beta > 0α=1,β>0 時,圖像的灰度值上移,灰度圖像顏色發(fā)白(彩色圖像顏色發(fā)亮)
- 當(dāng) α=1,β<0\alpha = 1,\beta < 0α=1,β<0 時,圖像的灰度值下移,灰度圖像顏色發(fā)黑(彩色圖像顏色發(fā)暗)
- 當(dāng) α>1\alpha>1α>1 時,圖像的對比度增強(qiáng)
- 當(dāng) 0<α<10 < \alpha < 10<α<1 時,圖像的對比度減小
- 當(dāng) α<0,β=255\alpha < 0,\beta=255α<0,β=255 時,圖像暗區(qū)域變亮,亮區(qū)域變暗,圖像求補(bǔ)
- 當(dāng) α=?1,β=255\alpha = -1,\beta = 255α=?1,β=255 時,圖像的灰度值反轉(zhuǎn)
直方圖正規(guī)化是根據(jù)圖像的最小灰度級和最大灰度級,將其拉伸到灰度級全域 [0,255] 的線性變換。
例程:1.49 圖像的線性灰度變換
# 1.49 圖像的線性灰度變換img = cv2.imread("../images/imgLena.tif") # 讀取彩色圖像(BGR)imgGray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 顏色轉(zhuǎn)換:BGR(OpenCV) -> Grayh, w = img.shape[:2] # 圖片的高度和寬度img1 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組img2 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組img3 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組img4 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組img5 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組img6 = np.empty((w, h), np.uint8) # 創(chuàng)建空白數(shù)組# Dt[i,j] = alfa*D[i,j] + betaalfa1, beta1 = 1, 50 # alfa=1,beta>0: 灰度值上移alfa2, beta2 = 1, -50 # alfa=1,beta<0: 灰度值下移alfa3, beta3 = 1.5, 0 # alfa>1,beta=0: 對比度增強(qiáng)alfa4, beta4 = 0.75, 0 # 0<alfa<1,beta=0: 對比度減小alfa5, beta5 = -0.5, 0 # alfa<0,beta=0: 暗區(qū)域變亮,亮區(qū)域變暗alfa6, beta6 = -1, 255 # alfa=-1,beta=255: 灰度值反轉(zhuǎn)for i in range(h):for j in range(w):img1[i][j] = min(255, max((imgGray[i][j]+beta1), 0)) # alfa=1,beta>0: 顏色發(fā)白img2[i][j] = min(255, max((imgGray[i][j]+beta2), 0)) # alfa=1,beta<0: 顏色發(fā)黑img3[i][j] = min(255, max(alfa3*imgGray[i][j], 0)) # alfa>1,beta=0: 對比度增強(qiáng)img4[i][j] = min(255, max(alfa4*imgGray[i][j], 0)) # 0<alfa<1,beta=0: 對比度減小img5[i][j] = alfa5*imgGray[i][j]+beta5 # alfa<0,beta=255: 暗區(qū)域變亮,亮區(qū)域變暗img6[i][j] = min(255, max(alfa6*imgGray[i][j]+beta6, 0)) # alfa=-1,beta=255: 灰度值反轉(zhuǎn)plt.figure(figsize=(10, 6))titleList = ["1. imgGray", "2. beta=50", "3. beta=-50", "4. alfa=1.5", "5. alfa=0.75", "6. alfa=-0.5"]imageList = [imgGray, img1, img2, img3, img4, img5]for i in range(6):plt.subplot(2, 3, i + 1), plt.title(titleList[i]), plt.axis('off')plt.imshow(imageList[i], vmin=0, vmax=255, cmap='gray')plt.show()3.3 分段線性灰度變換
分段線性變換函數(shù)可以增強(qiáng)圖像各部分的反差,增強(qiáng)感興趣的灰度區(qū)間、抑制不感興趣的灰度級。
分段線性函數(shù)的優(yōu)點(diǎn)是可以根據(jù)需要拉伸特征物的灰度細(xì)節(jié),一些重要的變換只能用分段函數(shù)來描述和實(shí)現(xiàn),缺點(diǎn)則是參數(shù)較多不容易確定。
分段線性函數(shù)通用公式如下:
Dt={caD,0≤D<ad?cb?a[D?a]+c,a≤D≤bf?de?b[D?a]+d,b<D≤eDt = \begin{cases} \dfrac{c}{a} D &, 0 \leq D < a\\ \dfrac{d-c}{b-a}[D-a]+c &, a \leq D \leq b\\ \dfrac{f-d}{e-b}[D-a]+d &, b < D \leq e\\ \end{cases} Dt=????????????ac?Db?ad?c?[D?a]+ce?bf?d?[D?a]+d?,0≤D<a,a≤D≤b,b<D≤e?
式中,D 為原始圖像的灰度值,Dt 為線性灰度變換后的圖像灰度值。
例程:1.50 分段線性灰度變換(對比度拉伸)
對比度拉伸可以擴(kuò)展圖像中的灰度級范圍,從而覆蓋設(shè)備的理想灰度范圍。
對比度拉伸變換函數(shù)可以有不同的實(shí)現(xiàn)方案,如將原始灰度范圍拉伸到較寬的灰度范圍;或?qū)⒃蓟叶确秶斓饺蚧叶确秶?#xff08;0,255);或?qū)⒃蓟叶确秶斓捷^寬的灰度范圍,同時對下限或上限進(jìn)行截斷處理。
本例程令 (r1, s1) = (rMin, 0)、(r2, s2) = (rmax, L-1),其中 rMin、rMax 表示圖像中最小灰度值和最大灰度值,將原始圖像的灰度級分段線性拉伸到整個范圍 [0, L-1]。運(yùn)行結(jié)果的左圖顯示本例程的拉伸變換曲線。
# 1.50 分段線性灰度變換 (對比度拉伸)imgGray = cv2.imread("../images/Fig0310b.tif", flags=0) # flags=0 讀取為灰度圖像height, width = imgGray.shape[:2] # 圖片的高度和寬度# constrast stretch, (r1,s1)=(rMin,0), (r2,s2)=(rMax,255)rMin = imgGray.min() # 原始圖像灰度的最小值rMax = imgGray.max() # 原始圖像灰度的最大值r1, s1 = rMin, 0 # (x1,y1)r2, s2 = rMax, 255 # (x2,y2)imgStretch = np.empty((width, height), np.uint8) # 創(chuàng)建空白數(shù)組k1 = s1 / r1 # imgGray[h,w] < r1:k2 = (s2-s1) / (r2-r1) # r1 <= imgGray[h,w] <= r2k3 = (255-s2) / (255-r2) # imgGray[h,w] > r2for h in range(height):for w in range(width):if imgGray[h,w] < r1:imgStretch[h,w] = k1 * imgGray[h,w]elif r1 <= imgGray[h,w] <= r2:imgStretch[h,w] = k2 * (imgGray[h,w] - r1) + s1elif imgGray[h,w] > r2:imgStretch[h,w] = k3 * (imgGray[h,w] - r2) + s2plt.figure(figsize=(10,3.5))plt.subplots_adjust(left=0.2, bottom=0.2, right=0.9, top=0.8, wspace=0.1, hspace=0.1)plt.subplot(131), plt.title("s=T(r)")x = [0, 96, 182, 255]y = [0, 30, 220, 255]plt.plot(x, y)plt.axis([0,256,0,256])plt.text(105, 25, "(r1,s1)", fontsize=10)plt.text(120, 215, "(r2,s2)", fontsize=10)plt.xlabel("r, Input value")plt.ylabel("s, Output value")plt.subplot(132), plt.imshow(imgGray, cmap='gray', vmin=0, vmax=255), plt.title("Original"), plt.axis('off')plt.subplot(133), plt.imshow(imgStretch, cmap='gray', vmin=0, vmax=255), plt.title("Stretch"), plt.axis('off')plt.show()例程:1.53 分段線性灰度變換(灰度級分層)
灰度級分層可以突出圖像中特定的灰度級區(qū)間,可以對灰度級進(jìn)行分層處理。
灰度級分層有兩種常用方案:一種方案是二值處理,將感興趣的灰度級區(qū)間設(shè)為較大的灰度值,其它區(qū)間設(shè)為較小的灰度值;另一種方案是窗口處理,將感興趣的灰度級區(qū)間設(shè)為較大的灰度值,其它區(qū)間不變。
兩種灰度級分層方案的分段變換公式分別為:
Dt1={d,a≤D≤bc,elseDt2={d,a≤D≤bD,elseDt_1 = \begin{cases} d &, a \leq D \leq b\\ c &, else \end{cases} \\ Dt_2 = \begin{cases} d &, a \leq D \leq b\\ D &, else \end{cases} Dt1?={dc?,a≤D≤b,else?Dt2?={dD?,a≤D≤b,else?
式中,D 為原始圖像的灰度值,Dt1、Dt2 為灰度變換后的圖像灰度值。
例程 1.53 對于腎部區(qū)域主動脈血管造影圖像,采用灰度級分層技術(shù)增強(qiáng)主要血管,將感興趣的灰度級區(qū)間顯示為白色。方案一進(jìn)行二值化處理,將其它灰度區(qū)間設(shè)為黑色;方案二則保留其它灰度區(qū)間的灰度值不變。
# # 1.53 分段線性灰度變換 (灰度級分層) # Gray layeredimgGray = cv2.imread("../images/Fig0312a.tif", flags=0) # flags=0 讀取為灰度圖像width, height = imgGray.shape[:2] # 圖片的高度和寬度# Gray layered strategy 1: binary imagea, b = 155, 245 # 突出 [a, b] 區(qū)間的灰度imgLayer1 = imgGray.copy()imgLayer1[(imgLayer1[:,:]<a) | (imgLayer1[:,:]>b)] = 0 # 其它區(qū)域:黑色imgLayer1[(imgLayer1[:,:]>=a) & (imgLayer1[:,:]<=b)] = 255 # 灰度級窗口:白色# Gray layered strategy 2: grayscale imageimgLayer2 = imgGray.copy()imgLayer2[(imgLayer2[:,:]>=a) & (imgLayer2[:,:]<=b)] = 255 # 灰度級窗口:白色,其它區(qū)域不變plt.figure(figsize=(10, 6))plt.subplot(131), plt.imshow(imgGray, cmap='gray'), plt.title('Original'), plt.axis('off')plt.subplot(132), plt.imshow(imgLayer1, cmap='gray'), plt.title('Binary layered'), plt.axis('off')plt.subplot(133), plt.imshow(imgLayer2, cmap='gray'), plt.title('Grayscale layered'), plt.axis('off')plt.show()例程:1.54 分段線性灰度變換(比特平面分層)
像素值也可以表示為二進(jìn)制形式,對 8bits 二進(jìn)制數(shù)的每一位進(jìn)行切片,可以得到 8 個比特平面,稱為比特平面分層(Bit-plane slicing)。
通常,高階比特平面包含了大量有視覺意義的數(shù)據(jù),而低階比特平面包含了更精細(xì)的灰度細(xì)節(jié)。因此,比特平面分層可以用于圖像壓縮和圖像重建。
3.4 非線性灰度變換:對數(shù)變換和指數(shù)變換
對數(shù)變換可以由以下公式描述:
Dt=c?log(1+D)Dt = c * log(1+D) Dt=c?log(1+D)
對數(shù)曲線在像素值較低的區(qū)域斜率大,在像素值較高的區(qū)域斜率小。對數(shù)變換將輸入中范圍較窄的低灰度值映射為范圍較寬的灰度級,輸入中的高灰度值則被映射為范圍較窄的灰度級。對數(shù)變換后,較暗區(qū)域的對比度提升,可以增強(qiáng)圖像的暗部細(xì)節(jié)。
對數(shù)變換實(shí)現(xiàn)了擴(kuò)展低灰度值而壓縮高灰度值的效果,廣泛應(yīng)用于頻譜圖像的顯示中。對數(shù)變換的典型應(yīng)用是傅立葉頻譜的動態(tài)范圍很寬,直接顯示時受顯示設(shè)備動態(tài)范圍的限制而丟失大量的暗部細(xì)節(jié);使用對數(shù)變換將圖像的動態(tài)范圍進(jìn)行非線性壓縮后,就可以清晰地顯示。
例程:1.55 圖像的對數(shù)變換
# 1.55 圖像的非線性灰度變換:對數(shù)變換img = cv2.imread("../images/Fig0305a.tif", flags=0) # flags=0 讀取為灰度圖像normImg = lambda x: 255. * (x-x.min()) / (x.max()-x.min()+1e-6) # 歸一化fft = np.fft.fft2(img) # 傅里葉變換fft_shift = np.fft.fftshift(fft) # 中心化amp = np.abs(fft_shift) # 傅里葉變換的頻譜amp = np.uint8(normImg(amp)) # 映射到 [0, 255]ampLog = np.abs(np.log(1 + np.abs(fft_shift))) # 對數(shù)變換ampLog = np.uint8(normImg(ampLog)) # 映射到 [0, 255]plt.figure(figsize=(9, 5))plt.subplot(131), plt.imshow(img, cmap='gray', vmin=0, vmax=255), plt.title('Original'), plt.axis('off')plt.subplot(132), plt.imshow(amp, cmap='gray', vmin=0, vmax=255), plt.title("FFT spectrum"), plt.axis('off')plt.subplot(133), plt.imshow(ampLog, cmap='gray', vmin=0, vmax=255), plt.title("FFT spectrum - log trans"), plt.axis('off')plt.tight_layout()plt.show()3.5 非線性灰度變換:冪律變換(伽馬變換)
冪律變換也稱伽馬變換,可以提升暗部細(xì)節(jié),對發(fā)白(曝光過度)或過暗(曝光不足)的圖片進(jìn)行矯正。
冪律變換可以由以下公式描述:
Dt=c?(D+?)γDt = c * (D+\epsilon)^{\gamma} Dt=c?(D+?)γ
伽馬變換本質(zhì)上是對圖像矩陣中的每個值進(jìn)行冪運(yùn)算。$ 0< \gamma <1$ 時,拉伸圖像中灰度級較低的區(qū)域,壓縮灰度級較高的部分,增加圖像的對比度;γ>1\gamma >1γ>1 時,拉伸圖像中灰度級較高的區(qū)域,壓縮灰度級較低的部分,降低圖像的對比度。
伽馬變換通過非線性變換對人類視覺特性進(jìn)行補(bǔ)償,最大化地利用有效的灰度級帶寬。很多拍攝、顯示、打印設(shè)備的亮度曲線都符合冪律曲線,因此伽馬變換廣泛應(yīng)用于各種設(shè)備顯示效果的調(diào)校,稱為伽馬校正。
例程:1.56 圖像的冪律變換
# 1.56 圖像的非線性灰度變換: 冪律變換 (伽馬變換)img = cv2.imread("../images/imgB2.jpg", flags=0) # flags=0 讀取為灰度圖像gammaList = [0.125, 0.25, 0.5, 1.0, 2.0, 4.0] # gamma 值normImg = lambda x: 255. * (x-x.min()) / (x.max()-x.min()+1e-6) # 歸一化為 [0,255]plt.figure(figsize=(9,6))for k in range(len(gammaList)):imgGamma = np.power(img, gammaList[k])imgGamma = np.uint8(normImg(imgGamma))plt.subplot(2, 3, k+1), plt.axis('off')plt.imshow(imgGamma, cmap='gray', vmin=0, vmax=255)plt.title(f"$\gamma={gammaList[k]}$")plt.show()4. 圖像的直方圖處理
4.1 灰度直方圖
圖像直方圖是反映圖像像素分布的統(tǒng)計表,橫坐標(biāo)代表像素值的取值區(qū)間,縱坐標(biāo)代表每一像素值在圖像中的像素總數(shù)或者所占的百分比。 灰度直方圖是圖像灰度級的函數(shù),用來描述每個灰度級在圖像矩陣中的像素個數(shù)。
灰度直方圖反映了圖像中的灰度分布規(guī)律,直觀地表現(xiàn)了圖像中各灰度級的占比,很好地體現(xiàn)出圖像的亮度和對比度信息:灰度圖分布居中說明亮度正常,偏左說明亮度較暗,偏右表明亮度較高;狹窄陡峭表明對比度降低,寬泛平緩表明對比度較高。
根據(jù)直方圖的形態(tài)可以判斷圖像的質(zhì)量,通過調(diào)控直方圖的形態(tài)可以改善圖像的質(zhì)量。
OpenCV 提供了函數(shù) cv2.calcHist 可以計算直方圖,Numpy 中的函數(shù) np.bincount 也可以實(shí)現(xiàn)同樣的功能。
函數(shù)說明:
cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) → hist函數(shù) cv2.calcHist 可以計算一維直方圖或二維直方圖,函數(shù)的參數(shù) images, channels, histSize, ranges 在計算一維直方圖時也要帶 [] 號。
參數(shù)說明:
- images:輸入圖像,用 [] 括號表示
- channels: 直方圖計算的通道,用 [] 括號表示
- mask:掩模圖像,一般置為 None
- histSize:直方柱的數(shù)量,一般取 256
- ranges:像素值的取值范圍,一般為 [0,256]
- 返回值 hist:返回每一像素值在圖像中的像素總數(shù),形狀為 (histSize,1)
注意:
- 參數(shù) images, channels, histSize, ranges 都要帶 [] 號。
- mask 是與 images 大小相同的掩模圖像,掩模為 0 的區(qū)域不作處理。不使用掩模時設(shè)為 None。
3. channels 設(shè)置對彩色圖像的指定通道計算直方圖,灰度圖像時設(shè)為 0。
4. Numpy 中的函數(shù) np.bincount 也可以實(shí)現(xiàn)同樣的功能,但該函數(shù)返回值的形狀為 (histSize,)
例程:1.57 圖像的灰度直方圖
# 1.57 圖像的灰度直方圖img = cv2.imread("../images/imgLena.tif", flags=0) # flags=0 讀取為灰度圖像histCV = cv2.calcHist([img], [0], None, [256], [0, 256]) # OpenCV 函數(shù) cv2.calcHisthistNP, bins = np.histogram(img.flatten(), 256)print(histCV.shape, histNP.shape) # histCV: (256, 1), histNP: (256,)plt.figure(figsize=(10,3))plt.subplot(131), plt.imshow(img, cmap='gray', vmin=0, vmax=255), plt.title("Original"), plt.axis('off')plt.subplot(132,xticks=[], yticks=[]), plt.axis([0,255,0,np.max(histCV)])plt.bar(range(256), histCV[:,0]), plt.title("Gray Hist(cv2.calcHist)")plt.subplot(133,xticks=[], yticks=[]), plt.axis([0,255,0,np.max(histCV)])plt.bar(bins[:-1], histNP), plt.title("Gray Hist(np.histogram)")plt.show()4.2 直方圖均衡化
直方圖均衡化是一種簡單有效的圖像增強(qiáng)技術(shù)。根據(jù)直方圖的形態(tài)可以判斷圖像的質(zhì)量,通過調(diào)控直方圖的形態(tài)可以改善圖像的質(zhì)量。
直方圖均衡化是將原始圖像通過函數(shù)變換,調(diào)控圖像的灰度分布,得到直方圖分布合理的新圖像,以此來調(diào)節(jié)圖像亮度、增強(qiáng)動態(tài)范圍偏小的圖像的對比度。
由于人眼視覺特性,直方圖均勻分布的圖像視覺效果較好。直方圖均衡化的基本思想是對圖像中占比大的灰度級進(jìn)行展寬,而對占比小的灰度級進(jìn)行壓縮,使圖像的直方圖分布較為均勻,擴(kuò)大灰度值差別的動態(tài)范圍,從而增強(qiáng)圖像整體的對比度。
因此,直方圖均衡化就是對圖像進(jìn)行非線性拉伸,重新分配圖像像素值,本質(zhì)上是根據(jù)直方圖對圖像進(jìn)行線性或非線性灰度變換。
例如,直方圖均衡化可以把原始圖像的直方圖調(diào)整到均勻分布,增加像素之間灰度值差別的動態(tài)范圍,從而增強(qiáng)圖像整體的對比度。
通過累積分布函數(shù)(cumulative distribution function, CDF)可以實(shí)現(xiàn)將原圖像 r 的分布轉(zhuǎn)換成 s 的均勻分布,累計分布函數(shù)(CDF)就是是概率密度函數(shù)(probability density function, PDF)的積分。
若 pr(r)p_r(r)pr?(r) 和 $p_s(s) $表示原圖像 r 和新圖像 s 的概率密度函數(shù),則:
s=T(r)=(L?1)∫0rpr(r)drs=T(r)= (L-1) \int _0 ^r p_r(r) dr s=T(r)=(L?1)∫0r?pr?(r)dr
其離散形式為:
sk=T(rk)=(L?1)∑j=0kpr(rj)=(L?1)∑j=0knjNs_k = T(r_k) = (L-1) \sum_{j=0}^k p_r(r_j) = (L-1) \sum_{j=0}^k \frac{n_j}{N} sk?=T(rk?)=(L?1)j=0∑k?pr?(rj?)=(L?1)j=0∑k?Nnj??
于是,可以通過原圖像的直方圖直接求出均衡化后各像素的灰度級 sks_ksk?,得到實(shí)現(xiàn)直方圖均衡的轉(zhuǎn)換函數(shù):
(1)計算原始灰度圖像的直方圖;
(2)通過直方圖累加計算原始圖像的累計分布函數(shù) CDF;
(3)基于累計分布函數(shù) CDF,通過插值計算得到新的灰度值。
OpenCV 提供了函數(shù) cv2. equalizeHist 可以實(shí)現(xiàn)直方圖均衡化。
函數(shù)說明:
cv2.qualizeHist(src[, dst]) → dst參數(shù)說明:
- src:輸入圖像
- 返回值 dst:輸出圖像,直方圖均衡化
例程:1.58 直方圖均衡
# 1.58 直方圖均衡img = cv2.imread("../images/Fig0310b.tif", flags=0) # flags=0 讀取為灰度圖像imgEqu = cv2.equalizeHist(img) # 使用 cv2.qualizeHist 完成直方圖均衡化變換# histogram equalization image# histImg, bins = np.histogram(img.flatten(), 256) # 計算原始圖像直方圖# cdf = histImg.cumsum() # 計算累積分布函數(shù) CDF# cdf = cdf * 255 / cdf[-1] # 累計函數(shù) CDF 歸一化: [0,1]->[0,255]# imgEqu = np.interp(img.flatten(), bins[:256], cdf) # 線性插值,計算新的灰度值# imgEqu = imgEqu.reshape(img.shape) # 將壓平的圖像數(shù)組重新變成二維數(shù)組fig = plt.figure(figsize=(7,7))plt.subplot(221), plt.title("Original image (youcans)"), plt.axis('off')plt.imshow(img, cmap='gray', vmin=0, vmax=255) # 原始圖像plt.subplot(222),plt.title("Hist-equalized image"), plt.axis('off')plt.imshow(imgEqu, cmap='gray', vmin=0, vmax=255) # 轉(zhuǎn)換圖像histImg, bins = np.histogram(img.flatten(), 256) # 計算原始圖像直方圖plt.subplot(223, yticks=[]), plt.bar(bins[:-1], histImg) # 原始圖像直方圖plt.title("Histogram of original image"), plt.axis([0,255,0,np.max(histImg)])histEqu, bins = np.histogram(imgEqu.flatten(), 256) # 計算原始圖像直方圖plt.subplot(224, yticks=[]), plt.bar(bins[:-1], histEqu) # 轉(zhuǎn)換圖像直方圖plt.title("Histogram of equalized image"), plt.axis([0,255,0,np.max(histImg)])plt.show()4.3 直方圖匹配
直方圖均衡直接對圖像全局進(jìn)行均衡化,生成具有均勻直方圖的圖像,并不考慮局部圖像區(qū)域的具體情況。對于一幅圖像的局部區(qū)域、具體缺陷,有時需要生成具有特殊形狀直方圖的圖像。
直方圖匹配又稱為直方圖規(guī)定化,是指將圖像的直方圖調(diào)整為規(guī)定的形狀。 例如,將一幅圖像或某一區(qū)域的直方圖匹配到另一幅影像上,使兩幅影像的色調(diào)保持一致。
這就需要在直方圖均衡的基礎(chǔ)上,再進(jìn)行一次反變換,將均勻形狀的直方圖調(diào)整為規(guī)定的形狀。
直方圖匹配的主要步驟為:
(1)通過規(guī)定圖像 z 的直方圖 pz(z)p_z(z)pz?(z),計算其直方圖均衡變換的 sks_ksk?;
(2)通過 sks_ksk? 計算圖像 z 的直方圖均衡變換函數(shù) GGG,G(zq)=skG(z_q)=s_kG(zq?)=sk?;
(3)計算變換函數(shù) GGG 的逆變換函數(shù) G?1G^{-1}G?1,zq=G?1(sk)z_q=G^{-1}(s_k)zq?=G?1(sk?);
(4)對輸入圖像 r 進(jìn)行直方圖均衡得到均衡圖像 s,然后再用逆變換函數(shù) G?1G^{-1}G?1 將其映射到 pz(z)p_z(z)pz?(z),得到直方圖匹配圖像 z。本步驟中的兩次變換,也可以合并為一次完成。
例程:1.59 灰度圖像直方圖匹配
# 1.59 灰度圖像直方圖匹配img = cv2.imread("../images/imgGaia.tif", flags=0) # flags=0 讀取為灰度圖像imgRef = cv2.imread("../images/Fig0307a.tif", flags=0) # 匹配模板圖像, matching template# imgOut = calcHistMatch(img, imgRef) # 子程序:直方圖匹配# 計算累計直方圖histImg, bins = np.histogram(img.flatten(), 256) # 計算原始圖像直方圖histRef, bins = np.histogram(imgRef.flatten(), 256) # 計算匹配模板直方圖cdfImg = histImg.cumsum() # 計算原始圖像累積分布函數(shù) CDFcdfRef = histRef.cumsum() # 計算匹配模板累積分布函數(shù) CDF# 計算直方圖匹配轉(zhuǎn)換函數(shù)transM = np.zeros(256)for i in range(256):index = 0vMin = np.fabs(cdfImg[i] - cdfRef[0])for j in range(256):diff = np.fabs(cdfImg[i] - cdfRef[j])if (diff < vMin):index = int(j)vMin = difftransM[i] = index# 直方圖匹配# imgOut = np.zeros_like(img)imgOut = transM[img].astype(np.uint8)fig = plt.figure(figsize=(10,7))plt.subplot(231), plt.title("Original image"), plt.axis('off')plt.imshow(img, cmap='gray') # 原始圖像plt.subplot(232), plt.title("Matching template"), plt.axis('off')plt.imshow(imgRef, cmap='gray') # 匹配模板plt.subplot(233), plt.title("Matching output"), plt.axis('off')plt.imshow(imgOut, cmap='gray') # 匹配結(jié)果histImg, bins = np.histogram(img.flatten(), 256) # 計算原始圖像直方圖plt.subplot(234, yticks=[]), plt.bar(bins[:-1], histImg)histRef, bins = np.histogram(imgRef.flatten(), 256) # 計算匹配模板直方圖plt.subplot(235, yticks=[]), plt.bar(bins[:-1], histRef)histOut, bins = np.histogram(imgOut.flatten(), 256) # 計算匹配結(jié)果直方圖plt.subplot(236, yticks=[]), plt.bar(bins[:-1], histOut)plt.show()例程:1.60 彩色圖像直方圖匹配
# 1.60 彩色圖像的直方圖匹配img = cv2.imread("../images/imgGaia.tif", flags=1) # flags=1 讀取為彩色圖像imgRef = cv2.imread("../images/imgLena.tif", flags=1) # 匹配模板圖像 (matching template)_, _, channel = img.shapeimgOut = np.zeros_like(img)for i in range(channel):print(i)histImg, _ = np.histogram(img[:,:,i], 256) # 計算原始圖像直方圖histRef, _ = np.histogram(imgRef[:,:,i], 256) # 計算匹配模板直方圖cdfImg = np.cumsum(histImg) # 計算原始圖像累積分布函數(shù) CDFcdfRef = np.cumsum(histRef) # 計算匹配模板累積分布函數(shù) CDFfor j in range(256):tmp = abs(cdfImg[j] - cdfRef)tmp = tmp.tolist()index = tmp.index(min(tmp)) # find the smallest number in tmp, get the index of this numberimgOut[:,:,i][img[:,:,i]==j] = indexfig = plt.figure(figsize=(10,7))plt.subplot(231), plt.title("Original image"), plt.axis('off')plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 顯示原始圖像plt.subplot(232), plt.title("Matching template"), plt.axis('off')plt.imshow(cv2.cvtColor(imgRef, cv2.COLOR_BGR2RGB)) # 顯示匹配模板plt.subplot(233), plt.title("Matching output"), plt.axis('off')plt.imshow(cv2.cvtColor(imgOut, cv2.COLOR_BGR2RGB)) # 顯示匹配結(jié)果histImg, bins = np.histogram(img.flatten(), 256) # 計算原始圖像直方圖plt.subplot(234, yticks=[]), plt.bar(bins[:-1], histImg)histRef, bins = np.histogram(imgRef.flatten(), 256) # 計算匹配模板直方圖plt.subplot(235, yticks=[]), plt.bar(bins[:-1], histRef)histOut, bins = np.histogram(imgOut.flatten(), 256) # 計算匹配結(jié)果直方圖plt.subplot(236, yticks=[]), plt.bar(bins[:-1], histOut)plt.show()4.4 局部直方圖處理
直方圖均衡和直方圖匹配都是基于整幅圖像的灰度分布進(jìn)行全局變換,并非針對圖像局部區(qū)域的細(xì)節(jié)進(jìn)行增強(qiáng)。
直方圖處理對于局部同樣適用,局部直方圖處理的思想是基于像素鄰域的灰度分布進(jìn)行直方圖變換處理。
局部直方圖處理的過程是:
(1)設(shè)定某一大小的模板(矩形鄰域),在圖像中沿逐個像素移動;
(2)對每個像素位置,計算模板區(qū)域的直方圖,對該局部區(qū)域進(jìn)行直方圖均衡或直方圖匹配變換,變換結(jié)果只用于模板區(qū)域中心像素點(diǎn)的灰度值修正;
(3)模板(鄰域)在圖像中逐行逐列移動,遍歷所有像素點(diǎn),完成對整幅圖像的局部直方圖處理。
OpenCV 提供了類 cv2. createCLAHE 用于創(chuàng)建自適應(yīng)均衡化的對象和方法,可以實(shí)現(xiàn)局部直方圖處理。
函數(shù)說明:
cv2.createCLAHE([, clipLimit[, tileGridSize]]) → retval參數(shù)說明:
- clipLimit:顏色對比度的閾值,可選項,默認(rèn)值 8
- titleGridSize:局部直方圖均衡化的模板(鄰域)大小,可選項,默認(rèn)值 (8,8)
cv2. createCLAHE 是一種限制對比度自適應(yīng)直方圖均衡化方法(Contrast Limited Adaptive Hitogram Equalization),采用了限制直方圖分布的方法和加速的插值方法。
基本例程:1.61 自適應(yīng)的局部直方圖均衡
# 1.61 局部直方圖均衡化img = cv2.imread("../images/FigClahe.jpg", flags=0) # flags=0 讀取為灰度圖像imgEqu = cv2.equalizeHist(img) # 全局直方圖均衡化clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(4,4)) # 創(chuàng)建 CLAHE 對象imgLocalEqu = clahe.apply(img) # 自適應(yīng)的局部直方圖均衡化plt.figure(figsize=(9, 6))plt.subplot(131), plt.title('Original'), plt.axis('off')plt.imshow(img, cmap='gray', vmin=0, vmax=255)plt.subplot(132), plt.title(f'Global Equalize Hist'), plt.axis('off')plt.imshow(imgEqu, cmap='gray', vmin=0, vmax=255)plt.subplot(133), plt.title(f'Local Equalize Hist'), plt.axis('off')plt.imshow(imgLocalEqu, cmap='gray', vmin=0, vmax=255)plt.tight_layout()plt.show()4.5 直方圖統(tǒng)計量圖像增強(qiáng)
直方圖統(tǒng)計量圖像增強(qiáng),是基于直方圖的統(tǒng)計量信息(如均值和方差)對圖像的灰度和對比度進(jìn)行調(diào)整。直方圖統(tǒng)計量不僅用于圖像的全局增強(qiáng),在圖像局部增強(qiáng)中更加有效。
局部均值和方差是根據(jù)像素鄰域特征進(jìn)行灰度調(diào)整的基礎(chǔ)。像素鄰域的局部均值是平均灰度的測度,局部方差是對比度的測度。使用局部均值和方差可以開發(fā)出簡單而強(qiáng)大的圖像局部增強(qiáng)算法。
以下基于 Rafael C. Gonzalez “Digital Image Processing (4th.Ed.)” 中的方法和案例進(jìn)行介紹。
增強(qiáng)后的圖像 g(x,y) 與原始圖像 f(x,y) 的修正公式為:
g(x,y)={C?f(x,y),(k0mG<m(Sxy)<k1mG)and(k2σG<σ(Sxy)<k3σG)f(x,y),C=max(rGlobal)/max(rROI)g(x,y)= \begin{cases} C*f(x,y) ,(k_0 m_G < m(S_{xy}) <k_1 m_G) and (k_2 \sigma_G < \sigma(S_{xy}) <k_3 \sigma_G)\\ f(x,y) , \end{cases}\\ C = max(r_{Global})/max(r_{ROI}) g(x,y)={C?f(x,y),(k0?mG?<m(Sxy?)<k1?mG?)and(k2?σG?<σ(Sxy?)<k3?σG?)f(x,y),?C=max(rGlobal?)/max(rROI?)
如果待增強(qiáng)區(qū)域相對平均灰度更暗,可以選擇 k0=0,k1=0.1k_0 = 0, k_1 = 0.1k0?=0,k1?=0.1;如果待增強(qiáng)區(qū)域的對比度很低,可以選擇 k2=0,k3=0.1k_2 = 0, k_3 = 0.1k2?=0,k3?=0.1。
需要指出的是,這種方法只對某些特殊類型的圖像有效,而且需要針對具體圖像進(jìn)行 ROI 設(shè)置和參數(shù)調(diào)節(jié),才能取得較好的圖像增強(qiáng)效果。
基本例程:1.63 直方圖統(tǒng)計量圖像增強(qiáng)
# # 1.63 直方圖統(tǒng)計量圖像增強(qiáng)img = cv2.imread("../images/Fig0326a.tif", flags=0) # flags=0 讀取為灰度圖像imgROI = img[12:120, 12:120]maxImg, maxROI = img.max(), imgROI.max()const = maxImg / maxROIimgHSE = enhanceHistStat(img, const) # 子程序:直方圖統(tǒng)計量增強(qiáng) (自定義方法)plt.figure(figsize=(10, 6))plt.subplot(131), plt.title("Original image"), plt.axis('off')plt.imshow(img, cmap='gray', vmin=0, vmax=255)plt.subplot(132), plt.title("Global equalize histogram"), plt.axis('off')imgEqu = cv2.equalizeHist(img) # 使用 cv2.qualizeHist 完成直方圖均衡化變換plt.imshow(imgEqu, cmap='gray', vmin=0, vmax=255)plt.subplot(133), plt.title("Histogram statistic enhance"), plt.axis('off')plt.imshow(imgHSE, cmap='gray', vmin=0, vmax=255)plt.show()
4.6 直方圖反向投影(反向追蹤)
直方圖反向投影是一種在輸入圖像中查找與特定模板圖像匹配最佳的點(diǎn)或區(qū)域的方法,可以對特定顏色物體、特定灰度物體進(jìn)行查找、跟蹤,常用于圖像查找、圖像分割。
直方圖反向投影處理的原理,是計算某一特征的直方圖模型,再使用該模型去尋找圖像中存在的特征。
直方圖反向投影處理的過程,首先建立模板區(qū)域的直方圖,再將直方圖投影到輸入圖像,計算輸入圖像中每個像素點(diǎn)的像素值與直方圖匹配概率,得到概率圖像并以一定閾值進(jìn)行二值化處理。
OpenCV 提供的函數(shù) cv2.calcBackProject() 可以用來做直方圖反向投影。
函數(shù)說明:
cv2.calcBackProject(images, channels, hist, ranges, scale[, dst]) → dst參數(shù)說明:
-
images:顏色對比度的閾值,可選項,默認(rèn)值 8
-
channels: 計算反向投影的圖像通道
-
hist: 查找模板區(qū)域的直方圖
-
ranges:每個維度中直方圖單元邊界的數(shù)組
-
scale:反向投影輸出的縮放比例
-
返回值 dst:返回反向投影的輸出圖像
基本例程:1.64 直方圖反向投影追蹤
# 1.64 直方圖反向投影roi = cv2.imread("../images/BallFrag.png", flags=1) # 查找的圖像區(qū)域target = cv2.imread("../images/imgBall.png", flags=1) # 被查找的目標(biāo)圖像hsvRoi = cv2.cvtColor(roi, cv2.COLOR_BGR2HSV)hsvTar = cv2.cvtColor(target, cv2.COLOR_BGR2HSV)histRoi = cv2.calcHist([hsvRoi], [0, 1], None, [180, 256], [0, 180, 0, 256]) # 計算目標(biāo)直方圖cv2.normalize(histRoi, histRoi, 0, 255, cv2.NORM_MINMAX) # 歸一化 ->[0,255]dst = cv2.calcBackProject([hsvTar], [0, 1], histRoi, [0, 180, 0, 256], 1) # 反向投影disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5)) # 定義橢圓結(jié)構(gòu)形狀imgConv = cv2.filter2D(dst, -1, disc) # 圖像卷積ret, thresh = cv2.threshold(imgConv, 100, 255, 0) # 圖像二值化處理,得到掩模模板imgTrack = cv2.bitwise_and(target, target, mask=thresh) # 以 thresh 為掩模按位與,顯示查找區(qū)域plt.figure(figsize=(10,6))plt.subplot(131), plt.imshow(cv2.cvtColor(target, cv2.COLOR_BGR2RGB)), plt.title("target image"), plt.axis('off')plt.subplot(132), plt.imshow(thresh, 'gray'), plt.title("tracking mask"), plt.axis('off')plt.subplot(133), plt.imshow(cv2.cvtColor(imgTrack, cv2.COLOR_BGR2RGB)), plt.title("tracking result"), plt.axis('off')plt.show()版權(quán)聲明:
注:本文中部分原始圖片來自 Rafael C. Gonzalez “Digital Image Processing, 4th.Ed.” Fig3.10b,特此致謝。
youcans 的 OpenCV 學(xué)習(xí)課 @ youcans 原創(chuàng)作品
轉(zhuǎn)載必須標(biāo)注原文鏈接:https://blog.csdn.net/youcans/article/details/121328057
Copyright 2021 youcans, XUPT
Crated:2021-11-18
歡迎關(guān)注 『youcans 的 OpenCV 學(xué)習(xí)課』 系列,持續(xù)更新
youcans 的 OpenCV 學(xué)習(xí)課—1.安裝與環(huán)境配置
youcans 的 OpenCV 學(xué)習(xí)課—2.圖像讀取與顯示
youcans 的 OpenCV 學(xué)習(xí)課—3.圖像的創(chuàng)建與修改
youcans 的 OpenCV 學(xué)習(xí)課—4.圖像的疊加與混合
youcans 的 OpenCV 學(xué)習(xí)課—5.圖像的幾何變換
youcans 的 OpenCV 學(xué)習(xí)課—6.灰度變換與直方圖處理
youcans 的 OpenCV 學(xué)習(xí)課—7.空間域圖像濾波
youcans 的 OpenCV 學(xué)習(xí)課—8.頻率域圖像濾波(上)
youcans 的 OpenCV 學(xué)習(xí)課—9.頻率域圖像濾波(下)
總結(jié)
以上是生活随笔為你收集整理的youcans 的 OpenCV 学习课—6.灰度变换与直方图处理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenCV 例程200篇】20. 图
- 下一篇: 【OpenCV 例程200篇】10. 图