2008年10月23日 星期四

OpenCV 1.1

新版的OpenCV 1.1 ,在2008年10月15號發佈,基本上只是優化前一版的內容,刪除了cvcam函式庫,並且提供了一本歐萊里的工具書
http://sourceforge.net/project/showfiles.php?group_id=22870


Notes:

This is OpenCV 1.1pre1, the first intermediate update after 1.0.It features better stereo support, SURF features, better performance of some functions, DirectShow support in highgui etc. It also includes many bug-fixes.

Changes:

>>> New functionality/features: <<<

    - General:

        * Octave bindings have been added. See interfaces/swig/octave
         (for now, Linux only)

        * [Windows] OpenCV is now built with VS2005 with SSE2 and OpenMP support included
         (if you want to rebuild OpenCV using Express or Standard Edition of VS, use
         _make\opencv.vs2005.no_openmp.sln).

        * [Windows] Python bindings have been updated to use Python 2.6

        * [Windows] cvcam has been removed (as videoInput is now supported by highgui)

    - CXCORE, CV, CVAUX:

        * Speeded-up Robust Features (SURF), contributed by Liu Liu.
         see samples/c/find_obj.cpp and the documentation opencvref_cv.htm

        * Many improvements in camera calibration:
            - Added stereo camera calibration: cvStereoCalibrate, cvStereoRectify etc.
            - Single camera calibration now uses Levenberg-Marquardt method and supports extra flags to
             switch on/off optimization of individual camera parameters
            - The optional 3rd radial distortion parameter (k3*r^6) is now supported in every calibration-related
             function

        * 2 stereo correspondence algorithms:
            - very fast block matching method by Kurt Konolige
             (processes the Tsukuba stereo pair in <10ms on Core2Duo laptop)
            - slow but more accurate graph-cut based algorithm by Kolmogorov and Zabin

        * Better homography estimation algorithms (RANSAC and LMEDs)

        * new C++ template image classes contributed by Daniel Filip (Google inc.). see
            opencv/cxcore/include/cvwimage.h

        * Fast approximate nearest neighbor search (by Xavier Delacour)

        * Codebook method for background/foreground segmentation (by Gary Bradski)

        * Sort function (contributed by Shiqi Yu)

        * [OpenCV+IPP] Face Detection (cvHaarDetectObjects) now runs much faster (up to 2x faster) when
            using IPP 5.3 or higher.

        * Much faster (~4x faster) fixed-point variant of cvRemap has been added

    - MLL:

        * Python bindings for MLL have been added. There are no samples yet.

    - HighGUI:

        * [Windows, 32bit] Added support for videoInput library. Hence, cvcam is [almost] not needed anymore

        * [Windows, 32bit] FFMPEG can now be used for video decoding/encoding via ffopencv*.dll

        * [Linux] Added unicap support

        * Improved internal video capturing and video encoding APIs

    - Documentation:

        * OpenCV book has been published (sold separately :) see docs/index.htm)

        - New samples (opencv/samples):

        * Many Octave samples

        * find_obj.cpp (SURF), bgfg_codebook.cpp (Codebook BG/FG segmentation), stereo_calib.cpp
            (Stereo calibration and stereo correspondence)

