2015年10月31日 星期六

OpenCV 2.4 的物件追蹤(Object Tracking)– cvMoments 函數

OpenCV 2.4 的物件追蹤(Object Tracking)– cvMoments 函數: 

物件偵測(Object Detection)的程式完成後,想利用 OpenCV 編寫一個可以追蹤物件(Object Tracking)的程式,當然是為了智能小車作物件追蹤,將物件的特性設定好,智能小車便會追蹤或找尋物件。其實物件追蹤程式是將物件偵測後的位置記錄下來,然後再處理圖片,從矩狀態找出物件位置(XY),將物件位置記錄,並一直保存在位置圖片上,再合成影像圖片和位置圖片,最後顯示合成圖片便可以。

OpenCV 2.4 的物件追蹤(Object Tracking
cvMoments 求取圖像的重心函數: 
void cvMoments( const CvArr* arr, CvMoments* moments, int binary=0 ); 

參數說明如下: 
1arr = 圖像 (1-通道或 3-通道,有 COI 設置) 或多邊形(點的 CvSeq 或一族點的向量)
2moments = 返回的矩狀態介面的指針。
3binary = (僅對圖像) 如果標識為非零,則所有零象素點被當成零,其他的被看成 1

函數 cvMoments 計算最高達三階的空間和中心矩,並且將結果存在結構 moments 中。矩用來計算形狀的重心,面積,主軸和其他的形狀特徵,如 7 Hu 不變數等 

cvGetSpatialMoment 從矩狀態結構中提取空間矩函數: 
double cvGetSpatialMoment( CvMoments* moments, int x_order, int y_order ); 

參數說明如下: 
1moments = 矩狀態,由 cvMoments 計算。 
2x_order = 提取的 x 次矩,x_order >= 0 
3y_order = 提取的 y 次矩,y_order >= 0 並且 x_order + y_order <= 3 

函數 cvGetSpatialMoment 提取空間矩,當圖像矩被定義為: 
Mx_order,y_order=sumx,y(I(x,y)xx_orderyy_order),其中 I(x,y) 是象素點 (x, y) 的亮度值。

GetCentralMoment 從矩狀態結構中提取中心矩函數:
double cvGetCentralMoment( CvMoments* moments, int x_order, int y_order ); 

參數說明如下: 
1moments = 矩狀態結構指針。 
2x_order = 提取的 x 階矩,x_order >= 0
3y_order = 提取的 y 階矩,y_order >= 0 x_order + y_order <= 3

函數 cvGetCentralMoment 提取中心矩,其中圖像矩的定義是:
μx_order,y_order=sumx,y(I(x,y)(x-xc)x_order(y-yc)y_order),其中 xc=M10/M00, yc=M01/M00 - 重心坐標。

物件追蹤(Object Tracking)程式:
// 物件追蹤(Object Tracking)程式
// cvMoments 函數

     img_dest=cvCloneImage(img_source);

     // First tracking to setup imgTracking Image
      if (track == 0) {
    
//create a blank image and assigned to 'imgTracking' which has the same size of original video
           imgTracking=cvCreateImage(cvGetSize(img_source),IPL_DEPTH_8U, 3);
           cvZero(imgTracking); //covert the image, 'imgTracking' to black
           lastX = -1;
           lastY = -1;
           track = 1;}

      // Repeat functions in below
//smooth the original image using Gaussian kernel
         cvSmooth(img_dest, img_dest, CV_GAUSSIAN,3,3);

     IplImage* imgHSV = cvCreateImage(cvGetSize(img_dest), IPL_DEPTH_8U, 3);
     cvCvtColor(img_dest, imgHSV, CV_BGR2HSV); //Change the color format from BGR to HSV
           
     //This function threshold the HSV image and create a binary image
     IplImage* imgThresh=cvCreateImage(cvGetSize(imgHSV),IPL_DEPTH_8U, 1);
     cvInRangeS(imgHSV, cvScalar(170,160,60), cvScalar(180,2556,256), imgThresh);

     //smooth the binary image using Gaussian kernel
     cvSmooth(imgThresh, imgThresh, CV_GAUSSIAN,3,3);
           
     /// Calculate the moments of 'imgThresh'
     CvMoments *moments = (CvMoments*)malloc(sizeof(CvMoments));
    cvMoments(imgThresh, moments, 1);
     double moment10 = cvGetSpatialMoment(moments, 1, 0);
    double moment01 = cvGetSpatialMoment(moments, 0, 1);
    double area = cvGetCentralMoment(moments, 0, 0);

    if(area>1000){
        // calculate the position of the ball
        int posX = moment10/area;
        int posY = moment01/area;       
       
       if(lastX>=0 && lastY>=0 && posX>=0 && posY>=0)
        {
            // Draw a yellow line from the previous point to the current point
4);
            cvLine(imgTracking, cvPoint(posX, posY), cvPoint(lastX, lastY), cvScalar(0,0,255), 20);
        }
        lastX = posX;
        lastY = posY;
     }
   free(moments);

                // Add the tracking image and the frame
                cvAdd(img_dest, imgTracking, img_dest);

     // create window and show the image in PictureBox2 Format24bppRgb Format8bppIndexed
        pictureBox2->Image  = gcnew System::Drawing::Bitmap(img_dest->width,img_dest->height,
                img_dest->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb,
                (System::IntPtr) img_dest->imageData);
                pictureBox2->Refresh();

                //Clean up used images
                cvReleaseImage(&imgHSV);
                cvReleaseImage(&imgThresh);           
                cvReleaseImage(&img_dest);

                //Clean up used Memory
                cvReleaseMemStorage(&storage);
                //Clean up used Memory
                cvReleaseMemStorage(&storage);

