"""
反向投影可以用來做圖像分割,或者在圖像中找尋我們感興趣的部分。
反向投影就是首先計算某一特征的直方圖模型,然后使用模型去尋找圖像中存在的該特征。。如果把圖像的某個區(qū)域含有特定和的紋理和物體,這個區(qū)域的的直方圖就可以看作是一個函數(shù),該函數(shù)返回某個像素屬于這個特殊紋理或物體的概率;
它會輸出與輸入圖像(待搜索)同樣大小的圖像,其中的每一個像素值代表了輸入圖像上對應(yīng)點屬于目標(biāo)對象的概率。
輸出圖像中像素值越高(越白)的點就越可能代表我們要搜索的目標(biāo) (在輸入圖像所在的位置)。
直方圖投影經(jīng)常與camshift 算法等一起使用。
步驟:
1. 為一張包含我們要查找目標(biāo)的圖像創(chuàng)建直方圖,我們要查找的對象要盡量占滿這張圖像。
最好使用顏色直方圖,因為一個物體的顏色要比它的灰度能更好的被用來進(jìn)行圖像分割與對象識別。
2. 再把這個顏色直方圖投影到輸入圖像中尋找我們的目標(biāo),
也就是找到輸入圖像中的每一個像素點的像素值在直方圖中對應(yīng)的概率,這樣我們就得到一個概率圖像。
3. 設(shè)置適當(dāng)?shù)拈撝祵Ω怕蕡D像進(jìn)行二值化
"""
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
# OpenCV 提供的函數(shù) cv2.calcBackProject() 可以用來做直方圖反向投影。
# 它的參數(shù)與函數(shù) cv2.calcHist 的參數(shù)基本相同。其中的一個參數(shù)是我們要查找目標(biāo)的直方圖。
# 同樣再使用目標(biāo)的直方圖做反向投影之前我們應(yīng)該先對其做歸一化處理。
# 返回的結(jié)果是一個概率圖像
def back_projection_demo():
#首先將圖像讀進(jìn)來,然后將其轉(zhuǎn)成hsv色彩空間,然后形成2d直方圖,對其進(jìn)行歸一化,輸出結(jié)果對其反向投影
sample = cv.imread("C:/Users/tzting/Desktop/opencv-python/lena.png")
target = cv.imread("C:/Users/tzting/Desktop/opencv-python/example.png")
sample_hsv = cv.cvtColor(sample,cv.COLOR_BGR2HSV)
target_hsv = cv.cvtColor(sample,cv.COLOR_BGR2HSV)
cv.imshow("sample",sample)
cv.imshow("target",target)
roiHist = cv.calcHist([sample_hsv],[0,1],None,[100,256],[0,100,0,256])#計算樣本直方圖 [100,256]越小,效果越好
cv.normalize(roiHist,roiHist,0,255,cv.NORM_MINMAX)#0-255之間歸一化
dst=cv.calcBackProject([target_hsv],[0,1],roiHist,[0,180,0,256],1)#1表示大小放縮 產(chǎn)生反向投影生成出來的圖像
cv.imshow("backprojection_demo",dst)
# 2D直方圖建立
def hist2d_demo(image):
hsv = cv.cvtColor(image,cv.COLOR_BGR2HSV)
hist =cv.calcHist([image],[0,1],None,[180,256],[0,100,0,256]) # 計算直方圖
#cv.imshow("hist2d",hist)
plt.imshow(hist,interpolation='nearest') # 直方圖必須是float32
plt.title("2D Histogram")
plt.show()
使用圖像:

target:

最后結(jié)果:

備注:
1、使用[cv.calcHist()]函數(shù)來找出直方圖。
cv.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])
例子:roiHist = cv.calcHist([sample_hsv],[0,1],None,[180,256],[0,100,0,256])
images : 它是uint8或float32類型的原圖。它應(yīng)該用方括號表示,即“[img]”。
channels : 它也在方括號中給出。它是我們計算直方圖的通道索引。例如,如果輸入的是灰度圖像,則其值為[0]。對于彩色圖像,可以通過[0]、[1]或[2]分別計算藍(lán)色通道、綠色通道和紅色通道的直方圖。
mask : 遮罩圖像,要找出完整圖像的直方圖,就把這個參數(shù)設(shè)為"None"。但如果你想要找出圖像一部分的直方圖的話,你必須創(chuàng)建一個遮罩圖像,并且把它當(dāng)做參數(shù)傳入。(稍后我會展示一個例子。)
histSize : 這代表了我們抽屜的數(shù)量。需要在方括號中給出,如果要取全量,我們傳入[256]。
ranges : 這是我們的區(qū)域。通常來說是[0,256]。
參考博客:https://blog.csdn.net/ssybc/article/details/84960863
2、 歸一化就是要把需要處理的數(shù)據(jù)經(jīng)過處理后(通過某種算法)限制在你需要的一定范圍內(nèi)。
歸一化函數(shù)cv2.normalize:
normalize(src, dst[, alpha[, beta[, norm_type[, dtype[, mask]]]]]) -> dst
例子:cv.normalize(roiHist,roiHist,0,255,cv.NORM_MINMAX)
src->輸入數(shù)組。
dst參數(shù)->輸出與src相同大小的數(shù)組,支持原地運算
alpha->range normalization模式的最小值。
beta->range normalization模式的最大值,不用于norm normalization(范數(shù)歸一化)模式。
norm_type參數(shù)->歸一化的類型,norm_type參數(shù)可以有以下的取值:
NORM_MINMAX:數(shù)組的數(shù)值被平移或縮放到一個指定的范圍,線性歸一化,一般較常用。
NORM_INF:歸一化數(shù)組的C-范數(shù)(絕對值的最大值)。
NORM_L1 :歸一化數(shù)組的L1-范數(shù)(絕對值的和)。
NORM_L2 :歸一化數(shù)組的(歐幾里德)L2-范數(shù)。
參考博客:https://blog.csdn.net/solomon1558/article/details/44689611
3、反向投影用于在輸入圖像(通常較大)中查找特定圖像(通常較小或者僅1個像素,以下將其稱為模板圖像)最匹配的點或者區(qū)域,也就是定位模板圖像出現(xiàn)在輸入圖像的位置。
函數(shù)原型cv2.calcBackProject:
calcBackProject(images, channels, hist, ranges, scale[, dst]) -> dst
例子: dst=cv.calcBackProject(target_hsv,[0,1],roiHist,[0,180,0,256],1)
images參數(shù)表示輸入圖像(是HSV圖像)。傳入時應(yīng)該用中括號[ ]括起來。
channels參數(shù)表示用于計算反向投影的通道列表,通道數(shù)必須與直方圖維度相匹配。
hist參數(shù)表示輸入的模板圖像直方圖。
ranges參數(shù)表示直方圖中每個維度bin的取值范圍 (即每個維度有多少個bin)。
scale參數(shù)表示可選輸出反向投影的比例因子,一般取1。
參考博客:https://blog.csdn.net/keith_bb/article/details/70154219