CalcBackProject函数
反向投影
目標
本文檔嘗試解答如下問題:
- 什么是反向投影,它可以實現什么功能?
- 如何使用OpenCV函數?calcBackProject?計算反向投影?
- 如何使用OpenCV函數?mixChannels?組合圖像的不同通道?
原理
什么是反向投影?
- 反向投影是一種記錄給定圖像中的像素點如何適應直方圖模型像素分布的方式。
- 簡單的講, 所謂反向投影就是首先計算某一特征的直方圖模型,然后使用模型去尋找圖像中存在的該特征。
- 例如, 你有一個膚色直方圖 ( Hue-Saturation 直方圖 ),你可以用它來尋找圖像中的膚色區域:
反向投影的工作原理?
-
我們使用膚色直方圖為例來解釋反向投影的工作原理:
-
假設你已經通過下圖得到一個膚色直方圖(Hue-Saturation), 旁邊的直方圖就是?模型直方圖?( 代表手掌的皮膚色調).你可以通過掩碼操作來抓取手掌所在區域的直方圖:
-
下圖是另一張手掌圖(測試圖像) 以及對應的整張圖像的直方圖:
-
我們要做的就是使用?模型直方圖?(代表手掌的皮膚色調) 來檢測測試圖像中的皮膚區域。以下是檢測的步驟
-
對測試圖像中的每個像素 (??),獲取色調數據并找到該色調(??)在直方圖中的bin的位置。
-
查詢?模型直方圖?中對應的bin -??- 并讀取該bin的數值。
-
將此數值儲存在新的圖像中(BackProjection)。 你也可以先歸一化?模型直方圖?,這樣測試圖像的輸出就可以在屏幕顯示了。
-
通過對測試圖像中的每個像素采用以上步驟, 我們得到了下面的 BackProjection 結果圖:
-
使用統計學的語言,?BackProjection?中儲存的數值代表了測試圖像中該像素屬于皮膚區域的?概率?。比如以上圖為例, 亮起的區域是皮膚區域的概率更大(事實確實如此),而更暗的區域則表示更低的概率(注意手掌內部和邊緣的陰影影響了檢測的精度)。
源碼
-
本程序做什么?
-
裝載圖像
-
轉換原圖像到 HSV 格式,再分離出?Hue?通道來建立直方圖 (使用 OpenCV 函數?mixChannels)
- 讓用戶輸入建立直方圖所需的bin的數目。
- 計算同一圖像的直方圖 (如果bin的數目改變則更新直方圖) 和反向投影圖。
-
顯示反向投影圖和直方圖。
-
-
下載源碼:
- 點擊?這里?獲取簡單版的源碼 (本教程使用簡單版)。
- 要嘗試更炫的代碼 (使用 H-S 直方圖和 floodFill 來定義皮膚區域的掩碼)你可以點擊?增強版演示
- 當然你也可以從實例庫里下載經典的?camshiftdemo?示例。
-
代碼一瞥:
解釋
申明圖像矩陣,初始化bin數目:
Mat src; Mat hsv; Mat hue; int bins = 25;讀取輸入圖像并轉換到HSV 格式:
src = imread( argv[1], 1 ); cvtColor( src, hsv, CV_BGR2HSV );本教程僅僅使用Hue通道來創建1維直方圖 (你可以從上面的鏈接下載增強版本,增強版本使用了更常見的H-S直方圖,以獲取更好的結果):
hue.create( hsv.size(), hsv.depth() ); int ch[] = { 0, 0 }; mixChannels( &hsv, 1, &hue, 1, ch, 1 );你可以看到這里我們使用?mixChannels?來抽取 HSV圖像的0通道(Hue)。 該函數接受了以下的實參:
- &hsv:?一系列輸入圖像的數組, 被拷貝的通道的來源
- 1:?輸入數組中圖像的數目
- &hue:?一系列目的圖像的數組, 儲存拷貝的通道
- 1:?目的數組中圖像的數目
- ch[] = {0,0}:?通道索引對的數組,指示如何將輸入圖像的某一通道拷貝到目的圖像的某一通道。在這里,&hsv圖像的Hue(0) 通道被拷貝到&hue圖像(單通道)的0 通道。
- 1:?通道索引對德數目
創建Trackbar方便用戶輸入bin數目。 Trackbar的任何變動將會調用函數?Hist_and_Backproj?。
char* window_image = "Source image"; namedWindow( window_image, CV_WINDOW_AUTOSIZE ); createTrackbar("* Hue bins: ", window_image, &bins, 180, Hist_and_Backproj ); Hist_and_Backproj(0, 0);顯示并等待用戶突出程序:
imshow( window_image, src );waitKey(0); return 0;Hist_and_Backproj 函數:?初始化函數?calcHist?需要的實參, bin數目來自于 Trackbar:
void Hist_and_Backproj(int, void* ) {MatND hist;int histSize = MAX( bins, 2 );float hue_range[] = { 0, 180 };const float* ranges = { hue_range };計算直方圖并歸一化到范圍?
calcHist( &hue, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false ); normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() );調用函數?calcBackProject?計算同一張圖像的反向投影
MatND backproj; calcBackProject( &hue, 1, 0, hist, backproj, &ranges, 1, true );所有的實參都已經知道了(與計算直方圖的實參一樣), 僅僅增加了 backproj 矩陣,用來儲存原圖像(&hue)的反向投影。
顯示 backproj:
imshow( "BackProj", backproj );顯示1維 Hue 直方圖:
int w = 400; int h = 400; int bin_w = cvRound( (double) w / histSize ); Mat histImg = Mat::zeros( w, h, CV_8UC3 );for( int i = 0; i < bins; i ++ ){ rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at<float>(i)*h/255.0 ) ), Scalar( 0, 0, 255 ), -1 ); }imshow( "Histogram", histImg );結果
下面是對一張樣本圖像(猜猜是什么?又是一掌)進行的測試結果。 你可以改變bin的數目來觀察它是如何影響結果圖像的:
|
|
|
|
總結
以上是生活随笔為你收集整理的CalcBackProject函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: preCornerDetect函数
- 下一篇: cvCalcBackProject的例子