學習opencv筆記(網絡)

 

一、OpenCV概述與功能介紹

OpenCV是Intel®開源計算機視覺庫。它由一系列 C 函數和少量 C++ 類構成,實現了圖像處理和計算機視覺方面的很多通用算法。OpenCV 擁有包括 300 多個C函數的跨平臺的中、高層 API。它不依賴於其它的外部庫——儘管也可以使用某些外部庫。

OpenCV 對非商業應用和商業應用都是免費(FREE)的。(細節參考 license)。代碼下載地址:http://www.sourceforge.net/projects/opencvlibrary

OpenCV 爲Intel® Integrated Performance Primitives (IPP) 提供了透明接口。 這意味着如果有爲特定處理器優化的的 IPP 庫, OpenCV 將在運行時自動加載這些庫。 更多關於 IPP 的信息請參考: http://www.intel.com/software/products/ipp/index.htm

它有以下特點:
1) 開放的C/C++源碼
2) 基於Intel處理器指令集開發的優化代碼
3) 統一的結構和功能定義
4) 強大的圖像和矩陣運算能力
5) 方便靈活的用戶接口
6)同時支持MS-WINDOWS、LINUX平臺
作爲一個基本的計算機視覺、圖像處理和模式識別的開源項目,OPENCV可以直接應用於很多領域,作爲第二次開發的理想工具。

OpenCV功能介紹:

OpenCV包含如下幾個部分:

Cxcore:一些基本函數(各種數據類型的基本運算等)。

Cv:圖像處理和計算機視覺功能(圖像處理,結構分析,運動分析,物體跟蹤,模式識別,攝像機定標)

Ml:機器學習模塊,目前內容主要爲分類器。

Cvaux:一些實驗性的函數(ViewMorphing,三維跟蹤,PCA,HMM)

Highgui:用戶交互部分,(GUI,圖象視頻I/O,系統調用函數)

 

二、OpenCV安裝

OpenCV2.0剛剛發佈,VC 2008 Express下安裝OpenCV2.0請參考:

http://www.opencv.org.cn/index.php/VC_2008_Express%E4%B8%8B%E5%AE%89%E8%A3%85OpenCV2.0

 

三、基礎知識:

1、opencv 數據類型轉換操作小結

(1)圖像中或矩陣數組中數據格式轉換:
cvConvert( image, image_temp );

cvConvertScale( const CvArr* src, CvArr* dst, double scale CV_DEFAULT(1), double shift CV_DEFAULT(0) );

cvScale(src, dst);

// Converts CvArr (IplImage or CvMat,...) to CvMat.
cvGetMat( const CvArr* arr, CvMat* header, int* coi CV_DEFAULT(NULL), int allowND CV_DEFAULT(0));
cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask ); //可以實現對不規制圖形的提取


(2)多通道圖像轉成數組中數據
cvGetMat( const CvArr* array, CvMat* mat, int* pCOI, int allowND )

cvCopy(img,mat); 

// Converts CvArr (IplImage or CvMat,...) to CvMat.
cvGetMat( const CvArr* arr, CvMat* header, int* coi CV_DEFAULT(NULL), int allowND CV_DEFAULT(0));


(3) 數組中數據轉成多通道圖像
cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL );

cvGetMat( const CvArr* arr, CvMat* header, int* coi CV_DEFAULT(NULL), int allowND CV_DEFAULT(0));

 

2、二值化函數cvAdaptiveThreshold和cvThreshold的一些發現

自適應二值化計算像素的鄰域的平均灰度,來決定二值化的值。如果整個區域幾乎是一樣灰度的,則無法給出合適的結果了。之所以看起來像邊緣檢測,是因爲窗尺寸設置的小,可以改大一點試一試。
cvAdaptiveThreshold( src, dst, 255, CV_ADAPTIVE_THRESH_MEAN_C, CV_THRESH_BINARY, 21); //窗設置爲21
沒有萬能的二值化方法,具體問題具體分析,自適應二值化對於光照不均的文字,條碼等,效果很好。窗口大小選擇,考慮被檢測物體尺寸。自適應閾值化中的閾值完全是由你所選擇的鄰域所確定的,如果你所選擇的鄰域非常小(比如3×3),那麼很顯然閾值的“自適應程度”就非常高,這在結果圖像中就表現爲邊緣檢測的效果。如果鄰域選擇的比較大(比如31×31),那麼閾值的“自適應程度”就比較低,這在結果圖像中就表現爲二值化的效果。

 

3、用 gabor 和 AdaBoost (MultiBoost )做目標檢測圖像識別

