乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      OpenCV_顏色直方圖的計(jì)算、顯示、處理、對(duì)比及反向投影

       學(xué)海無涯GL 2012-09-11

      OpenCV_顏色直方圖的計(jì)算、顯示、處理、對(duì)比及反向投影

      首先介紹一下直方圖
      一.用帶權(quán)重的樣本統(tǒng)計(jì)直方圖
      直方圖Histogram,是一種常見的概率分布的非參數(shù)(區(qū)別于高斯分布,泊松分布等用參數(shù)表達(dá)概率密度的方法)表達(dá)方法。直方圖可以看成概率密度分布的離散化表達(dá)方法。它的計(jì)算很簡(jiǎn)單,是一種投票的方法,就是每個(gè)樣本往對(duì)應(yīng)的小盒子(bin)里投一票。假設(shè)N個(gè)樣本數(shù)據(jù)x量化為1~M之間的整數(shù),那么Hist是M維數(shù)組,對(duì)應(yīng)的直方圖計(jì)算方法如下:

      //initializing
      for i=1:M
          Hist[i] = 0;
      end
      //voting
      for  i = 1:N
          Hist[x[i]] += 1 ;
      end
      為了表示成概率分布,需要Hist數(shù)組和為1:
      //normalize
      for  j = 1:M
          Hist[j] = Hist[j]/sum(Hist) ; //sum(Hist) = Hist[1] + Hist[2] + ... + Hist[M];
      end
      在這里sum(Hist)等于樣本個(gè)數(shù)N。以上“投票+歸一化”兩個(gè)步驟,其實(shí)可以和成一步,即每個(gè)樣本x[i]有一個(gè)對(duì)應(yīng)的權(quán)重w[i]=1/N,投票的時(shí)候往小盒子里放的是權(quán)重:
       
      //initializing
      for i=1:M
          Hist[i] = 0;
      end
      //voting
      for  i = 1:N
          Hist[x[i]] += w[i] ;
      end
       
      這樣得到數(shù)組Hist里的每個(gè)值都是一個(gè)0-1之間的小數(shù),表示當(dāng)x取這個(gè)值(數(shù)組對(duì)應(yīng)的下標(biāo))時(shí)候的概率。
       
      二.樣本權(quán)重的變化影響直方圖形狀
      如果想改變一個(gè)概率分布取曲線的形狀,比如,在訓(xùn)練的時(shí)候要強(qiáng)調(diào)x[i]=3的樣本,一種辦法是增加這種樣本的個(gè)數(shù),使Hist[3]變大,另一種方法是增加和它對(duì)應(yīng)的樣本的權(quán)重w[i],讓某些樣本產(chǎn)生“一個(gè)頂倆”的效果,這兩種方式都能起到改變概率分布的作用。
       
      對(duì)人臉檢測(cè)這類基于圖像的目標(biāo)檢測(cè)方法,需要搜集大量樣本進(jìn)行離線的訓(xùn)練,樣本要盡可能覆蓋所有可能的情況,從而使所提取特征的概率分布具有代表性,當(dāng)樣本數(shù)趨向于無窮大的時(shí)候,概率分布就趨向于真實(shí)的分布情況。但通常在實(shí)際中,樣本數(shù)總是有限的,這時(shí)就可以通過增加某些比較重要的樣本的權(quán)重,來達(dá)到看起來是增加了某些樣本數(shù)量的效果。
       
      另外,直方圖數(shù)組Hist的某個(gè)bin中的樣本權(quán)重的改變,不應(yīng)該僅僅影響當(dāng)前的bin,也應(yīng)該對(duì)周圍相鄰的bin造成影響。比如,在統(tǒng)計(jì)一個(gè)地區(qū)人群的身高分布的時(shí)候,如果只有一個(gè)樣本x=1.65m,我們可以在Hist數(shù)組中對(duì)應(yīng)1.6<=x<1.7這一個(gè)bin里投上一票,但是1.5<=x<1.6和1.7<=x<1.8兩個(gè)bin的得票為0。其實(shí)不應(yīng)該這樣,根據(jù)身高應(yīng)該是連續(xù)分布的這一假設(shè),從樣本x=1.65m可以安全地推斷出世上也應(yīng)該有身高1.59和1.71的人,這樣左右兩個(gè)相鄰的bin的值就不應(yīng)為0,應(yīng)該也受到x=1.65m這個(gè)樣本的影響,這種影響可以假設(shè)是服從高斯分布,即越遠(yuǎn)的bin受影響越小。這其實(shí)是另一種常見的概率密度估計(jì)的非參數(shù)方法,kernel density estimation(KDE)。我們的人臉檢測(cè)應(yīng)用由于樣本足夠多,所以沒有考慮這一方法。也就是說,每個(gè)特征值在投票的時(shí)候,只對(duì)一個(gè)bin起作用,不影響相鄰的那兩個(gè)。

      顏色直方圖直觀的顯示了圖像在色彩空間的分布狀況,本文將討論在OpenCv中跟直方圖相關(guān)的一些基本操作,包括:計(jì)算、顯示、處理、對(duì)比及反向投影.

      直方圖的計(jì)算、顯示、處理
        OpenCv中,可以用方法cvCalcHist方法計(jì)算圖像的直方圖。不過值得注意的是,該方法的第一個(gè)參數(shù)image是一個(gè)指向數(shù)組的IplImage* 類型指針。這允許利用多個(gè)圖像通道。對(duì)于多通道圖像(如HSV或者RGB),在調(diào)用函數(shù)cvCalcHist()之前,先要調(diào)用函數(shù)cvSplit()將圖像分為單通道,此方法與宏cvCvtPixtoPlane等同,然后再選擇需要參與直方圖計(jì)算的通道。下面有幾段計(jì)算直方圖的代碼,分別計(jì)算單通道(紅色)直方圖、色調(diào)和飽和度直方圖。

      如何在OpenCV中繪制一個(gè)直方圖?下面是有關(guān)于繪制直方圖實(shí)驗(yàn)的學(xué)習(xí)總結(jié):

      1.cvCreateHist(dim,&size,flag,**range,uniform):

         dim為hist的維度;size為總分區(qū)間數(shù);flag為標(biāo)記圖像是什么類型,是CV_HIST_ARRAY,還是CV_HIST_TREE,然后就可以選擇如何保存數(shù)據(jù),如果CV_HIST_ARRAY,就用CvMatND(多維密集數(shù)組);如果CV_HIST_TREE,就使用CvSparseMat(多維稀疏數(shù)組);range為每個(gè)維度的范圍;uniform為歸一化標(biāo)識(shí),這個(gè)還不是很好理解。

      2.IplImage中有一個(gè)屬性可以設(shè)置圖像的原點(diǎn)坐標(biāo),0代表左上角,1代表左下角。(image->origin)

      3.cvCalcHist(**imge,*hist):

         image為統(tǒng)計(jì)圖像,hist為直方圖結(jié)構(gòu)體

      4.獲取了直方圖信息后,可以通過直方圖結(jié)構(gòu)體直接訪問內(nèi)部信息:

        hist->type;hist->thresh[i][0]和hist->thresh[i][1]分別存儲(chǔ)上閥值和下閥值。如果CV_HIST_ARRAY的話,可以通過((CvMatND*)hist->bins)->data.fl[i]獲取統(tǒng)計(jì)值。不過OpenCV已經(jīng)提供了一個(gè)很好的方法去查詢,cvQueryHistValue_*D(hist,d...);

      5.可以通過CV_RGB(R,G,B)的宏設(shè)置RGB顏色。

      6.直方圖的繪制,使用cvQueryHistValue_*D去獲取統(tǒng)計(jì)值,然后繪制在一個(gè)創(chuàng)建好的圖像中??梢酝ㄟ^cvLine或者cvRectangle方法。

      7.還可以通過設(shè)置range的范圍來獲取有需要的區(qū)域,如果這樣的話,最好在畫直方圖的時(shí)候,計(jì)算好每個(gè)區(qū)間的width值。

      8.cvGetMinMaxValue(hist,*min,*max,*minindex,*maxindex):

        min和max必須為float類型,minindex和maxindex為最小最大值的位置

      9.cvRound方法:四舍五入

      10.從HSV顏色轉(zhuǎn)換為RGB顏色:

        IplImage* hsv_color = cvCreateImage(cvSize(1,1),8,3);
        IplImage* rgb_color = cvCreateImage(cvSize(1,1),8,3); 

        cvSet2D(hsv_color,0,0,cvScalar(h*180.f/h_bins,s*255.f/s_bins,255,0));
        cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);
        CvScalar color = cvGet2D(rgb_color,0,0);

      具體代碼如下:

      View Code
      復(fù)制代碼
        1 #include "stdafx.h"
      2 #include <iostream>
      3 using namespace std;
      4
      5
      6 #ifdef _CH_
      7 #pragma package <opencv>
      8 #endif
      9
      10 #include "cv.h"
      11 #include "highgui.h"
      12
      13
      14 //色相飽和度直方圖
      15 void CalcHistHs()
      16 {
      17 IplImage* img_source;
      18
      19 if (img_source = cvLoadImage("flower.jpg",1))
      20 {
      21 IplImage* hsv = cvCreateImage(cvGetSize(img_source),8,3);
      22
      23 //rgb色彩空間轉(zhuǎn)換到hsv色彩空間
      24 cvCvtColor(img_source,hsv,CV_BGR2HSV);
      25 cvNamedWindow( "hsv", 1 );
      26 cvShowImage( "hsv", hsv );
      27
      28 IplImage* h_plane = cvCreateImage(cvGetSize(img_source),8,1);
      29 IplImage* s_plane = cvCreateImage(cvGetSize(img_source),8,1);
      30 IplImage* v_plane = cvCreateImage(cvGetSize(img_source),8,1);
      31
      32 IplImage* planes[] ={h_plane,s_plane};
      33 //分割為單通道圖像
      34 cvCvtPixToPlane(hsv,h_plane,s_plane,v_plane,0);
      35 cvNamedWindow( "h_plane", 1 );
      36 cvShowImage( "h_plane", h_plane );
      37 cvNamedWindow( "s_plane", 1 );
      38 cvShowImage( "s_plane", s_plane );
      39 cvNamedWindow( "v_plane", 1 );
      40 cvShowImage( "v_plane", v_plane );
      41
      42
      43 //build the histogram and compute its contents
      44
      45 /** H 分量劃分為30個(gè)等級(jí),S分量劃分為32個(gè)等級(jí) */
      46 int h_bins =30, s_bins = 32;
      47
      48 CvHistogram* hist;
      49
      50 {
      51 int hist_size[] = {h_bins,s_bins};
      52 float h_ranges[] = {0,180}; /* hue varies from 0 (~0°red) to 180 (~360°red again) */
      53
      54 float s_ranges[] = {0,255}; /* saturation varies from 0 (black-gray-white) to 255 (pure spectrum color) */
      55
      56 float* ranges[] = {h_ranges,s_ranges};
      57
      58 /** 創(chuàng)建直方圖,二維, 每個(gè)維度上均分 */
      59 hist = cvCreateHist(
      60 2, // int dims
      61 hist_size, // int* sizes
      62 CV_HIST_ARRAY, // int type
      63 ranges, // float** ranges
      64 1 //uniform
      65 );
      66 }
      67
      68 // 根據(jù)H,S兩個(gè)平面數(shù)據(jù)統(tǒng)計(jì)直方圖
      69 cvCalcHist( planes, hist, 0, 0 );
      70 //歸一化處理
      71 cvNormalizeHist(hist,1.0);
      72 /** 獲取直方圖統(tǒng)計(jì)的最大值,用于動(dòng)態(tài)顯示直方圖 */
      73 float max_value;
      74 cvGetMinMaxHistValue( hist, 0, &max_value, 0, 0 );
      75
      76 int scale=10;
      77 //創(chuàng)建直方圖圖像
      78 /** 設(shè)置直方圖顯示圖像 */
      79 int height = 240;
      80 int width = (h_bins*s_bins*6);
      81 IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
      82 cvZero( hist_img );
      83
      84 /** 用來進(jìn)行HSV到RGB顏色轉(zhuǎn)換的臨時(shí)單位圖像 */
      85 IplImage * hsv_color = cvCreateImage(cvSize(1,1),8,3);
      86 IplImage * rgb_color = cvCreateImage(cvSize(1,1),8,3);
      87 int bin_w = width / (h_bins * s_bins);
      88 for(int h = 0; h < h_bins; h++)
      89 {
      90 for(int s = 0; s < s_bins; s++)
      91 {
      92 int i = h*s_bins + s;
      93 /** 獲得直方圖中的統(tǒng)計(jì)次數(shù),計(jì)算顯示在圖像中的高度 */
      94 float bin_val = cvQueryHistValue_2D( hist, h, s );
      95 int intensity = cvRound(bin_val*height/max_value);
      96
      97 /** 獲得當(dāng)前直方圖代表的顏色,轉(zhuǎn)換成RGB用于繪制 */
      98 cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,255,0));
      99 cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);
      100 CvScalar color = cvGet2D(rgb_color,0,0);
      101
      102 cvRectangle( hist_img, cvPoint(i*bin_w,height),
      103 cvPoint((i+1)*bin_w,height - intensity),
      104 color, -1, 8, 0 );
      105 }
      106 }
      107
      108 cvNamedWindow( "Source", 1 );
      109 cvShowImage( "Source", img_source );
      110
      111 cvNamedWindow( "H-S Histogram", 1 );
      112 cvShowImage( "H-S Histogram", hist_img );
      113
      114
      115
      116
      117 }
      118
      119 }
      120
      121 void CalcHistRgb()
      122 {
      123 IplImage* img_source;
      124
      125 if (img_source = cvLoadImage("flower.jpg",1))
      126 {
      127 IplImage* RedChannel = cvCreateImage( cvGetSize(img_source), 8, 1);
      128 IplImage* GreenChannel = cvCreateImage( cvGetSize(img_source), 8, 1);
      129 IplImage* BlueChannel = cvCreateImage( cvGetSize(img_source), 8, 1);
      130 IplImage* alphaChannel = cvCreateImage( cvGetSize(img_source), 8, 1);
      131 IplImage* gray_plane = cvCreateImage(cvGetSize(img_source),8,1);
      132
      133
      134 //分割為單通道圖像
      135 cvCvtPixToPlane(img_source,BlueChannel,GreenChannel,RedChannel,0);
      136 // 顯示圖像
      137 cvNamedWindow( "RedChannel", 1 );
      138 cvNamedWindow( "GreenChannel", 1 );
      139 cvNamedWindow( "BlueChannel", 1 );
      140 cvNamedWindow( "lphaChannel", 1 );
      141
      142 cvShowImage( "RedChannel", RedChannel );
      143 cvShowImage( "GreenChannel", GreenChannel );
      144 cvShowImage( "BlueChannel", BlueChannel );
      145 cvShowImage( "lphaChannel", alphaChannel );
      146
      147
      148 cvCvtColor(img_source,gray_plane,CV_BGR2GRAY);
      149 cvNamedWindow("GrayPlane",1);
      150 cvShowImage("GrayPlane",gray_plane);
      151 //OpenCV中不管是Windows中Load的還是攝像頭取得的都是BGR順序排列的
      152
      153 //然后為這四幅圖創(chuàng)建對(duì)應(yīng)的直方圖結(jié)構(gòu)。
      154 int hist_size = 100;
      155
      156 int hist_height = 100;
      157
      158 float range[] = {0,255};
      159
      160 float* ranges[]={range};
      161
      162 CvHistogram* r_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
      163
      164 CvHistogram* g_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
      165
      166 CvHistogram* b_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
      167
      168 CvHistogram* gray_hist = cvCreateHist(1,&hist_size,CV_HIST_ARRAY,ranges,1);
      169
      170 //接下來計(jì)算直方圖,創(chuàng)建用于顯示直方圖的圖像,略去了一部分重復(fù)代碼,以下也是
      171
      172 cvCalcHist(&RedChannel,r_hist,0,0);
      173 cvCalcHist(&GreenChannel,g_hist,0,0);
      174 cvCalcHist(&BlueChannel,b_hist,0,0);
      175 cvCalcHist(&gray_plane,gray_hist,0,0);
      176 cvNormalizeHist(gray_hist,1.0);
      177 cvNormalizeHist(r_hist,1.0);
      178 cvNormalizeHist(g_hist,1.0);
      179 cvNormalizeHist(b_hist,1.0);
      180
      181 int scale = 2;
      182
      183 IplImage* hist_image = cvCreateImage(cvSize(hist_size*scale,hist_height*4),8,3);
      184
      185 cvZero(hist_image);
      186
      187 //然后開始顯示,這里對(duì)直方圖進(jìn)行了標(biāo)準(zhǔn)化處理,不然的話無法觀察到明顯的變化。
      188
      189 float r_max_value = 0;
      190 float g_max_value = 0;
      191 float b_max_value = 0;
      192 float gray_max_value = 0;
      193 cvGetMinMaxHistValue(r_hist, 0,&r_max_value,0,0);
      194 cvGetMinMaxHistValue(g_hist, 0,&g_max_value,0,0);
      195 cvGetMinMaxHistValue(b_hist, 0,&b_max_value,0,0);
      196 cvGetMinMaxHistValue(b_hist, 0,&gray_max_value,0,0);
      197 for(int i=0;i<hist_size;i++)
      198 {
      199
      200 float r_bin_val = cvQueryHistValue_1D(r_hist,i);
      201
      202 int r_intensity = cvRound(r_bin_val*hist_height/r_max_value);
      203 cvRectangle(
      204 hist_image,
      205 cvPoint(i*scale,hist_height-1),
      206 cvPoint((i+1)*scale - 1, hist_height - r_intensity),
      207 CV_RGB(255,0,0));
      208
      209 float g_bin_val=cvQueryHistValue_1D(g_hist,i);
      210 int g_intensity = cvRound(g_bin_val*hist_height/g_max_value);
      211 cvRectangle(
      212 hist_image,
      213 cvPoint(i*scale,2*hist_height-1),
      214 cvPoint((i+1)*scale - 1, 2*hist_height - g_intensity),
      215 CV_RGB(0,255,0));
      216
      217 float b_bin_val = cvQueryHistValue_1D(b_hist,i);
      218 int b_intensity = cvRound(b_bin_val*hist_height/b_max_value);
      219 cvRectangle(
      220 hist_image,
      221 cvPoint(i*scale,3*hist_height-1),
      222 cvPoint((i+1)*scale - 1, 3*hist_height - b_intensity),
      223 CV_RGB(0,0,255));
      224
      225 float gray_bin_val = cvQueryHistValue_1D(gray_hist,i);
      226 int gray_intensity = cvRound(gray_bin_val*hist_height/gray_max_value);
      227 cvRectangle(
      228 hist_image,
      229 cvPoint(i*scale,4*hist_height-1),
      230 cvPoint((i+1)*scale - 1, 4*hist_height - gray_intensity),
      231 CV_RGB(100,100,100));
      232
      233 }
      234 cvNamedWindow( "Source", 1 );
      235 cvShowImage( "Source", img_source );
      236
      237 cvNamedWindow( "RGB_Histogram", 1 );
      238 cvShowImage( "RGB_Histogram", hist_image );
      239
      240
      241 }
      242
      243 }
      244
      245 int main()
      246 {
      247 CalcHistRgb();
      248 CalcHistHs();
      249 cvWaitKey(0);
      250 }
      復(fù)制代碼

      直方圖對(duì)比

      OpenCv提供了5種對(duì)比直方圖的方式:CORREL(相關(guān))、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA、EMD(最小工作距離),其中CHISQR速度最快,EMD速度最慢且有諸多限制,但是EMD的效果最好。世界總是充滿了矛盾,而我們的工作就是化解矛盾,把每種方式都測(cè)試一下,找到正好能解決問題并且速度最優(yōu)的方法。
       需要注意的是:EMD方式要求先將直方圖轉(zhuǎn)換成矩陣:
      EMD方法會(huì)占用很很很大量的內(nèi)存,在使用前請(qǐng)注意直方圖的維數(shù)及區(qū)間數(shù)目,不然會(huì)出現(xiàn)內(nèi)存不足的異常。關(guān)于這點(diǎn),請(qǐng)參看我的另一篇文章《關(guān)于使用cvCalcEMD2計(jì)算兩個(gè)直方圖間最小工作距離的限制(Why cvCalcEMD2 Throw Insufficient Memory Exception)》。還有一點(diǎn)值得注意的是,不同的對(duì)比方式對(duì)待結(jié)果的方式很不一樣,結(jié)果越大不一定說明匹配度更高,具體請(qǐng)參看《學(xué)習(xí)OpenCv》這本書的相關(guān)章節(jié)。

      對(duì)于直方圖的相關(guān)和相交對(duì)比,結(jié)果值越大(即亮度較高)的地方表示匹配程度越高;
      對(duì)于直方圖的卡方、Bhattacharyya、EMD對(duì)比,結(jié)果值越小(即越黑暗)的地方表示匹配程度越高。

      陸地移動(dòng)距離EMD

      光線能引起圖像顏色值的漂移,盡管這些漂移沒有改變顏色直方圖的形狀,但是這些漂移引起了顏色值位置的變化,從而導(dǎo)致前述匹配策略失效。如果利用顏色直方圖的距離測(cè)量來代替直方圖的匹配策略,那么我們?nèi)匀豢梢韵裰狈綀D對(duì)比一樣對(duì)比兩個(gè)直方圖的距離,即使第二個(gè)直方圖發(fā)生漂移,也能找到最小的距離度量。

      陸地移動(dòng)距離時(shí)一種度量準(zhǔn)則,它實(shí)際上度量的是怎樣將一個(gè)直方圖的形狀轉(zhuǎn)變?yōu)榱硪粋€(gè)直方圖的形狀,包括移動(dòng)直方圖的部分或者全部到一個(gè)新的位置,可以在任何維的直方圖上進(jìn)行這種度量。

      0表示最精確匹配,半匹配是成功將直方圖的一半轉(zhuǎn)換,將左邊直方圖的一半轉(zhuǎn)換到下一個(gè)直方圖。最終移動(dòng)整個(gè)直方圖到右邊需要整個(gè)單位的距離(即將模板直方圖轉(zhuǎn)換為完全不匹配直方圖)。1表示完全不匹配。

      具體代碼如下:

      View Code
      復(fù)制代碼
       1 int main()
      2 {
      3 /*CalcHistHs("flower.jpg");
      4 CvHistogram* hist1 = CalcHistRgb("flower.jpg");
      5 CvHistogram* hist2 = CalcHistRgb("flower3.jpg");
      6
      7 double result = cvCompareHist(hist1,hist2,CV_COMP_CORREL);
      8 cout<< result;
      9
      10 cvWaitKey(0);*/
      11
      12 IplImage *src = cvLoadImage("flower.jpg");
      13 IplImage *hsv = cvCreateImage(cvGetSize(src),8,3);
      14 cvCvtColor(src,hsv,CV_BGR2HSV);// change RGB of src to HSV of hsv
      15 IplImage *h_plane = cvCreateImage(cvGetSize(src),8,1);
      16 IplImage *s_plane = cvCreateImage(cvGetSize(src),8,1);
      17 IplImage *v_plane = cvCreateImage(cvGetSize(src),8,1);
      18 IplImage *planes[]={h_plane,s_plane};
      19 cvSplit(hsv,h_plane,s_plane,v_plane,0);//split HSV to 3 channal
      20
      21 //求得直方圖
      22 int h_bins=30,s_bins=32;
      23 CvHistogram *hist1,*hist2;
      24 int size[]={h_bins,s_bins};
      25 float h_ranges[]={0,180};
      26 float s_ranges[]={0,255};
      27 float *ranges[]={h_ranges,s_ranges};
      28
      29 hist1=cvCreateHist(2,size,CV_HIST_ARRAY,ranges,1);
      30 cvCalcHist(planes,hist1,0,0);//只能一個(gè)通道一個(gè)通道的寫入直方圖,所以上面分成H、S、V
      31 cvNormalizeHist(hist1,1.0);//歸一化直方圖,使所有塊的值加起來為1
      32 hist2=cvCreateHist(2,size,CV_HIST_ARRAY,ranges,1);
      33 cvCalcHist(planes,hist2,0,0);
      34 cvNormalizeHist(hist2,1.0);
      35
      36 //求得signature用于比較直方圖
      37 CvMat *sig1,*sig2;
      38 int numrows=h_bins*s_bins;
      39 sig1=cvCreateMat(numrows,3,CV_32FC1);//由于是2維圖像直方圖,所以只需保存每個(gè)點(diǎn)的(值,橫坐標(biāo),縱坐標(biāo))三個(gè)數(shù),一共numrows個(gè)點(diǎn)
      40 sig2=cvCreateMat(numrows,3,CV_32FC1);
      41 for(int h=0;h<h_bins;h++)
      42 {
      43 for(int s=0;s<s_bins;s++)
      44 {
      45 float bin_val=cvQueryHistValue_2D(hist1,h,s);
      46 cvSet2D(sig1,h*s_bins+s,0,cvScalar(bin_val));
      47 cvSet2D(sig1,h*s_bins+s,1,cvScalar(h));
      48 cvSet2D(sig1,h*s_bins+s,2,cvScalar(s));
      49 bin_val=cvQueryHistValue_2D(hist2,h,s);
      50 cvSet2D(sig2,h*s_bins+s,0,cvScalar(bin_val));
      51 cvSet2D(sig2,h*s_bins+s,1,cvScalar(h));
      52 cvSet2D(sig2,h*s_bins+s,2,cvScalar(s));
      53 }
      54 }
      55 float emd=cvCalcEMD2(sig1,sig2,CV_DIST_L2);
      56 cout<<emd;//可以清楚的看出因?yàn)槲覍?duì)比同一個(gè)圖像直方圖,所以得數(shù)0是對(duì)的,完全一樣
      57 cvWaitKey(0);
      58 return 0;
      59
      60
      61 }
      復(fù)制代碼


      直方圖的反向投影

      我對(duì)于反向投影的理解是通過顏色直方圖,檢測(cè)圖片中的某個(gè)像素點(diǎn)的顏色是否位于直方圖中,若位于則將其加亮(閥值化?),通過對(duì)圖像的檢測(cè),得出結(jié)果圖像。如果照著我這個(gè)理解的話,那么對(duì)同一物體的顏色的取樣點(diǎn)越多,那么越能更好的找出目標(biāo)圖形(當(dāng)然,這很可能也會(huì)帶來一些不需要的點(diǎn),那么這個(gè)方法應(yīng)該對(duì)于對(duì)比度較大的圖像比較有效……)
      換個(gè)說法就是在反向投影中,直方圖的作用在于提供一個(gè)比較標(biāo)準(zhǔn),即對(duì)于要檢測(cè)的圖像來說,需要給它提供一個(gè)用于識(shí)別出它需要被識(shí)別出的部分的直方圖。

      1.反向投影的作用是什么?
          反向投影用于在輸入圖像(通常較大)中查找特定圖像(通常較小或者僅1個(gè)像素,以下將其稱為模板圖像)最匹配的點(diǎn)或者區(qū)域,也就是定位模板圖像出現(xiàn)在輸入圖像的位置。
      2.反向投影如何查找(工作)?
          查找的方式就是不斷的在輸入圖像中切割跟模板圖像大小一致的圖像塊,并用直方圖對(duì)比的方式與模板圖像進(jìn)行比較。

      假設(shè)我們有一張100x100的輸入圖像,有一張10x10的模板圖像,查找的過程是這樣的:
      (1)從輸入圖像的左上角(0,0)開始,切割一塊(0,0)至(10,10)的臨時(shí)圖像;
      (2)生成臨時(shí)圖像的直方圖;
      (3)用臨時(shí)圖像的直方圖和模板圖像的直方圖對(duì)比,對(duì)比結(jié)果記為c;
      (4)直方圖對(duì)比結(jié)果c,就是結(jié)果圖像(0,0)處的像素值;
      (5)切割輸入圖像從(0,1)至(10,11)的臨時(shí)圖像,對(duì)比直方圖,并記錄到結(jié)果圖像;
      (6)重復(fù)(1)~(5)步直到輸入圖像的右下角。

      直方圖反向投影示意圖

      3.反向投影的結(jié)果是什么?
          反向投影的結(jié)果包含了:以每個(gè)輸入圖像像素點(diǎn)為起點(diǎn)的直方圖對(duì)比結(jié)果??梢园阉闯墒且粋€(gè)二維的浮點(diǎn)型數(shù)組,二維矩陣,或者單通道的浮點(diǎn)型圖像。
      4.特殊情況怎么樣?
          如果輸入圖像和模板圖像一樣大,那么反向投影相當(dāng)于直方圖對(duì)比。如果輸入圖像比模板圖像還小,直接罷工~~。
      5.使用時(shí)有什么要注意的地方?
          需要注意的地方比較多,我們對(duì)照反向投影函數(shù)來說:
          void cvCalcBackProjectPatch(
              IplImage** image,   /*輸入圖像:是一個(gè)單通道圖像數(shù)組,而非實(shí)際圖像*/
              CvArr* dst,         /*輸出結(jié)果:是一個(gè)單通道32位浮點(diǎn)圖像,它的寬度為W-w+1,高度為H-h+1,這里的W和H是輸入圖像的寬度和高度,w和h是模板圖像的寬度和高度*/
              CvSize patch_size,  /*模板圖像的大?。簩挾群透叨?/
              CvHistogram* hist,  /*模板圖像的直方圖:直方圖的維數(shù)和輸入圖像的個(gè)數(shù)相同,并且次序要一致;例如:輸入圖像包含色調(diào)和飽和度,那么直方圖的第0維是色調(diào),第1維是飽和度*/
              int method,         /*對(duì)比方式:跟直方圖對(duì)比中的方式類似,可以是:CORREL(相關(guān))、CHISQR(卡方)、INTERSECT(相交)、BHATTACHARYYA*/
              float factor        /*歸一化因子,一般都設(shè)置成1,否則很可能會(huì)出錯(cuò);中文、英文以及各路轉(zhuǎn)載的文檔都錯(cuò)了,這個(gè)參數(shù)的實(shí)際類型是double,而非float,我看了源代碼才搞定這個(gè)地方*/
          );
          還有最需要注意的地方:這個(gè)函數(shù)的執(zhí)行效率非常的低,在使用之前尤其需要注意圖像的大小,直方圖的維數(shù),對(duì)比方式。如果說對(duì)比單個(gè)直方圖對(duì)現(xiàn)在的電腦來說是清風(fēng)拂面,那么反向投影是狂風(fēng)海嘯。對(duì)于1010x1010的RGB輸入圖像,10x10的模板圖像,需要生成1百萬次3維直方圖,對(duì)比1百萬次3維直方圖。

       下面為具體代碼:

      View Code
      復(fù)制代碼
        1 #include <cv.h>
      2 #include <highgui.h>
      3
      4
      5 int main()
      6 {
      7 IplImage* src = cvLoadImage("./sample1.jpg");
      8 if (src != NULL)
      9 {
      10 IplImage* hsv = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 3);
      11 //將bgr圖像轉(zhuǎn)化為hsv圖像
      12 cvCvtColor(src, hsv, CV_BGR2HSV);
      13
      14
      15 //創(chuàng)建3個(gè)單通道的圖像,用于將hsv圖像分離為3個(gè)通道
      16 IplImage* h = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
      17 IplImage* s = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
      18 IplImage* v = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
      19 IplImage* planes[] = {h, s};
      20 //將hsv圖像分離
      21 cvCvtPixToPlane(hsv, h, s, v, 0);
      22
      23
      24 //在h通道上設(shè)定30個(gè)劃分度,在s通道上設(shè)定32個(gè)劃分度
      25 int h_bins(30), s_bins(32);
      26 CvHistogram* hist;
      27 {
      28 int hist_size[] = {h_bins, s_bins};
      29 float h_ranges[] = {0, 180};
      30 float s_ranges[] = {0, 255};
      31 //將h通道上的范圍,即[0,180],以及s通道上的范圍,即[0,255]組織成函數(shù)cvCreateHist所需
      32 //的形式
      33 float* ranges[] = {h_ranges, s_ranges};
      34 //創(chuàng)建一個(gè)2維的、h維上劃分度為30、s維上劃分度為32的均分直方圖
      35 hist = cvCreateHist(2, hist_size, CV_HIST_ARRAY, ranges, 1);
      36 }
      37 //通過源圖像上的h與s通道上圖像數(shù)據(jù)統(tǒng)計(jì)出直方圖
      38 cvCalcHist(planes, hist, 0, 0);
      39 //獲取得到的直方圖的所有數(shù)據(jù)的和
      40 CvScalar sc = cvSum(hist->bins);
      41 float sum = sc.val[0] + sc.val[1] + sc.val[2] + sc.val[3];
      42 //歸一化直方圖
      43 cvNormalizeHist(hist, 1.0);
      44 //scale:每一個(gè)劃分在用于顯示的圖像上所占的像素點(diǎn)數(shù)
      45 int scale = 10;
      46 IplImage* img = cvCreateImage(cvSize(h_bins * scale, s_bins * scale), IPL_DEPTH_8U, 3);
      47 cvZero(img);
      48
      49
      50 //為什么要求最大值呢?由于歸一化之后的圖像中的像素點(diǎn)的值都不會(huì)大于1,那么在人眼看來都是黑
      51 //色的一片,沒法通過圖像來直觀的感受直方圖了,所以在下邊會(huì)通過將直方圖的值和直方圖中的最大
      52 //值做除法,再乘以255,使人眼能看出直方圖中數(shù)值的變化……如下代碼對(duì)應(yīng)直方圖2
      53 float max_value = 0;
      54 cvGetMinMaxHistValue(hist, NULL, &max_value, 0, 0);
      55 for (int h = 0; h < h_bins; ++h)
      56 {
      57 for (int s = 0; s < s_bins; ++s)
      58 {
      59 //訪問直方圖在關(guān)于h與s所確定的顏色的數(shù)值
      60 float bin_val = cvQueryHistValue_2D(hist, h, s);
      61 int intensity = cvRound(bin_val * 255 / max_value);
      62 cvRectangle(img,
      63 cvPoint(h * scale, s * scale),
      64 cvPoint((h + 1) * scale - 1, (s + 1) * scale - 1),
      65 CV_RGB(intensity, intensity, intensity),
      66 CV_FILLED);
      67 }
      68 }
      69
      70
      71 //如下代碼對(duì)應(yīng)直方圖1
      72 int height = 240;
      73 int width = (h_bins*s_bins*6);
      74 IplImage* hist_img = cvCreateImage( cvSize(width,height), 8, 3 );
      75 cvZero( hist_img );
      76
      77 IplImage * hsv_color = cvCreateImage(cvSize(1,1),8,3);
      78 IplImage * rgb_color = cvCreateImage(cvSize(1,1),8,3);
      79 int bin_w = width / (h_bins * s_bins);
      80 for(int h = 0; h < h_bins; h++)
      81 {
      82 for(int s = 0; s < s_bins; s++)
      83 {
      84 int i = h*s_bins + s;
      85
      86 float bin_val = cvQueryHistValue_2D( hist, h, s );
      87 int intensity = cvRound(bin_val*height/max_value);
      88
      89 cvSet2D(hsv_color,0,0,cvScalar(h*180.f / h_bins,s*255.f/s_bins,255,0));
      90 //hsv顏色轉(zhuǎn)化為bgr顏色
      91 cvCvtColor(hsv_color,rgb_color,CV_HSV2BGR);
      92 CvScalar color = cvGet2D(rgb_color,0,0);
      93 //IplImage類型指定的圖像原點(diǎn)在左上角,所以要實(shí)現(xiàn)圖中的效果,矩形的兩個(gè)頂角應(yīng)像下邊
      94 //代碼中設(shè)置
      95 cvRectangle( hist_img, cvPoint(i*bin_w,height),
      96 cvPoint((i+1)*bin_w,height - intensity),
      97 color, -1, 8, 0 );
      98 }
      99 }
      100 cvNamedWindow( "H-S Histogram", 1 );
      101 cvShowImage( "H-S Histogram", hist_img );
      102 cvNamedWindow("src");
      103 cvShowImage("src", src);
      104 cvNamedWindow("img");
      105 cvShowImage("img", img);
      106
      107
      108 IplImage* img2 = cvLoadImage("./sample2.jpg");
      109 IplImage* hsv2 = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 3);
      110 cvCvtColor(img2, hsv2, CV_BGR2HSV);
      111 IplImage* h2 = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 1);
      112 IplImage* s2 = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 1);
      113 IplImage* v2 = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 1);
      114 IplImage* planes2[] = {h2, s2};
      115 cvCvtPixToPlane(hsv2, h2, s2, v2, 0);
      116 //cvCvtPixToPlane(img2, h2, s2, v2, 0);
      117 IplImage* backProject = cvCreateImage(cvGetSize(img2), IPL_DEPTH_8U, 1);
      118 cvSetZero(backProject);
      119 cvNormalizeHist(hist, sum);
      120 cvCalcBackProject(planes2, backProject, hist);
      121
      122
      123 cvNamedWindow("img2");
      124 cvShowImage("img2", img2);
      125 cvNamedWindow("back project");
      126 cvShowImage("back project", backProject);
      127
      128
      129 //釋放資源
      130 cvWaitKey(0);
      131 cvDestroyAllWindows();
      132 cvReleaseImage(&src);
      133 cvReleaseImage(&img);
      134 cvReleaseImage(&backProject);
      135 cvReleaseImage(&img2);
      136 cvReleaseHist(&hist);
      137 }
      138
      139
      140 return 0;
      141 }
      復(fù)制代碼

      模板匹配(Match Template) 修改版

      模板匹配的工作方式
          模板匹配的工作方式跟直方圖的反向投影基本一樣,大致過程是這樣的:通過在輸入圖像上滑動(dòng)圖像塊對(duì)實(shí)際的圖像塊和輸入圖像進(jìn)行匹配。
          假設(shè)我們有一張100x100的輸入圖像,有一張10x10的模板圖像,查找的過程是這樣的:
        (1)從輸入圖像的左上角(0,0)開始,切割一塊(0,0)至(10,10)的臨時(shí)圖像;(改者注:其實(shí)每次匹配都是在模板的中心點(diǎn)對(duì)應(yīng)的位置來給像素賦值,即第一次比較應(yīng)該是將模板的(temp.width/2,temp.height/2)中心點(diǎn)開始的1/4面積同輸入圖像進(jìn)行比較,匹配得到的結(jié)果c保存到模板中心點(diǎn)所在像素值中,具體參照《Learning OpenCV》,所以最終用來保留匹配結(jié)果的圖像大小應(yīng)該是size =  (images->width - patch_size.x + 1,images->height - patch_size.y + 1))

        (2)用臨時(shí)圖像和模板圖像進(jìn)行對(duì)比,對(duì)比結(jié)果記為c;
        (3)對(duì)比結(jié)果c,就是結(jié)果圖像(0,0)處的像素值;
        (4)切割輸入圖像從(0,1)至(10,11)的臨時(shí)圖像,對(duì)比,并記錄到結(jié)果圖像;
        (5)重復(fù)(1)~(4)步直到輸入圖像的右下角。
          大家可以看到,直方圖反向投影對(duì)比的是直方圖,而模板匹配對(duì)比的是圖像的像素值;模板匹配比直方圖反向投影速度要快一些,但是我個(gè)人認(rèn)為直方圖反向投影的魯棒性會(huì)更好。

       

      模板匹配的匹配方式
          在OpenCv和EmguCv中支持以下6種對(duì)比方式:
          CV_TM_SQDIFF 平方差匹配法:該方法采用平方差來進(jìn)行匹配;最好的匹配值為0;匹配越差,匹配值越大。
          CV_TM_CCORR 相關(guān)匹配法:該方法采用乘法操作;數(shù)值越大表明匹配程度越好。
          CV_TM_CCOEFF 相關(guān)系數(shù)匹配法:1表示完美的匹配;-1表示最差的匹配。
          CV_TM_SQDIFF_NORMED 歸一化平方差匹配法
          CV_TM_CCORR_NORMED 歸一化相關(guān)匹配法
          CV_TM_CCOEFF_NORMED 歸一化相關(guān)系數(shù)匹配法
          根據(jù)我的測(cè)試結(jié)果來看,上述幾種匹配方式需要的計(jì)算時(shí)間比較接近(跟《學(xué)習(xí)OpenCv》書上說的不同),我們可以選擇一個(gè)能適應(yīng)場(chǎng)景的匹配方式。

      具體代碼:

      View Code
      復(fù)制代碼
       1 int main( int argc, char** argv ) {
      2
      3 IplImage *src, *templ,*ftmp[6]; //ftmp is what to display on
      4 int i;
      5
      6 //Read in the template to be used for matching:
      7 if((templ=cvLoadImage("flower1.jpg", 1))== 0) {
      8 printf("Error on reading template /n");
      9 return(-1);
      10 }
      11
      12 //Read in the source image to be searched:
      13 if((src=cvLoadImage("flower.jpg", 1))== 0) {
      14 printf("Error on reading src image /n");
      15 return(-1);
      16 }
      17
      18 int patchx = templ->width;
      19 int patchy = templ->height;
      20 int iwidth = src->width - patchx + 1;
      21 int iheight = src->height - patchy + 1;
      22 for(i=0; i<6; ++i){
      23 ftmp[i] = cvCreateImage( cvSize(iwidth,iheight),32,1);
      24 }
      25
      26 //DO THE MATCHING OF THE TEMPLATE WITH THE IMAGE
      27 for(i=0; i<6; ++i){
      28 cvMatchTemplate( src, templ, ftmp[i], i);
      29 // double min,max;
      30 // cvMinMaxLoc(ftmp,&min,&max);
      31 cvNormalize(ftmp[i],ftmp[i],1,0,CV_MINMAX);
      32 }
      33 //DISPLAY
      34 cvNamedWindow( "Template", 0 );
      35 cvShowImage( "Template", templ );
      36 cvNamedWindow( "Image", 0 );
      37 cvShowImage( "Image", src );
      38
      39 cvNamedWindow( "SQDIFF", 0 );
      40 cvShowImage( "SQDIFF", ftmp[0] );
      41
      42 cvNamedWindow( "SQDIFF_NORMED", 0 );
      43 cvShowImage( "SQDIFF_NORMED", ftmp[1] );
      44
      45 cvNamedWindow( "CCORR", 0 );
      46 cvShowImage( "CCORR", ftmp[2] );
      47
      48 cvNamedWindow( "CCORR_NORMED", 0 );
      49 cvShowImage( "CCORR_NORMED", ftmp[3] );
      50
      51 cvNamedWindow( "CCOEFF", 0 );
      52 cvShowImage( "CCOEFF", ftmp[4] );
      53
      54 cvNamedWindow( "CCOEFF_NORMED", 0 );
      55 cvShowImage( "CCOEFF_NORMED", ftmp[5] );
      56
      57
      58 //LET USER VIEW RESULTS:
      59 cvWaitKey(0);
      60
      61 return 0;
      62 }
      復(fù)制代碼

      感謝您耐心看完本文,希望對(duì)您有所幫助。

        本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
        轉(zhuǎn)藏 分享 獻(xiàn)花(0

        0條評(píng)論

        發(fā)表

        請(qǐng)遵守用戶 評(píng)論公約

        類似文章 更多