操作系統:Windows XP 32-bit 
操作環境:Windows Visual Studio 2010 + OpenCV 2.4.8

相關網址:
※ 在 Windows XP Visual Studio 2010 安裝 OpenCV 2.4
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 第一個程式
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 安裝使用 FFmpeg 函數庫
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 顯示 IPCam 串流視頻
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 導入屬性工作表文件檔
※ 在 Windows XP Visual Studio 2010 使用 Windows From OpenCV 2.4 配置
※ 在 OpenCV 2.4 的 IplImage 資料結構
※ OpenCV 2.4 的坎尼圖像邊緣檢測(Canny Edge Detection) – Canny 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLines 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLinesP 函數
※ OpenCV 2.4 的人臉偵測(Face Detection)– cvHaarDetectObjects 函數
※ OpenCV 2.4 的物件偵測(Object Detection)– cvHoughCircles 函數
※ OpenCV 2.4 的物件追蹤(Object Tracking)– cvMoments 函數

參考網址:
※ Cv圖像處理

2015 年 10月 31日 天氣報告
氣溫:25.1@ 21:20
相對濕度:百分之 79%
天氣:大致多雲

2015年10月29日 星期四

OpenCV 2.4 的物件偵測(Object Detection)– cvHoughCircles 函數

OpenCV 2.4 的物件偵測(Object Detection)– cvHoughCircles 函數: 

OpenCV 除了可以偵測人臉外,其實還可以偵測其他形狀的物件,這次是要作圓形物件偵測,會使用到霍夫圓形偵測 (cvHoughCircles)函數,函數是通過一個叫做“霍夫梯度法”的方法來解決圓變換的問題,需要注意的是霍夫圓變換對圖像的要求,是輸入的圖像必須是灰度圖像,在使用方法 CV_HOUGH_GRADIENT 時,後面兩個參數 param1 param2 分別是邊緣閾值(Canny)和累加器的閾值,而 Canny 的另外一個閾值則會自動設置為 param1 的一半。