http://www.opencv.org.cn/forum/viewtopic.php?f=10&t=7790

 

4、視頻跟蹤方法

跟蹤的方法我知道的有KLMAN濾波.粒子濾波.camshift.meanshift。

基於Mean Shift的閾值分割:http://www.codesoso.com/code/mean_shift.aspx

http://arslan-ai.spaces.live.com/blog/cns!CAE7EF891A2218BA!123.entry

 

5、怎麼訪問圖像像素

(座標是從0開始的,並且是相對圖像原點的位置。圖像原點或者是左上角 (img->origin=IPL_ORIGIN_TL) 或者是左下角 (img->origin=IPL_ORIGIN_BL) )

假設有 8-bit 1-通道的圖像 I (IplImage* img):

---------------------------------------------------------------------

I(x,y) ~ ((uchar*)(img->imageData + img->widthStep*y))[x]

---------------------------------------------------------------------

假設有 8-bit 3-通道的圖像 I (IplImage* img):

---------------------------------------------------------------------

I(x,y)blue ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3]

I(x,y)green ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3+1]

I(x,y)red ~ ((uchar*)(img->imageData + img->widthStep*y))[x*3+2]

------------------------------------------------------------------------------

例如,給點 (100,100) 的亮度增加 30 ,那麼可以這樣做:

------------------------------------------------------------------------------

CvPoint pt = {100,100};

((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3] += 30;

((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3+1] += 30;

((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3+2] += 30;

-----------------------------------------------------------------------------

或者更高效地:

-----------------------------------------------------------------------------

CvPoint pt = {100,100};

uchar* temp_ptr = &((uchar*)(img->imageData + img->widthStep*pt.y))[pt.x*3];

temp_ptr[0] += 30;

temp_ptr[1] += 30;

temp_ptr[2] += 30;

-----------------------------------------------------------------------------

假設有 32-bit 浮點數, 1-通道 圖像 I (IplImage* img):

-----------------------------------------------------------------------------

I(x,y) ~ ((float*)(img->imageData + img->widthStep*y))[x]

-----------------------------------------------------------------------------

現在,一般的情況下,假設有 N-通道,類型爲 T 的圖像:

-----------------------------------------------------------------------------

I(x,y)c ~ ((T*)(img->imageData + img->widthStep*y))[x*N + c]

-----------------------------------------------------------------------------

你可以使用宏 CV_IMAGE_ELEM( image_header, elemtype, y, x_Nc )

-----------------------------------------------------------------------------

I(x,y)c ~ CV_IMAGE_ELEM( img, T, y, x*N + c )

-----------------------------------------------------------------------------

也有針對各種圖像(包括 4 通道圖像)和矩陣的函數(cvGet2D, cvSet2D), 但是它們非常慢。

 

6、如何訪問矩陣元素?

方法是類似的(下面的例子都是針對 0 起點的列和行)

 

設有 32-bit 浮點數的實數矩陣 M (CvMat* mat):

----------------------------------------------------------------------------

M(i,j) ~ ((float*)(mat->data.ptr + mat->step*i))[j]

----------------------------------------------------------------------------

設有 64-bit 浮點數的複數矩陣 M (CvMat* mat):

----------------------------------------------------------------------------

Re M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2]

Im M(i,j) ~ ((double*)(mat->data.ptr + mat->step*i))[j*2+1]

----------------------------------------------------------------------------

對單通道矩陣,有宏 CV_MAT_ELEM( matrix, elemtype, row, col ), 例如對 32-bit

 浮點數的實數矩陣:

M(i,j) ~ CV_MAT_ELEM( mat, float, i, j ),

例如,這兒是一個 3x3 單位矩陣的初始化:

CV_MAT_ELEM( mat, float, 0, 0 ) = 1.f;

CV_MAT_ELEM( mat, float, 0, 1 ) = 0.f;

CV_MAT_ELEM( mat, float, 0, 2 ) = 0.f;

CV_MAT_ELEM( mat, float, 1, 0 ) = 0.f;

CV_MAT_ELEM( mat, float, 1, 1 ) = 1.f;

CV_MAT_ELEM( mat, float, 1, 2 ) = 0.f;

CV_MAT_ELEM( mat, float, 2, 0 ) = 0.f;

CV_MAT_ELEM( mat, float, 2, 1 ) = 0.f;

CV_MAT_ELEM( mat, float, 2, 2 ) = 1.f;

 

7、如何在 OpenCV 中處理我自己的數據

設你有 300x200 32-bit 浮點數 image/array, 也就是對一個有 60000 個元素的數組。

----------------------------------------------------------------------------

int cols = 300, rows = 200;

float* myarr = new float[rows*cols];

// 第一步,初始化 CvMat 頭

CvMat mat = cvMat( rows, cols,

                  CV_32FC1, // 32 位浮點單通道類型

                  myarr // 用戶數據指針(數據沒有被複制)

                  );

// 第二步,使用 cv 函數, 例如計算 l2 (Frobenius) 模

double norm = cvNorm( &mat, 0, CV_L2 );

...

delete myarr;

其它情況在參考手冊中有描述。 見 cvCreateMatHeader,cvInitMatHeader,cvCreateImageHeader, cvSetData 等

 

8、如何讀入和顯示圖像

----------------------------------------------------------------------------

/* usage: prog <image_name> */

#include "cv.h"

#include "highgui.h"

 

int main( int argc, char** argv )

{

   

    IplImage* img;

    if( argc == 2 && (img = cvLoadImage( argv[1], 1)) != 0 )

    {

       

        cvNamedWindow( "Image view", 1 );

        cvShowImage( "Image view", img );

        cvWaitKey(0); // 非常重要,內部包含事件處理循環

        cvDestroyWindow( "Image view" );

        cvReleaseImage( &img );

        return 0;

         

}

    return -1;

       

}

 

9、圖像的通道

描述一個像素點,如果是灰度,那麼只需要一個數值來描述它,就是單通道。 如果一個像素點,有RGB三種顏色來描述它,就是三通道。4通道通常爲RGBA,在某些處理中可能會用到。 2通道圖像不常見,通常在程序處理中會用到,如傅里葉變換,可能會用到,一個通道爲實數,一個通道爲虛數,主要是編程方便。

 

10、HBITMAP 轉換IplImage、IplImage轉換爲DIB

// HBITMAP 轉換IplImage

IplImage* hBitmap2Ipl(HBITMAP hBmp)

{

BITMAP bmp;

::GetObject(hBmp,sizeof(BITMAP),&bmp);

int nChannels = bmp.bmBitsPixel == 1 ? 1 : bmp.bmBitsPixel/8 ;

int depth = bmp.bmBitsPixel == 1 ? IPL_DEPTH_1U : IPL_DEPTH_8U;

IplImage* img = cvCreateImageHeader( cvSize(bmp.bmWidth, bmp.bmHeight)

, depth, nChannels );

img->imageData =

(char*)malloc(bmp.bmHeight*bmp.bmWidth*nChannels*sizeof(char));

memcpy(img->imageData,(char*)(bmp.bmBits),bmp.bmHeight*bmp.bmWidth*nChannels);

return img;

}

 

void createDIB(IplImage* &pict){

IplImage * Red=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),

IPL_DEPTH_8U, 1 );

IplImage * Green=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),

