OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()
OpenCV學習(二十二) :反向投影:calcHist(),minMaxLoc(),compareHist()
參考博客:
反向投影backproject的直觀理解
opencv 反向投影
顏色直方圖的計算、顯示、處理、對比及反向投影
一、概述
1、官方解釋:反向投影是一種記錄給定圖像中的像素點如何適應直方圖模型像素分布的方式。簡單的講,
1)就是首先計算某一特征的直方圖模型;(特征可以為色調+飽和度、灰度值等等)
2)然后使用模型去尋找圖像中存在的該特征。例如,你有一個膚色直方圖(Hue-Saturation直方圖),你可以用它(色調和飽和度)來尋找圖像中的膚色區域:
2、反向投影圖就是圖像對應位置像素的數量統計,也可以看做是密度統計。 反向投影圖在某一位置(點)的值是原圖對應位置(點)的像素值所在原圖區間(bins)的總數目。(所以,一個區間點越多,在反向投影矩陣中就越亮。)
3、反向投影中的“反向”指的是從直方圖值到反向投影矩陣映射的過程。
4、通過反向投影,原始的圖像被簡化了,而這個簡化的過程實際上就是提取出圖像的某個特征。所以我們就可以用這個特征來對比兩幅圖,如果兩幅圖的反向投影矩陣相似或相同,那么我們就可以判定這兩幅圖這個特征是相同的。
5、反向投影的作用:
反向投影用于在輸入圖像(通常較大)中查找**特定圖像(通常較小或者僅1個像素,以下將其稱為模板圖像)**最匹配的點或者區域,也就是定位模板圖像出現在輸入圖像的位置。如圖:
第一個圖為源圖像,中間的那個小圖像是產生用于反向投影的直方圖的圖像,最后的用直方圖均衡化后的結果圖像,可以看到,蘋果的像素位置幾被找到了。
二、calcBackProject()函數
calcBackProject 的基本過程是:
1)拿到 特征圖像 (或模板圖像)
2)得到 特征圖像的直方圖
3)拿到測試圖像,依據測試圖像的每個像素的值,在特征圖像的直方圖中找到對應的值,然后將直方圖的值賦給新的圖像,backproject算法就完成了。
三、CalcBackProjectPatch()函數
對于calcBackProjectPatch,整個是基于塊的形式,利用直方圖做匹配,類似于模板匹配,只不過這些模板轉換為直方圖,而原圖中以某點為基準,摳出來作對比的部分也轉換為直方圖,兩個直方圖作匹配,匹配的結果作為此點的值。
結果會是一張概率圖,概率越大的地方,代表此區域與模板的相似度越高。而且,當模板小于檢測的目標時,得到的結果圖也能反映出檢測區域的形狀。這個結果與模板匹配的結果很相似,但利用直方圖的方式,就能去除光照變化、邊緣遮擋,旋轉等因素的影響。另外
基于塊的反向投影。這種方法速度很慢,模版圖像別弄的太大了。
例如:
1)當模板圖像小與目標的時候,作為區域檢測器,測試如下:可以找到手區域
2)當模板等于目標的時候,測試如下:輸出圖像,較亮的部分就是人的頭部大致位置
詳情參考:
opencv 直方圖反向投影
函數原型:
void cvCalcBackProjectPatch( IplImage** image, // 輸入圖像:是一個單通道圖像數組,而非實際圖像 CvArr* dst, // 輸出結果:是一個單通道32位浮點圖像,它的寬度為W-w+1,高度為H-h+1,這里的W和H是輸入圖像的寬度和高度,w和h是模板圖像的寬度和高度 CvSize patch_size, // 模板圖像的大小:寬度和高度 CvHistogram* hist, // 模板圖像的直方圖:直方圖的維數和輸入圖像的個數相同,并且次序要一致;例如:輸入圖像包含色調和飽和度,那么直方圖的第0維是色調,第1維是飽和度 int method, // 對比方式:跟直方圖對比中的方式類似,可以是:CORREL(相關)、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA float factor // 歸一化因子,一般都設置成1,否則很可能會出錯;中文、英文以及各路轉載的文檔都錯了,這個參數的實際類型是double,而非float,我看了源代碼才搞定這個地方 )四、mixChannels()函數
mixChannels()函數用于將輸入數組的指定通道復制到輸出數組的指定通道。
其實我們接觸到的,split()和merge(),以及cvtColor的某些形式,都只是mixChannels()的一部分。
參考:
opencv3/C++ mixChannels()詳解:4通道圖像分割、HSV通道獲取
示例:
#include<opencv2/opencv.hpp> using namespace cv;int main() {Mat bgra( 500, 500, CV_8UC4, Scalar(255,255,0,255) );Mat bgr( bgra.rows, bgra.cols, CV_8UC3 );Mat alpha( bgra.rows, bgra.cols, CV_8UC1 );Mat out[] = { rgb, alpha };int from_to[] = { 0, 2, 1, 1, 2, 0, 3, 3 };// 輸入1一個矩陣,輸出2個舉證,4個索引對mixChannels( &bgra, 1, out, 2, from_to, 4 );imshow("bgra", bgra); // 青色imshow("bgr", bgr); // 黃色(通道值改變,色彩空間不變)waitKey(0);return 0; }五、示例:
使用模型直方圖(代表手掌的皮膚色調)來檢測測試圖像中 的皮膚區域。
1)對測試圖像中的每個像素(p(i,j),獲取色調數據并找到該色調(h(i,j),s(i,j))在直方圖中的bin的位置;
2)查詢模型直方圖中對應的bin-(hi,j,si,j)并讀取該bin的數值;
3)將此數值存儲在新的圖像中(BackProjection)。你也可以先歸一化模型直方圖,這樣測試圖像的輸出就可以在屏幕顯示了;
4)通過對測試圖像中的每個像素采用以上步驟,我們得到了下面的BackProjection結果圖:
5)使用統計學的語言,BackProjection中存儲的數值代表了測試圖像中該像素屬于皮膚區域的概率。比如上圖為例,亮起的區域是皮膚區域的概率更大,而更暗的區域則表示更低的概率(注意手掌內部和邊緣的陰影影響了檢測的精度)。
直方圖計算 bins(特征空間子區段的數目)回調函數:
void on_BinChange(int, void* ) {// 1、參數準備MatND hist;int histSize = MAX( g_bins, 2 ); // 組距 最小為2float hue_range[] = { 0, 180 };const float* ranges = { hue_range };// 2、計算直方圖并歸一化// 將handhue取值替換為g_hueImage圖像的中心部分,作為特征圖像Mat handhue_feature= g_hueImage(Rect(g_hueImage.rows/2-25, g_hueImage.cols/2-25, 50, 50)).clone();// g_hueImageimshow("handhue_feature", handhue_feature); // 顯示特征// 將handhue_feature的取值 替換為g_hueImage圖像的中心部分,作為特征圖像calcHist( &handhue_feature, 1, 0, Mat(), hist, 1, &histSize, &ranges, true, false );normalize( hist, hist, 0, 255, NORM_MINMAX, -1, Mat() ); // 歸一化直方圖數值范圍為0~255之間// 3、計算 獲取反向投影MatND backproj;calcBackProject( &g_hueImage, 1, 0, hist, backproj, &ranges, 1, true );// 4、顯示反向投影imshow( "反向投影圖", backproj );// 5、繪制直方圖的參數準備int w = 400; int h = 400;int bin_w = cvRound( (double) w / histSize );Mat histImg = Mat::zeros( w, h, CV_8UC3 );// 6、繪制直方圖for( int i = 0; i < g_bins; i ++ ){ rectangle( histImg, Point( i*bin_w, h ), Point( (i+1)*bin_w, h - cvRound( hist.at<float>(i)*h/255.0 ) ), Scalar( 100, 123, 255 ), -1 ); }// 7、顯示直方圖窗口imshow( "直方圖", histImg ); }源圖+色調圖
特征圖:
總結
以上是生活随笔為你收集整理的OpenCV学习(二十二) :反向投影:calcBackProject(),mixChannels()的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: tensorflow中GPU的设置
- 下一篇: C++查看各种数据类型所占字节和最大最小