反向投影法是用已知圖像的某些特徵來突出其它圖像中此類特徵的一種方法,基於直方圖。html
主要步驟以下:測試
一、統計已知圖像某個特徵的色度直方圖,一般用色度-飽和度(Hue-Saturation)來統計二維直方圖,並把直方圖表示爲機率的形式。ui
二、選取測試圖像,對於圖像中的每個像素,查看它的色度在已統計直方圖上的機率,用這個機率來重建整張圖像。spa
三、最後把重建出的圖像歸一化,會發現用於統計直方圖的特徵被突出出來。3d
舉OpenCV的例子,已知圖像以下:code
咱們稱之爲模型。選取圖中的手做爲要統計的特徵,它的mask以下:htm
因而能夠統計獲得手的Hue-Saturation直方圖和聯合機率分佈(看作相互獨立)的熱度圖:blog
測試圖片是另外一張手的圖像:圖片
而後執行第三步:get
能夠發現手被突出出來了,這是由於,相同物體在不一樣的圖像中的色值一般是相近的,所以能夠經過這種方式來突出它。
Python代碼以下:
import cv2 import numpy as np import matplotlib.pyplot as plt #獲取mask、model、test圖像數據,並進行預處理 mask = plt.imread('mask.jpg')[:,:,0] mask = ((mask<120)*255).astype(np.uint8) n = np.sum(mask>100) model = cv2.cvtColor(plt.imread('model.jpg'),cv2.COLOR_RGB2HSV)#把RGB顏色空間轉換爲HSV test = cv2.cvtColor(plt.imread('test.jpg'),cv2.COLOR_RGB2HSV) #根據色度和飽和度(明度不考慮),統計model顏色信息,並繪製直方圖和它們聯合分佈的熱度圖 hist_size = 50 #直方圖劃分的區間數量 hist_h = cv2.calcHist([model],[0],mask,[hist_size],[0,256])/n hist_s = cv2.calcHist([model],[1],mask,[hist_size],[0,256])/n hot_values = np.matmul(hist_s, hist_h.T) fig = plt.figure() ax1 = fig.add_subplot(121) ax2 = fig.add_subplot(122) ax1.bar(range(len(hist_h)),hist_h[:,0]) ax1.bar(range(len(hist_s)),hist_s[:,0]) hot = ax2.imshow(hot_values) plt.colorbar(hot) plt.show() #使用熱度圖重建test圖像 projection = np.zeros([test.shape[0],test.shape[1]]) for i in range(projection.shape[0]): for j in range(projection.shape[1]): h_pos = (test[i,j,0]/256*hist_size).astype(np.uint8) s_pos = (test[i,j,1]/256*hist_size).astype(np.uint8) projection[i,j] = hist_h[h_pos] * hist_s[s_pos] projection = projection / np.max(projection) plt.imshow(projection,cmap='gray') plt.show()
咱們還能夠用RGB來統計,創建RGB的三維聯合分佈,而後對測試圖像進行重建,效果以下:
能夠看出突出效果並無H-S模型來得好。代碼以下:
import cv2 import numpy as np import matplotlib.pyplot as plt mask = plt.imread('mask.jpg')[:,:,0] mask = ((mask<120)*255).astype(np.uint8) n = np.sum(mask>100) model = plt.imread('model.jpg') test = plt.imread('test.jpg') hist_size = 50 #直方圖劃分的區間數量 hist_r = cv2.calcHist([model],[0],mask,[hist_size],[0,256])[:,0]/n hist_g = cv2.calcHist([model],[1],mask,[hist_size],[0,256])[:,0]/n hist_b = cv2.calcHist([model],[2],mask,[hist_size],[0,256])[:,0]/n plt.bar(range(len(hist_r)),hist_r) plt.bar(range(len(hist_g)),hist_g) plt.bar(range(len(hist_b)),hist_b) plt.show() projection = np.zeros([test.shape[0],test.shape[1]]) for i in range(projection.shape[0]): for j in range(projection.shape[1]): r_pos = (test[i,j,0]/256*hist_size).astype(np.uint8) g_pos = (test[i,j,1]/256*hist_size).astype(np.uint8) b_pos = (test[i,j,2]/256*hist_size).astype(np.uint8) projection[i,j] = hist_r[r_pos] * hist_g[g_pos] * hist_b[b_pos] projection = projection / np.max(projection) plt.imshow(projection,cmap='gray') plt.show()
參考自:https://docs.opencv.org/master/da/d7f/tutorial_back_projection.html