IPL_DEPTH_8U, 1 );

IplImage * Blue=cvCreateImage( cvSize(IMAGE_WIDTH,IMAGE_HEIGHT),

IPL_DEPTH_8U, 1 );

cvSetImageCOI( pict, 3);

cvCopy(pict,Red);

cvSetImageCOI( pict, 2);

cvCopy(pict,Green);

cvSetImageCOI(pict, 1);

cvCopy(pict,Blue);

//Initialize the BMP display buffer

bmi = (BITMAPINFO*)buffer;

bmih = &(bmi->bmiHeader);

memset( bmih, 0, sizeof(*bmih));

bmih->biSize = sizeof(BITMAPINFOHEADER);

bmih->biWidth = IMAGE_WIDTH;

bmih->biHeight = IMAGE_HEIGHT; // -IMAGE_HEIGHT;

bmih->biPlanes = 1;

bmih->biCompression = BI_RGB;

bmih->biBitCount = 24;

palette = bmi->bmiColors;

for( int i = 0; i < 256; i++ ){

palette[i].rgbBlue = palette[i].rgbGreen = palette[i].rgbRed =

(BYTE)i;

palette[i].rgbReserved = 0;

}

cvReleaseImage(&Red);

cvReleaseImage(&Green);

cvReleaseImage(&Blue);

}

 

// HBITMAP轉換DIB

HBITMAP plIamgeToDIB(IplImage *pImg,int Size)  