OpenCV 2.4 的物件偵測(Object Detection
cvHoughCircles 函數:
CvSeq* cvHoughCircles( CvArr* image, void* circle_storage, 
                       int method, double dp, double min_dist, 
                       double param1=100, double param2=100, 
                       int min_radius=0, int max_radius=0 );

參數說明如下:
1image = 輸入 8-比特、單通道灰度圖像。
2circle_storage = 檢測到的圓存儲倉. 可以是記憶體存儲倉 (此種情況下,一個線段序列在存儲倉中被創建,並且由函數返回)或者是包含圓參數的特殊類型的具有單行/單列的 CV_32FC3 型矩陣 (CvMat*)矩陣頭為函數所修改,使得它的 cols/rows 將包含一組檢測到的圓。如果 circle_storage 是矩陣,而實際圓的數目超過矩陣尺寸,那麼最大可能數目的圓被返回每個圓由三個浮點數表示:圓心坐標 (x,y) 和半徑。 
3method = Hough 變換方式,目前只支持 CV_HOUGH_GRADIENT 
4dp = 累加器圖像的解析度。這個參數允許創建一個比輸入圖像解析度低的累加器。(這樣做是因為有理由認為圖像中存在的圓會自然降低到與圖像寬高相同數量的範疇)。如果 dp 設置為 1,則解析度是相同的;如果設置為更大的值(比如2),累加器的解析度受此影響會變小(此情況下為一半)。dp 的值不能比 1 小。 
5min_dist = 該參數是讓演算法能明顯區分的兩個不同圓之間的最小距離。 
6param1 = 用於 Canny 的邊緣閥值上限,下限被置為上限的一半。 
7param2 = 累加器的閥值。
8min_radius = 最小圓半徑。 
9max_radius = 最大圓半徑。 

結果: 
circles[0] = 圓中心的 X座標 
circles[1] = 圓中心的 Y座標 
circles[2] = 圓半径

物件偵測(Object Detection)程式:
// 物件偵測(Object Detection)程式
// cvHoughCircles 函數

     // Copy Image Source to Image Destination
     img_dest=cvCloneImage(img_source);
    
     // Converting the Image Source into Grayscale
    IplImage* img_gray = cvCreateImage(cvGetSize(img_dest), IPL_DEPTH_8U, 1);
    cvCvtColor(img_dest, img_gray, CV_BGR2GRAY);

    // Prevent a lot of false circles from being detected
    cvSmooth(img_gray, img_gray, CV_GAUSSIAN, 5, 7);

     // Create Memory Storage 0 = 64kb
    CvMemStorage* storage = cvCreateMemStorage(0);

     // Hold the sequence of pointer of a circles and store in Memory
    CvSeq* circles = cvHoughCircles(img_gray, storage, CV_HOUGH_GRADIENT, 1, img_gray->height/8, 250, 100);

         //for (size_t i = 0; i < circles->total; i++)
     for (size_t i = 0; i < circles->total; i++)
    {
         // round the floats to an int
         float* p = (float*)cvGetSeqElem(circles, i);
         cv::Point center(cvRound(p[0]), cvRound(p[1]));
         int radius = cvRound(p[2]);

         // draw the circle outline
            cvCircle(img_dest, center, radius+1, CV_RGB(0,0,255), 20, 8, 0 );

    }

     // create window and show the image in PictureBox2 Format24bppRgb Format8bppIndexed
     pictureBox2->Image  = gcnew System::Drawing::Bitmap(img_dest->width,img_dest->height,
                img_dest->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb,
                (System::IntPtr) img_dest->imageData);
                pictureBox2->Refresh();

                textBox1->Text = Convert::ToString(circles->total);

                //Clean up used images
                cvReleaseImage(&img_gray);
                cvReleaseImage(&img_dest);

                //Clean up used Memory
                cvReleaseMemStorage(&storage);

操作系統:Windows XP 32-bit 
操作環境:Windows Visual Studio 2010 + OpenCV 2.4.8

相關網址:
※ 在 Windows XP Visual Studio 2010 安裝 OpenCV 2.4
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 第一個程式
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 安裝使用 FFmpeg 函數庫
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 顯示 IPCam 串流視頻
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 導入屬性工作表文件檔
※ 在 Windows XP Visual Studio 2010 使用 Windows From OpenCV 2.4 配置
※ 在 OpenCV 2.4 的 IplImage 資料結構
※ OpenCV 2.4 的坎尼圖像邊緣檢測(Canny Edge Detection) – Canny 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLines 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLinesP 函數
※ OpenCV 2.4 的人臉偵測(Face Detection)– cvHaarDetectObjects 函數
※ OpenCV 2.4 的物件偵測(Object Detection)– cvHoughCircles 函數
※ OpenCV 2.4 的物件追蹤(Object Tracking)– cvMoments 函數

參考網址:
※ Face Detection using OpenCV

2015 年 10月 29日 天氣報告
氣溫:26.1@ 20:00
相對濕度:百分之 84%
天氣:大致多雲

2015年10月24日 星期六

OpenCV 2.4 的人臉偵測(Face Detection)– cvHaarDetectObjects 函數

OpenCV 2.4 的人臉偵測(Face Detection)– cvHaarDetectObjects 函數: 

現在當大家使用數碼相機拍攝人像時,都會用到人臉偵測技術,在數碼相機對焦一群人時,焦點都會落在每個人臉上,快門按下,拍攝出來的相片都是清晰人臉,不會出現有失焦的情況。在 OpenCV 內已經具有 Face Detection 函數,人臉檢測(Face Detection)是一種在任意數字圖像中找到人臉的位置和大小的計算機技術,其實 Face Detection 基本原理是先做 Feature Extraction,接著做 Cascade Detection,擷取圖像特徵 (Feature Extraction),偵測檢查特徵,並處理特徵辨識的部位,當然就是眼睛、鼻子和嘴巴。

OpenCV 2.4 的人臉偵測(Face Detection
其中函數 cvHaarDetectObjects 使用針對某目標物體訓練的級聯分類器在圖像中找到包含目標物體的矩形區域,並且將這些區域作為一序列的矩形框返回。函數以不同比例大小的掃描視窗對圖像進行幾次搜索。每次都要對圖像中的這些重疊區域利用 cvRunHaarClassifierCascade 進行檢測。有時候也會利用某些繼承(heuristics)技術以減少分析的候選區域,例如利用 Canny 裁減(pruning)方法。函數在處理和收集到候選的方框(全部通過級聯分類器各層的區域)科之後,接著對這些區域進行組合並且返回一系列各個足夠大的組合中的平均矩形。調節程式中的缺省參數(scale_factor=1.1, min_neighbors=3, flags=0)用於對目標進行更精確同時也是耗時較長的進一步檢測。為了能對視頻圖像進行更快的即時檢測,參數設置通常是:scale_factor=1.2min_neighbors=2flags=CV_HAAR_DO_CANNY_PRUNINGmin_size = 

cvHaarDetectObjects 函數:
cvHaarDetectObjects(const CvArr* image, CvHaarClassifierCascade* cascade,
                               CvMemStorage* storage, double scale_factor=1.1,
                               int min_neighbors=3, int flags=0,
                               CvSize min_size=cvSize(0,0) );

參數說明如下:
1image = 表示要偵測的圖片。 
2cascade = 要使用的分類器,在第一個步驟所載入的分類器。 
3storage = 偵測到的物件所儲存的記憶體區塊。 
4scale_factor = 搜索視窗成長比率。 
5min_neighbors = 最少鄰近偵測視窗。一個臉可能重複偵測好幾次,但我們只要取一次,如果設 0 的話,所有偵測的視窗都會畫出來。
6flag = 演算法模式。 
7min_size = 檢測視窗的最小尺寸。因為 AdaBoost 的演算法,分成搜索視窗和檢測視窗兩個部分,搜索視窗在整個影像中移動,檢測視窗在搜索視窗中移動並計算特徵值。當檢測視窗越小,則計算特徵值的單位就越小,需要的運算量就越高,但是結果不一定會更為精確。 

簡單介紹與描述:  
Frontal Face stump        24x24, 20x20gentle, 20x20tree 
Profile Face                    20x20 
Frontal eyes (both eyes)    25*1
Frontal eyes (both eyes)    25*15
Right Eye               18x12 
Left Eye                  18x12 
Frontal Eyes           22x5 
Mouth                      25x15 
Nose                       25x15
righteye_2splits     20x20
lefteye_2splits       20x20

cvHaarDetectObjects函數
人臉訓練集(haarcascade_frontalface_default.xml):
使用 Cascade Adaboost 分類器作為學習機制,OpenCV 的分類器會放在 C:\OpenCV2.4\opencv\data\haarcascades 內,而分類器中的級聯是指最終的分類器是由幾個簡單分類器級聯組成。在圖像檢測中,被檢視窗依次通過每一級分類器,這樣在前面幾層的檢測中大部分的候選區域就被排除了,全部通過每一級分類器檢測的區域即為目標區域。目前支持這種分類器的 boosting 技術有四種:Discrete AdaboostReal AdaboostGentle Adaboost and Logitboostboosted 即指級聯分類器的每一層都可以從中選取一個 boosting 演算法(權重投票),並利用基礎分類器的自我訓練得到。

人臉訓練集(haarcascade_frontalface_default.xml
下面的範例程式裡面,使用了 Haar feature做為辨識特徵,使用 Cascade Adaboost 分類器作為學習機制。這個範例程式是 OpenCV 安裝完以後附帶範例的簡化版本。

人臉偵測(Face Detection)程式:
// 人臉偵測(Face Detection)程式
// cvHaarDetectObjects 函數
// 使用 haarcascade_frontalface_default.xml 分類器

// 讀取 Cascade 分類器
if (!cascade){
     storage=cvCreateMemStorage(0); // 建立一個指定大小的記憶體區塊 0=64k
     cvFirstType();
     file_name="C:\\haarcascade_frontalface_alt.xml"; // 分類器
     cascade = (CvHaarClassifierCascade*)cvLoad(file_name);
     cvClearMemStorage(storage);
     }

// 設定圖像
image = frame;

// 偵測人臉
faces = cvHaarDetectObjects( image, cascade, storage, 1.1, 2,
CV_HAAR_DO_CANNY_PRUNING,cvSize(20, 10));

// 偵測到的人臉和框
if (faces){
     for(i=0;itotal; ++i ){
           CvRect* r = (CvRect*)cvGetSeqElem( faces, i );
           pt1.x = r->x;
           pt2.x = (r->x+r->width);
           pt1.y = r->y;
           pt2.y = (r->y+r->height);
           cvRectangle( image, pt1, pt2, CV_RGB(255,0,0), 3, 8, 0 );
           }
}

// 畫出偵測到的人臉框
pictureBox2->Image  = gcnew System::Drawing::Bitmap(frame->width,frame->height,
frame->widthStep,System::Drawing::Imaging::PixelFormat::Format24bppRgb,
(System::IntPtr) image->imageData);
pictureBox2->Refresh();

操作系統:Windows XP 32-bit 
操作環境:Windows Visual Studio 2010 + OpenCV 2.4.8

相關網址:
※ 在 Windows XP Visual Studio 2010 安裝 OpenCV 2.4
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 第一個程式
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 安裝使用 FFmpeg 函數庫
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 使用 WebCam
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 顯示 IPCam 串流視頻
※ 在 Windows XP Visual Studio 2010 使用 OpenCV 2.4 導入屬性工作表文件檔
※ 在 Windows XP Visual Studio 2010 使用 Windows From OpenCV 2.4 配置
※ 在 OpenCV 2.4 的 IplImage 資料結構
※ OpenCV 2.4 的坎尼圖像邊緣檢測(Canny Edge Detection) – Canny 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLines 函數
※ OpenCV 2.4 的霍夫直線偵測轉換 – HoughLinesP 函數
※ OpenCV 2.4 的人臉偵測(Face Detection)– cvHaarDetectObjects 函數
※ OpenCV 2.4 的物件偵測(Object Detection)– cvHoughCircles 函數
※ OpenCV 2.4 的物件追蹤(Object Tracking)– cvMoments 函數

參考網址:
※ Face Detection using OpenCV

2015 年 10月 24日 天氣報告
氣溫:26.4@ 23:20
相對濕度:百分之 91%
天氣:多雲