>>> Bug fixes: <<<

    Many thanks to everybody who submitted bug reports and/or provided the patches!

    * added dma_unlisten to icvCloseCAM_DC1394 (thanks to Victor Benso)

    * LMEDs algorithm for cvFindFundamentalMat estimation has been fixed

    * Broken debug build of highgui in VS2005/2008 (SF #2056185, SF #1709435)

    * cvFindChessboardCorners memory leak and incorrect size checks
    (SF #1972896, SF #1910323)

    * disabling GTK causes v4l runtime error (SF #2088102)

    * cvsetmousecallback bug (SF #2053529)

    * libhighgui needed deprecated "img_convert" replacement (SF #2011753)

    * Segfault in createsamples caused by uninitialized variable (SF #1977989)

    * Data Alignment Issue in bgfg_gaussmix (SF #1961755)

    * libpng need to be updated (SF #1952793)

    * cvCreateVideoWriter_Win32 - identifier not found (SF #1944254)

    * Bug in cvmorph.cpp (SF #1908844)

    * dilate (cvDilate) works bogus with default kernel (SF #1887130)

    * CvEM non-default constructor declared but not defined (SF #1830346)

    * cvFloodFill (in ver 1.0) Hangs (SF #1790565)

    * double delete in CvImage (SF #1733437)

    * cvFilter2D anchor default value is not working properly (SF #1713779)

    * cvCvtColor - Bug? in converting HSV2RGB (SF #1676344)

    * Invalid selection of the MKL-dll version in cvUseOptimized() (SF #1633017)


>>> Known issues:

    * Borland compiler is not supported (but might work) in this update.

    * 64-bit Windows is not supported (but might work) in this update.

    * SF bug tracker still contains over 50 records of open bugs. Many of them will be addressed in the next
     update.




2008年10月19日 星期日

OpenCV統計應用-CvHistogram直方圖資料結構

CvHistogram可以提供直方圖的計算,並且可以支援多個維度的直方圖設計,但是在繪製直方圖圖形的時候就需要自己用繪圖函式來繪製,CvHistogram算是一個比較複雜的資料結構,由於它在維度小於二的可以用密集的資料結構,CvMatND來設計,可以當它的直方圖維度大於二的時候,就必須要用到稀疏矩陣,CvSparseMat的方式,下面就是用CvHistogram結構計算一維直方圖的例子

CvHistogram一維設計
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int HistogramBins = 256;
float HistogramRange1[2]={0,255};
float *HistogramRange[1]={&HistogramRange1[0]};

int main()
{
    IplImage *Image1;
    CvHistogram *Histogram1;
    IplImage *HistogramImage1;

    Image1=cvLoadImage("Riverbank.jpg",0);

    Histogram1 = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
    HistogramImage1 = cvCreateImage(cvSize(256,300),8,3);
    HistogramImage1->origin=1;

    cvCalcHist(&Image1,Histogram1);

    printf("type is : %d\n",Histogram1->type);
    printf("Low Bound is : %.f\n",Histogram1->thresh[0][0]);
    printf("Up Bound is : %.f\n",Histogram1->thresh[0][1]);
    printf("The Bins are : %d\n",((CvMatND *) Histogram1->bins)->dim[0].size);

    printf("\nGray Level Values:\n");
    for(int i=0;i<HistogramBins;i++)
    {
        printf("%.f \n",((CvMatND *) Histogram1->bins)->data.fl[i]);
        cvLine(HistogramImage1,cvPoint(i,0),cvPoint(i,(int)(cvQueryHistValue_1D(Histogram1,i)/10)),CV_RGB(127,127,127));
    }

    cvNamedWindow("Histogram",1);
    cvNamedWindow("Riverbank",1);
    cvShowImage("Riverbank",Image1);
    cvShowImage("Histogram",HistogramImage1);
    cvWaitKey(0);
}

原始圖片:


執行結果:


跟前面直接用矩陣累加設計出的統計直方圖一樣,到最後還是要自己用繪圖函式自己畫,CvHistogram這個資料結構的特色,它可以設定要用幾個區塊來呈現,這邊設立為256個區塊,而實際上,它可以用比較模糊的方式設定直方圖的區域,也就是可以小於256個的區塊數,是利用切割成n等分的方式,然後它可以自行設定上界(Up Bound)以及下界(Low Bound),在灰階圖裡面數據的範圍為0~255,而CvHistogram資料結構可以設立為上界30,下界200這樣的方式縮小範圍,而0~29,201~266這範圍內的數據將不會被計算,下面是CvHistogram資料結構的內容,分別為CV_HIST_ARRAY及CV_HIST_SPARSE兩種

1.


2.


CvHistogram的type固定都為CV_HIST_MAGIC_VAL這的參數,與上面程式cvCreateHist()所設定的CV_HIST_ARRAY無關,這也許是OpenCV裡面對於CvHistogram這個結構設計不良的地方,而對於CvHistogram資料結構的參數,定義如下

#define CV_HIST_ARRAY 0
#define CV_HIST_SPARSE 1
#define CV_HIST_TREE CV_HIST_SPARSE


因此,它的參數只有CV_HIST_ARRAY的多維矩陣CvMatND以及CV_HIST_SPARSE的稀疏矩陣CvSparseMat資料結構,而它的thresh是放上下界的資料,thresh2是放動態的維度上下界資料,而一般的直方圖數據資料都是放在bins裡面.而CvHistogram內的CvMatND結構則是在做快速初始化,bins以及mat都是使用同一個記憶體空間,而將直方圖資料的提取就要用到cvQueryHistValue_1D()這個函式了.

接著是將直方圖的空間分區塊的方式實作,將它分為50塊,並且上界為30,下界為200

CvHistogram結構區塊與上下界
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int HistogramBins = 50;
int HistogramBinWidth;
float HistogramRange1[2]={30,200};
float *HistogramRange[1]={&HistogramRange1[0]};

int main()
{
    IplImage *Image1;
    CvHistogram *Histogram1;
    IplImage *HistogramImage1;
    CvPoint Point1;
    CvPoint Point2;

    Image1=cvLoadImage("Riverbank.jpg",0);

    Histogram1 = cvCreateHist(1,&HistogramBins,CV_HIST_ARRAY,HistogramRange);
    HistogramImage1 = cvCreateImage(cvSize(256,300),8,3);
    cvSetZero(HistogramImage1);
    HistogramImage1->origin=1;
    HistogramBinWidth=256/HistogramBins;
    printf("The Bolck Width is : %d\n",HistogramBinWidth);
    cvCalcHist(&Image1,Histogram1);

    printf("Gray Level Values:\n");
    for(int i=0;i<HistogramBins;i++)
    {
        printf("%.f \n",((CvMatND *) Histogram1->bins)->data.fl[i]);
        Point1=cvPoint(i*HistogramBinWidth,0);
        Point2=cvPoint((i+1)*HistogramBinWidth,(int)cvQueryHistValue_1D(Histogram1,i)/50);

        cvRectangle(HistogramImage1,Point1,Point2,CV_RGB(127,127,127));
    }

    cvNamedWindow("Histogram",1);
    cvNamedWindow("Riverbank",1);
    cvShowImage("Riverbank",Image1);
    cvShowImage("Histogram",HistogramImage1);
    cvWaitKey(0);
}

執行結果:


因此,這邊就用cvRectangle()的方式來表達,對於CvHistogram這個資料結構,為什麼可以任意定義上下界以及區塊的個數呢?因為CvHistogram使用的是Look-up table(LUT)的方式,也就是查表法,開一個256大小空間的陣列,利用比例的縮放,縮放的數據存入Look-up table裡面,在利用索引的方式對應,而使用Look-up table最大的缺點為,無法取得很精確的數據,由於它是被比例縮放過的,因此除了範圍為256的可以求的完整的數值,LUT的用法會在後面使用到.

對於其他維度的直方圖,它的做法如下

三維直方圖擷取
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int Histogram3DBins[3] = {256,256,256};
float HistogramRange1[6]={0,255,0,255,0,255};
float *HistogramRange[3]={&HistogramRange1[0],&HistogramRange1[2],&HistogramRange1[4]};

void Print3DHistogram(CvHistogram *Histogram,int BinSize);

int main()
{
    CvHistogram *Histogram1;
    IplImage *Image1=cvLoadImage("Riverbank.jpg",1);
    IplImage *RedImage=cvCreateImage(cvGetSize(Image1),8,1);
    IplImage *GreenImage=cvCreateImage(cvGetSize(Image1),8,1);
    IplImage *BlueImage=cvCreateImage(cvGetSize(Image1),8,1);
    IplImage *ImageArray[3]={RedImage,GreenImage,BlueImage};

    cvSplit(Image1,BlueImage,GreenImage,RedImage,0);
    Histogram1 = cvCreateHist(3,Histogram3DBins,CV_HIST_SPARSE,HistogramRange);

    cvCalcHist(ImageArray,Histogram1);

    printf("3D Historgram Data\n");
    Print3DHistogram(Histogram1,256);

    cvNamedWindow("Riverbank",1);
    cvShowImage("Riverbank",Image1);

    cvWaitKey(0);
}

void Print3DHistogram(CvHistogram *Histogram,int BinSize)
{
    for(int i=0;i<BinSize;i++)
    {
        for(int j=0;j<BinSize;j++)
        {
            for(int k=0;k<BinSize;k++)
            {
                if(cvQueryHistValue_3D(Histogram,i,j,k)>10)
                {
                    printf("%.f\n",cvQueryHistValue_3D(Histogram,i,j,k));
                }
            }
        }
    }
}

執行結果:


上面是三個維度的統計直方圖,分別為R維度,G維度,B維度,並且分別被量化成256等分的區塊,同樣的,也是使用LUT的方法,由於這個統計直方圖非常的大,它所佔的區域為256*256*256的大小,而實際上累積的分佈只有一點點,所以說,對於高維度的統計直方圖就要用到稀疏矩陣,要不然會浪費大量的記憶體空間,但是對於多維度的圖表呈現,OpenCV最多也只能支援到一維的方式,二維的方式可以用OpenGL(glut)呈現,當然高的維度本來就很難用視覺化的方式呈現.

cvCreateHist()
初始化CvHistogram資料結構,可以選擇密集矩陣(CvMatND)CV_HIST_ARRAY以及稀疏矩陣(CvSparseMat)CV_HIST_SPARSE,第一個引數為維度的選擇,第二個引數為要將直方圖切割為多少區塊,第三個引數為選擇cvCreateHist()函數的參數或代號,第四個引數為每一個維度的上下界
cvCreateHist(輸入int型別直方圖維度,輸入int型別直方圖區塊數,輸入參數或代號,輸入每個維度的上下界數據)

cvCalcHist()
計算直方圖累積數據,第一個引數為輸入目標IplImage圖形陣列資料結構,第二個引數輸出為CvHistogram資料結構
cvCalcHist(輸入目標IplImage圖形陣列資料結構,輸出為CvHistogram資料結構)

cvQueryHistValue_1D()
讀取CvHistogram資料結構一維空間的圖形直方圖資料,它在OpenCV的"cvcompat.h"函式庫被定義為

#define cvQueryHistValue_1D( hist, idx0 ) ((float)cvGetReal1D( (hist)->bins, (idx0)))

因此回傳的是float型別的資料,輸入CvHistogram資料結構,以及輸入一維資料結構的Index索引數據
cvQueryHistValue_1D(輸入CvHistogram資料結構,輸入一維int型別數據索引)

cvQueryHistValue_2D()
讀取CvHistogram資料結構二維空間的圖形直方圖資料,它在OpenCV的"cvcompat.h"函式庫被定義為

#define cvQueryHistValue_2D( hist, idx0, idx1 ) ((float)cvGetReal2D( (hist)->bins, (idx0), (idx1)))

回傳float型別的資料,第一個引數為輸入CvHistogram資料結構,第二個引數為輸入二維資料結構的x軸索引數據,第三個引數為y軸索引數據
cvQueryHistValue_2D(輸入CvHistogram資料結構,輸入二維int型別x軸數據索引,輸入二維int型別y軸數據索引)

cvQueryHistValue_3D()
讀取CvHistogram資料結構三維空間的圖形直方圖資料,它在OpenCV的"cvcompat.h"函式庫被定義為

#define cvQueryHistValue_3D( hist, idx0, idx1, idx2 ) ((float)cvGetReal3D( (hist)->bins, (idx0), (idx1), (idx2)))

回傳float型別的資料,第一個引數為輸入CvHistogram資料結構,第二個引數為輸入三維資料結構的x軸索引數據,第三個引數為輸入y軸索引數據,第四個引數為輸入z軸索引數據
cvQueryHistValue_3D(輸入CvHistogram資料結構,輸入三維int型別x軸數據索引,輸入三維int型別y軸數據索引,輸入三維int型別z軸數據索引)



2008年10月11日 星期六

OpenCV統計應用-極端值,cvReduce

在統計模型裡面,總是會有一些特別高或特別低的數值,這個數值已經脫離了統計分配的假設,不符合統計的模型,通常會有這種極大或是極小的極端值(outlier)有可能是因為量測誤差,或是在統計模型中那0.0001的機率發生,因此,在統計學裡,挑出極端值來做最精簡的量測也是很重要的,就好比一群低收入戶的人裡面出現了一位身價上億的人而拉高了一群人的平均所得,使得低收入戶的族群變成中高收入的族群,這邊要抓取那個最大最小值就用到了cvMinMaxLoc()的函式啦.在圖片裡面,也許很難有如此極端的事件產生,cvMinMaxLoc()可以處理一般的數據,亦可以處理圖片找出它最大最小值以及它的位置.

cvMinMaxLoc()的實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);

    double MinValue;
    double MaxValue;

    CvPoint MinLocation;
    CvPoint MaxLocation;

    cvSetImageCOI(Image1,1);
    cvMinMaxLoc(Image1,&MinValue,&MaxValue,&MinLocation,&MaxLocation);

    printf("The Min number is : %.f\n",MinValue);
    printf("The position is : ( %d , %d )\n",MinLocation.x,MinLocation.y);
    printf("The Max number is : %.f\n",MaxValue);
    printf("The position is : (%d , %d )\n",MaxLocation.x,MaxLocation.y);

    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

執行結果:


上面的結果是抓出這張圖片最大最小值的數據,選擇綠色這個通道,雖然這已經不算是極端值的意義了,不過它仍然是可以對一般圖形做處理,cvMinMaxLoc()可以同時找出最大最小值,也可以指出最大值的位置跟最小值的位置,而cvMinMaxLoc()必須對單通道做處理因此必須要用,cvSetImageCOI選定顏色,也可以支援ROI,甚至,cvMinMaxLoc()可以用遮罩的方式實作,使用的方法如下

#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    IplImage *MaskImage1=cvLoadImage("grotto_Threshold.bmp",0);
    double MinValue;
    double MaxValue;

    CvPoint MinLocation;
    CvPoint MaxLocation;

    cvSetImageCOI(Image1,1);
    cvMinMaxLoc(Image1,&MinValue,&MaxValue,&MinLocation,&MaxLocation,MaskImage1);

    printf("The Min number is : %.f\n",MinValue);
    printf("The position is : ( %d , %d )\n",MinLocation.x,MinLocation.y);
    printf("The Max number is : %.f\n",MaxValue);
    printf("The position is : (%d , %d )\n",MaxLocation.x,MaxLocation.y);

    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

執行結果:


上面的程式也只對grotto_Threshold.bmp白色的部份做處理,從白色區域找出它的最大最小值以及它的位置,跟前面的程式差不多.

cvReduce()為將矩陣維度降低為向量的維度,也就勢將該行或該列做加總,平均,找出最大,最小值,cvReduce()可使用的參數或代號如下

#define CV_REDUCE_SUM 0
#define CV_REDUCE_AVG 1
#define CV_REDUCE_MAX 2
#define CV_REDUCE_MIN 3


而它的數據要從圖形縮成行或縮成列,則輸入的向量就必須要跟它的行或列相等長度,而且是一維的形式,下面這個是求出每一列的RGB值的平均數,並且用圖表的方式

cvReduce()平均數向量
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    IplImage *AVGImage=cvCreateImage(cvSize(Image1->width,255),IPL_DEPTH_8U,3);
    CvMat *AVGVector=cvCreateMat(1,Image1->width,CV_32FC3);

    cvReduce(Image1,AVGVector,0,CV_REDUCE_AVG);


    for(int i=0;i<Image1->width;i++)
    {
        printf("%f\t%f\t%f\t\n",cvGet1D(AVGVector,i).val[0],cvGet1D(SumVector,i).val[1],cvGet1D(SumVector,i).val[2]);
        if(i!=Image1->width-1)
        {
            cvLine(AVGImage,cvPoint(i,(int)cvGet1D(AVGVector,i).val[0]),cvPoint(i+1,(int)cvGet1D(AVGVector,i+1).val[0]),CV_RGB(0,0,255));
            cvLine(AVGImage,cvPoint(i,(int)cvGet1D(AVGVector,i).val[1]),cvPoint(i+1,(int)cvGet1D(AVGVector,i+1).val[1]),CV_RGB(0,255,0));
            cvLine(AVGImage,cvPoint(i,(int)cvGet1D(AVGVector,i).val[2]),cvPoint(i+1,(int)cvGet1D(AVGVector,i+1).val[2]),CV_RGB(255,0,0));
        }

    }

    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvNamedWindow("AVG Image",1);
    cvShowImage("AVG Image",AVGImage);

    cvWaitKey(0);
}

執行結果:



cvReduce()可以支援多通道,而AVGVector則是通道三的向量,然後圖表的呈現以cvLine()實作,cvReduce()第一個引數為目標要被統計的圖片,第二個引數為要被計算出來的向量,而第二個引數有一些特殊的規定,它的使用條件如下

1.通道數必須與輸入圖片的數目相同
2.所需要計算的列或欄的長度必須要與輸入圖片
3.一定要用浮點數型別來輸入,如CV_32FC3,CV64FC3,CV_32FC1等,由於uchar型別在做像是CV_REDUCE_SUM時數據一定會超過,因此cvReduce()會做檢查驗證

而且而CV_REDUCE_SUM則是在二值化的圖片的計算比較具有意義,它可以求出二值化圖片的投影向量,並且以圖表的方式呈現.下面就是以列投影以及欄投影的方式來做圖表的呈現.

二值化圖形投影計算
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto_Threshold.bmp",0);
    IplImage *RowProjectionImage=cvCreateImage(cvSize(Image1->width,300),IPL_DEPTH_8U,3);
    IplImage *ColumnProjectionImage=cvCreateImage(cvSize(300,Image1->height),IPL_DEPTH_8U,3);
    CvMat *RowSumVector=cvCreateMat(1,Image1->width,CV_32FC1);
    CvMat *ColumnSumVector=cvCreateMat(Image1->height,1,CV_32FC1);

    RowProjectionImage->origin=1;
    cvReduce(Image1,RowSumVector,0,CV_REDUCE_SUM);
    cvReduce(Image1,ColumnSumVector,1,CV_REDUCE_SUM);

    for(int i=0;i<Image1->width;i++)
    {
        cvLine(RowProjectionImage,cvPoint(i,(int)cvGet1D(RowSumVector,i).val[0]/(2*255)),cvPoint(i,0),CV_RGB(255,255,255));
    }
    for(int i=0;i<Image1->height;i++)
    {
        cvLine(ColumnProjectionImage,cvPoint((int)cvGet1D(ColumnSumVector,i).val[0]/(2*255),i),cvPoint(0,i),CV_RGB(255,255,255));
    }

    cvNamedWindow("grotto Threshold",1);
    cvShowImage("grotto Threshold",Image1);

    cvNamedWindow("Row Projection Image",1);
    cvShowImage("Row Projection Image",RowProjectionImage);

    cvNamedWindow("Column Projection Image",1);
    cvShowImage("Column Projection Image",ColumnProjectionImage);
    cvWaitKey(0);
}

執行結果:


上面的程式,由於是二值化的圖片,只有0跟255,所以必須要將累加的數值除以255才能知道它所累積的個數,在將該數目除以二平移,使他在圖表呈現上不會太大,對於投影的實作,可以藉由選取較高的區間,提出二值化裡面有意義的資料區塊,在人臉辨識可以藉由這種方法提取特定臉部器官的特徵.

cvMinMaxLoc()
找出圖片或一組數據中最大值及最小值的數據,以及最大值及最小值的位置,第一個引數為輸入IplImage資料結構或CvMat資料結構,第二個引數為輸出最小值double型別數據,第三個引數為輸出最大值double型別數據,第四個引數為輸出最小值位置CvPoint資料結構,第五個引數為輸出最大值位置CvPoint資料結構.
cvMinMaxLoc(輸入IplImage或CvMat資料結構,輸出double型別最小值數據,輸出double型別最大值數據,輸出最小值CvPoint資料結構,輸出最大值CvPoint資料結構)

cvReduce()
將二維圖形縮減成列向量或欄向量,cvReduce()具有四個參數,分別為CV_REDUCE_SUM總和,CV_REDUCE_AVG平均,CV_REDUCE_MAX最大值,CV_REDUCE_MIN最小值,可以由多通道的輸入,但輸出的行向量或欄向量一定要符合圖形的長度.第一個引數為輸入目標IplImage資料結構或CvMat資料結構,第二個引數為輸出目標CvMat結構向量,第三個引數為縮減為列向量或欄向量,0為欄向量,1為列向量,第四個引數為cvReduce()的參數或代號.
cvReduce(輸入IplImage或CvMat資料結構,輸出CvMat向量資料結構,輸入縮減欄向量或列向量代號,目標參數或代號)



2008年10月10日 星期五

OpenCV統計應用-平均數與標準差

平均數跟標準差是統計學裡最基本的東西,cvAvg()為平均數的計算,也支援多通道的使用,而它使用的方法如下

簡單cvAvg()實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>
int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    CvScalar Scalar1;
    Scalar1 = cvAvg(Image1);

    printf("Blue Channel Avg is : %.f\n",Scalar1.val[0]);
    printf("Green Channel Avg is : %.f\n",Scalar1.val[1]);
    printf("Red Channel Avg is : %.f\n",Scalar1.val[2]);


    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

執行結果:


與cvSum()相同,而它與cvSum()唯一不同的地方為它支援Mask遮罩的操作,cvAvg()將黑白圖遮罩白色的部份做平均數的統計,使用方式如下

簡單cvAvg()遮罩實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    IplImage *MaskImage1=cvLoadImage("grotto_Threshold.jpg",0);
    CvScalar Scalar1;
    Scalar1 = cvAvg(Image1,MaskImage1);

    printf("Blue Channel Avg is : %.f\n",Scalar1.val[0]);
    printf("Green Channel Avg is : %.f\n",Scalar1.val[1]);
    printf("Red Channel Avg is : %.f\n",Scalar1.val[2]);


    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

執行結果:


將之前洞穴的二值化黑白圖片當遮罩對應出白色部分做平均數的計算,而OpenCV也有另外一個算平均數的函式cvAvgSdv(),它可以同時算出平均數跟標準差,也支援Mask遮罩的實作,使用的方式如下

簡單cvAvgSdv()實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    CvScalar MeanScalar;
    CvScalar StandardDeviationScalar;
    cvAvgSdv(Image1,&MeanScalar,&StandardDeviationScalar);

    printf("Blue Channel Avg is : %.f\n",MeanScalar.val[0]);
    printf("Blue Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[0]);
    printf("Green Channel Avg is : %.f\n",MeanScalar.val[1]);
    printf("Green Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[1]);
    printf("Red Channel Avg is : %.f\n",MeanScalar.val[2]);
    printf("Red Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[2]);


    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

執行結果:


上面的是用cvAvgSdv()計算平均數跟標準差,也同樣是用CvScalar資料結構來做數值的接收,再來,就是Mask的部份

簡單cvAvgSdv()遮罩實作
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    IplImage *MaskImage1=cvLoadImage("grotto_Threshold.jpg",0);
    CvScalar MeanScalar;
    CvScalar StandardDeviationScalar;
    cvAvgSdv(Image1,&MeanScalar,&StandardDeviationScalar,MaskImage1);

    printf("Blue Channel Avg is : %.f\n",MeanScalar.val[0]);
    printf("Blue Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[0]);
    printf("Green Channel Avg is : %.f\n",MeanScalar.val[1]);
    printf("Green Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[1]);
    printf("Red Channel Avg is : %.f\n",MeanScalar.val[2]);
    printf("Red Channel Standard Deviation is : %.f\n",StandardDeviationScalar.val[2]);


    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvNamedWindow("grotto_Threshold",1);
    cvShowImage("grotto_Threshold",MaskImage1);

    cvWaitKey(0);
}

執行結果:


也是跟cvAvg()一樣用單通道二值化影像做遮罩,計算平均數與標準差,也不限於圖形的輸入,實際上任何的資料數據都可以做輸入,下面就是任意一筆資料來做平均數跟標準差的計算

cvMat資料結構計算平均數標準差
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


uchar Array[10]={1,2,3,4,5,6,7,8,9};
int main()
{
    CvMat *Matrix1=cvCreateMat(1,10,CV_8UC1);
    cvSetData(Matrix1,Array,Matrix1->step);

    CvScalar MeanScalar;
    CvScalar StandardDeviationScalar;
    cvAvgSdv(Matrix1,&MeanScalar,&StandardDeviationScalar);

    printf("Matrix1 Avg is : %.f\n",MeanScalar.val[0]);
    printf("Matrix1 Standard Deviation is : %.f\n",StandardDeviationScalar.val[0]);

    system("pause");
}

執行結果:


實際上,很多的函式IplImage資料結構跟CvMat資料結構都是可以共用的,包括前面的cvCountNonZero(),cvSum(),cvAvg()及cvAvgSdv().

cvAvg()
計算IplImage資料結構或CvMat資料結構的平均數,支援Mask遮罩的運算,第一個引數輸入為IplImage資料結構或CvMat資料結構,第二個引數為IplImage資料結構單通道uchar型別的遮罩對應,輸出為CvScalar資料結構
cvAvg(輸入IplImage資料結構或CvMat資料結構,輸入單通道uchar型別IplImage資料結構)

cvAvgSdv()
計算IplImage資料結構或CvMat資料結構的平均數,標準差,支援Mask通道的計算,第一個引數為輸入IplImage資料結構或CvMat資料結構,第二個引數為輸出CvScalar平均數資料結構,第三個引數為輸出CvScalar標準差資料結構,第四個引數為IplImage資料結構單通道uchar型別遮罩的輸入
cvAvgSdv(輸入IplImage資料結構或CvMat資料結構,輸出平均數CvScalar資料結構,輸出標準差CvScalar資料結構,輸入單通道uchar型別IplImage資料結構)



2008年10月7日 星期二

OpenCV統計應用-總和,計算非零

再來就是一些計數的函式啦,下面簡單的介紹一張圖形,所有數值總和以及圖形上所有非0的計算,在一些圖形數值的量測方面,稍微具有一些實質的意義.

簡單cvSum()使用
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);
    CvScalar Scalar1;
    Scalar1 = cvSum(Image1);

    printf("Blue Channel Sum is : %.f\n",Scalar1.val[0]);
    printf("Green Channel Sum is : %.f\n",Scalar1.val[1]);
    printf("Red Channel Sum is : %.f\n",Scalar1.val[2]);


    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

原始圖片:


執行結果:


cvSum()是計算所有圖片每個通道數據的總和,因此在這個通道為3的RGB圖,所有的總和都被計算在CvScalar資料結構上面了,cvSum()輸入為IplImage或CvMat資料結構,輸出為CvScalar的資料結構,裡面存放著RGB的總和數值,接著就是cvContNonZero()的使用.

簡單cvCountNonZero()使用
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int main()
{
    IplImage *Image1=cvLoadImage("grotto_Threshold.jpg",0);

    printf("Thresholding Non Zero is : %d\n",cvCountNonZero(Image1));

    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);
    cvWaitKey(0);
}

原始圖片:


執行結果:


cvCountNonZero()為計算非0的個數,只能使用在單通道的圖形,而且對於這個函式在黑白圖的使用上會比較具有意義,由於黑白圖非0即1因此計算出非0的個數同時也算出了1的個數,而cvCountNonZero(),以及cvSum()也可以支援COI(Color Of Interesting)以及ROI(Region Of Interesting)的使用,使用方式如下

cvCountNonZero()及cvSum()的ROI,COI
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int main()
{
    IplImage *Image1=cvLoadImage("grotto.jpg",1);

    cvSetImageROI(Image1,cvRect(100,100,100,100));

    cvSetImageCOI(Image1,1);
    printf("Blue Channel Non Zero is : %d\n",cvCountNonZero(Image1));
    printf("Blue Channel Sum is : %.f\n",cvSum(Image1).val[0]);

    cvSetImageCOI(Image1,2);
    printf("\nGreen Channel Non Zero is : %d\n",cvCountNonZero(Image1));
    printf("Green Channel Sum is : %.f\n",cvSum(Image1).val[0]);

    cvSetImageCOI(Image1,3);
    printf("\nRed Channel Non Zero is : %d\n",cvCountNonZero(Image1));
    printf("Red Channel Sum is : %.f\n",cvSum(Image1).val[0]);

    cvNamedWindow("grotto(ROI)",1);
    cvShowImage("grotto(ROI)",Image1);
    cvResetImageROI(Image1);
    cvNamedWindow("grotto",1);
    cvShowImage("grotto",Image1);

    cvWaitKey(0);
}

執行結果:


對於一個被選定COI的他會對於特定顏色做統計,cvCountNonZero()以及cvSum()亦是如此,而被選定ROI他會對於特定的區域做計算,因此上面的結果會是被選定的區域,加上被選定的顏色,他所計算出來的統計結果,而COI選定的顏色後,因為是單通道的,所以cvSum()計算出來的結果會被放在CvScalar資料結構val[0]的位置,這邊用cvSum(Image1).val[0]表示直接存取CvScalar資料結構val[0]的數據.

cvSum()
計算所有通道數據的總和,計算出來的結果會回傳放在CvScalar資料結構上,如果是使用單通道或是COI的話會放在CvScalar資料結構val[0]上面.輸入的引數為IplImage資料結構或CvMat資料結構.
cvSum(輸入IplImage或CvMat資料結構)

cvCountNonZero()
計算所有非0數據的總和,只支援單通道或是COI,輸入為IplImage資料結構或CvMat資料結構,輸出為int變數型別.
cvCountNonZero(輸入IplImage或CvMat資料結構)



OpenCV統計應用-基本統計直方圖

在統計學裡面,最基本影像處理的應用,就是統計直方圖了,它可以將一張圖片的色彩結構統計起來,對於一張圖片的R值,G值,B值或灰階做統計計算,或者是,轉換到另一個色彩空間,將圖形做量化及統計的計算,在OpenCV裡面,也有不少統計直方圖的計算,並且可以將它圖表化,呈現出統計的概況.

基本統計直方圖計算
#include <cv.h>
#include <highgui.h>
#include <stdio.h>

int BlueHistogramData[256]={0};
int GreenHistogramData[256]={0};
int RedHistogramData[256]={0};
int GrayLevelHistogramData[256]={0};

int main()
{
    IplImage *Image1=cvLoadImage("waterfall.jpg",1);
    CvScalar Scalar1;
    int BlueColor,GreenColor,RedColor,GrayLevelColor;

    for(int i=0;i<Image1->height;i++)
    {
        for(int j=0;j<Image1->width;j++)
        {

            Scalar1=cvGet2D(Image1,i,j);
            BlueColor=(int)Scalar1.val[0];
            GreenColor=(int)Scalar1.val[1];
            RedColor=(int)Scalar1.val[2];
            GrayLevelColor=(int) (0.299*RedColor+0.587*GreenColor+0.114*BlueColor);

            BlueHistogramData[BlueColor]++;
            GreenHistogramData[GreenColor]++;
            RedHistogramData[RedColor]++;
            GrayLevelHistogramData[GrayLevelColor]++;

        }
    }
    printf("Red\tGreen\tBlue\tGrayLevel\n");
    for(int i=0;i<256;i++)
    {

        printf("%d\t%d\t%d\t%d\t\n",RedHistogramData[i],GreenHistogramData[i],BlueHistogramData[i],GrayLevelHistogramData[i]);
    }

    cvNamedWindow("waterfall",1);
    cvShowImage("waterfall",Image1);
    cvWaitKey(0);
}

原始圖片:


執行結果:


上面的程式碼,就是將RGB值做統計,將R值,G值,B值累加在0~255的範圍裡,因此就可以知道這張圖的色彩分布的結構,灰階圖亦然,而OpenCV亦可以做到圖表的呈現的方式,利用的是繪圖函式來實作,用cvLine()或是cvRectangle()就可以做到統計值方圖的繪製,OpenCV在統計直方圖製作部分有一個CvHistogram的資料結構可以實作,而下面這個,則是直接將上面的程式碼修改繪製上去的統計值方圖製作.

統計直方圖計算與繪製
#include <cv.h>
#include <highgui.h>
#include <stdio.h>


int BlueHistogramData[256]={0};
int GreenHistogramData[256]={0};
int RedHistogramData[256]={0};
int GrayLevelHistogramData[256]={0};


int main()
{
    IplImage *Image1=cvLoadImage("waterfall.jpg",1);
    IplImage *BlueHistogramImage,*GreenHistogramImage,*RedHistogramImage;
    IplImage *GrayLevelHistogramImage;

    BlueHistogramImage=cvCreateImage(cvSize(256,250),IPL_DEPTH_8U,3);
    GreenHistogramImage=cvCreateImage(cvSize(256,250),IPL_DEPTH_8U,3);
    RedHistogramImage=cvCreateImage(cvSize(256,250),IPL_DEPTH_8U,3);
    GrayLevelHistogramImage=cvCreateImage(cvSize(256,250),IPL_DEPTH_8U,3);

    BlueHistogramImage->origin=1;
    GreenHistogramImage->origin=1;
    RedHistogramImage->origin=1;
    GrayLevelHistogramImage->origin=1;

    CvScalar Scalar1;
    int BlueColor,GreenColor,RedColor,GrayLevelColor;

    for(int i=0;i<Image1->height;i++)
    {
        for(int j=0;j<Image1->width;j++)
        {

            Scalar1=cvGet2D(Image1,i,j);
            BlueColor=(int)Scalar1.val[0];
            GreenColor=(int)Scalar1.val[1];
            RedColor=(int)Scalar1.val[2];
            GrayLevelColor=(int) (0.299*RedColor+0.587*GreenColor+0.114*BlueColor);

            BlueHistogramData[BlueColor]++;
            GreenHistogramData[GreenColor]++;
            RedHistogramData[RedColor]++;
            GrayLevelHistogramData[GrayLevelColor]++;

        }
    }
    for(int i=0;i<255;i++)
    {
        cvLine(BlueHistogramImage,cvPoint(i,BlueHistogramData[i]/10),cvPoint(i,0),CV_RGB(0,0,255));
        cvLine(GreenHistogramImage,cvPoint(i,GreenHistogramData[i]/10),cvPoint(i,0),CV_RGB(0,255,0));
        cvLine(RedHistogramImage,cvPoint(i,RedHistogramData[i]/10),cvPoint(i,0),CV_RGB(255,0,0));
        cvLine(GrayLevelHistogramImage,cvPoint(i,GrayLevelHistogramData[i]/10),cvPoint(i,0),CV_RGB(128,128,128));
    }

    cvNamedWindow("waterfall",1);
    cvShowImage("waterfall",Image1);
    cvNamedWindow("Blue Histogram",1);
    cvShowImage("Blue Histogram",BlueHistogramImage);
    cvNamedWindow("Green Histogram",1);
    cvShowImage("Green Histogram",GreenHistogramImage);
    cvNamedWindow("Red Histogram",1);
    cvShowImage("Red Histogram",RedHistogramImage);
    cvNamedWindow("GrayLevel Histogram",1);
    cvShowImage("GrayLevel Histogram",GrayLevelHistogramImage);

    cvWaitKey(0);
}

執行結果:


在繪製圖形的時候,亦要開啟圖表的空間,IplImage資料結構,在將IplImage資料結構的origin設為1,為Window XP預設圖形起始點,這部份在"資料結構操作與運算-IplImage資料結構"有詳細的介紹,再來就是讀取RGB值做統計,以及使用cvLine()做繪製,cvLine()的繪製方法則是在"OpenCV繪圖的實作-cvLine,cvRectangle"有介紹到,而CvHistogram資料結構也是使用類似上面的原理,在OpenCV裡面,統計直方圖的部分還是需要自己動手畫,沒有很方便的函式可以直接實作出視覺化圖形的呈現.



Copyright 2008-2009,yester