{  

    HDC hDC = ::CreateCompatibleDC(0);  

    BYTE tmp[sizeof(BITMAPINFO)+255*4];  

    BITMAPINFO *bmi = (BITMAPINFO*)tmp;  

    HBITMAP hBmp;  

    int i;  

    memset(bmi,0,sizeof(BITMAPINFO));  

    bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  

    bmi->bmiHeader.biWidth = pImg->width;  

    bmi->bmiHeader.biHeight = -pImg->height;  

    bmi->bmiHeader.biPlanes = Size;  

    bmi->bmiHeader.biBitCount = pImg->nChannels * pImg->depth;  

 

    bmi->bmiHeader.biCompression = BI_RGB;  

    bmi->bmiHeader.biSizeImage = pImg->width*pImg->height*1;  

    bmi->bmiHeader.biClrImportant =0 ;  

    switch(pImg->nChannels * pImg->depth)  

    {  

    case 8 :  

    for(i=0 ; i < 256 ; i++)  

    {  

    bmi->bmiColors[i].rgbBlue = i;  

    bmi->bmiColors[i].rgbGreen= i;  

    bmi->bmiColors[i].rgbRed= i;  

    }  

    break;  

    case 32:  

    case 24:  

    ((DWORD*) bmi->bmiColors)[0] = 0x00FF0000; /* red mask */ 

    ((DWORD*) bmi->bmiColors)[1] = 0x0000FF00; /* green mask */ 

    ((DWORD*) bmi->bmiColors)[2] = 0x000000FF; /* blue mask */ 

    break;  

    }  

    hBmp = ::CreateDIBSection(hDC,bmi,DIB_RGB_COLORS,NULL,0,0);  

    SetDIBits(hDC,hBmp,0,pImg->height,pImg->imageData,bmi,DIB_RGB_COLORS);  

    ::DeleteDC(hDC);  

return hBmp;  

 

 

11、圖像分割

做分水嶺圖像分割:cvWatershed

meanshift圖像分割:PyrMeanShiftFiltering

用金字塔實現圖像分割:cvPyrSegmentation

http://blog.csdn.net/gnuhpc/archive/2009/06/21/4286186.aspx

大津算法閾值分割:http://hi.baidu.com/lazycat3611/blog/item/491febde06bc605d94ee37e8.html

最大熵閾值分割算法:http://www.aiseminar.cn/html/00/t-700.html

 

12、邊緣檢測

cvCanny:採用 Canny 算法做邊緣檢測

cvLaplace:laplace邊緣檢測

http://www.mvonline.com.cn/bbs/simple/index.php?t2421.html

cvSobel:Sobel邊緣檢測

cvCornerHarris:哈里斯(Harris)邊緣檢測

 

13、匹配

cvCalcEMD2:兩個加權點集之間計算最小工作距離

cvMatchShapes:比較兩個形狀

cvMatchTemplate:比較模板和重疊的圖像區域

基於opencv的sift圖像匹配算法vc++源碼:http://codechina.net/source/620393

 

14、分類器

boosted分類器:分類器的boosting技術有四種: Discrete Adaboost, Real Adaboost, Gentle Adaboost and Logitboost。

HAAR分類器,自於haar小波運算。

神經網絡分類器

SVM分類器,SVM是一個分類器,原始的SVM是一個兩類分類的分類器。可以通過1:1或者1:n的方式來組合成一個多類分類的分類器。天生通過核函數的使用支持高維數據的分類。從幾何意義上講,就是找到最能表示類別特徵的那些向量(支持向量SV),然後找到一條線,能最大化分類的 Margin。libSVM是一個不錯的實現。

http://blog.csdn.net/byxdaz/archive/2009/11/28/4893935.aspx

 

15、如何用OpenCV訓練自己的分類器

http://blog.csdn.net/byxdaz/archive/2009/11/30/4907211.aspx

 

16、運動目標跟蹤與檢測

CamShift:

MeanShift:

http://blog.csdn.net/xauatnwpu/archive/2009/10/29/4743058.aspx

 

17、目標檢測

目標檢測:http://wenjuanhe.blog.163.com/blog/static/745017252009102101728454/

人臉檢測的代碼分析:

http://wenjuanhe.blog.163.com/blog/static/74501725200910391512151/

基於Haar-like特徵的層疊推進分類器快速目標檢測:

http://wenjuanhe.blog.163.com/blog/static/7450172520091039180911/

 

18、檢測直線、圓、矩形

檢測直線:cvHoughLines,cvHoughLines2

檢測圓:cvHoughCircles

檢測矩形:opencv中沒有對應的函數,下面有段代碼可以檢測矩形,是通過先找直線,然後找到直線平行與垂直的四根線。

http://blog.csdn.net/byxdaz/archive/2009/12/01/4912136.aspx 

 

  

 

19、直方圖

typedef struct CvHistogram
{
int     type;
CvArr* bins; //用於存放直方圖每個灰度級數目的數組指針,數組在cvCreateHist 的時候創建,其維數由cvCreateHist 確定
float   thresh[CV_MAX_DIM][2]; // for uniform histograms 
float** thresh2; // for non-uniform histograms 
CvMatND mat; // embedded matrix header for array histograms 
}CvHistogram;

創建直方圖 CvHistogram* cvCreateHist( int dims, int* sizes, int type,float** ranges=NULL, int uniform=1 );
dims 直方圖維數的數目 
sizes 直方圖維數尺寸的數組 
type 直方圖的表示格式: CV_HIST_ARRAY 意味着直方圖數據表示爲多維密集數組 CvMatND; CV_HIST_TREE 意味着直方圖數據表示爲多維稀疏數組 CvSparseMat. 
ranges 圖中方塊範圍的數組. 它的內容取決於參數 uniform 的值。這個範圍的用處是確定何時計算直方圖或決定反向映射(backprojected ),每個方塊對應於輸入圖像的哪個/哪組值。 
uniform 歸一化標識。 如果不爲0,則ranges[i](0<=i<cDims,譯者注:cDims爲直方圖的維數,對於灰度圖爲1,彩色圖爲3)是包含兩個元素的範圍數組,包括直方圖第i維的上界和下界。在第i維上的整個區域 [lower,upper]被分割成 dims[i] 個相等的塊(譯者注:dims[i]表示直方圖第i維的塊數),這些塊用來確定輸入象素的第 i 個值(譯者注:對於彩色圖像,i確定R, G,或者B)的對應的塊;如果爲0,則ranges[i]是包含dims[i]+1個元素的範圍數組,包括lower0, upper0, lower1, upper1 == lower2, ..., upperdims[i]-1, 其中lowerj 和upperj分別是直方圖第i維上第 j 個方塊的上下界(針對輸入象素的第 i 個值)。

OpenCV統計應用-CvHistogram直方圖資料:http://blog.csdn.net/koriya/archive/2008/11/21/3347369.aspx

20、物體跟蹤
http://blog.csdn.net/gnuhpc/category/549384.aspx?PageNumber=4

21、在opencv中暫時無法打開二值圖像,它裏面至少是8位的圖像。0,表示黑點;255,表示白點。


22、cvcanny   Canny 算法做邊緣檢測 
void cvCanny( const CvArr* image, CvArr* edges, double threshold1,double threshold2, int aperture_size=3 );
一般threshold=threshol2*0.4 (經驗值)。


23、cvCopy與cvCloneImage的區別 
/* Copies source array to destination array */
CVAPI(void)  cvCopy( const CvArr* src, CvArr* dst,
                     const CvArr* mask CV_DEFAULT(NULL) );

/* Creates a copy of IPL image (widthStep may differ) */
CVAPI(IplImage*) cvCloneImage( const IplImage* image );

如果設定了ROI等參數的時候,cvCopy只是複製被設定的區域,複製到一個和所設定參數相吻合的新的IplImage中
而cvCloneImage則是將整個IplImage結構複製到新的IplImage中,其中的ROI等參數也會一同複製。新的IplImage將會和原來的一模一樣。

cvCopy的原型是:
void cvCopy( const CvArr* src, CvArr* dst, const CvArr* mask=NULL );
在使用這個函數之前,你必須用cvCreateImage()一類的函數先開一段內存,然後傳遞給dst。cvCopy會把src中的數據複製到dst的內存中。如果mask(x,y)=0,則不對src/dst的(x,y)操作操作;如果mask(x,y)!=0, 則操作。

cvCloneImage的原型是:
IplImage* cvCloneImage( const IplImage* image );
在使用函數之前,不用開闢內存。該函數會自己開一段內存,然後複製好image裏面的數據,然後把這段內存中的數據返回給你。

clone是把所有的都複製過來,也就是說不論你是否設置Roi,Coi等影響copy的參數,clone都會原封不動的克隆過來。
copy就不一樣,只會複製ROI區域等。用clone複製之後,源圖像在內存中消失後,複製的圖像也變了,而用copy複製,源圖像消失後,複製的圖像不變。

使用cvCopy實現對不規制圖形的提取:http://artificialwistom.spaces.live.com/blog/cns!C4334BEEE0193F50!191.entry


24、圖像形態學操作
http://blog.csdn.net/byxdaz/archive/2010/07/30/5775717.aspx

 

四、書籍推薦:

《opencv教程基礎篇》大部分爲OpenCV幫助手冊的翻譯,原創性內容不是很多。

《Learning OpenCV》深入淺出講OpenCV函數背後的原理,比課堂教材生動且實用,極具實戰功能。

http://download.csdn.net/source/1860888

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章