【原創】opencv 實現特定形狀視頻跟蹤,圖像裁剪

【原創】 opencv 實現特定形狀視頻跟蹤,圖像裁剪

Author: chad
Mail: [email protected]

先看效果:
這裏寫圖片描述

如上圖所示,程序通過攝像頭採集圖像,然後使用cvCanny算子實現邊緣檢測,最後使用cvFindContours查找輪廓,進而根據預設參數尋找對應圖像區域.並完成圖像裁剪與選裝.

程序如下:

/*
    2015-07-24 [email protected]
    編譯命令如下:
    g++ `pkg-config opencv --cflags` main.c -o meter `pkg-config opencv --libs` 
*/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <cv.h>
#include <highgui.h>
#include <cmath>
#include <opencv/highgui.h>
#include <stdio.h>

using namespace std;
//旋轉,縮放
int WarpAffine(IplImage *src, double angle, double scale )
{
   CvPoint2D32f srcTri[3], dstTri[3];
   CvMat* rot_mat = cvCreateMat(2,3,CV_32FC1);
   IplImage *dst;

   dst = cvCloneImage(src);
   dst->origin = src->origin;
   cvZero(dst);

   //COMPUTE ROTATION MATRIX
   CvPoint2D32f center = cvPoint2D32f(src->width/2,
                                         src->height/2);
   cv2DRotationMatrix(center,angle,scale,rot_mat);
   cvWarpAffine(src,dst,rot_mat);
   cvCopy(dst,src);

   cvReleaseImage(&dst);
   cvReleaseMat(&rot_mat);
   return 0;
}
//void callTrackbar( int position )
//{

//}
int main(int argc,char *argv[])
{
    char tmpbuf[100];

    CvCapture* capture ;

    cvNamedWindow("out");
    if( argc != 1 )
        capture = cvCreateFileCapture( argv[1] );   //從視頻文件獲取圖像
    else 
        capture = cvCreateCameraCapture( 1 );       //從視頻設備獲取圖像
    IplImage *frame;
    IplImage *out = NULL;
    IplImage *grayimg = NULL;
    int i = 0;

    double length,area,rectArea;
    double rectDegree = 0.0; //矩形度
    double long2Short = 1.0; //體態比
    int DirectFlag = 0;      //長寬顛倒標準
    //計算邊界序列的參數 長度 面積 矩形 最小矩形 
    //並輸出每個邊界的參數
    CvRect rect;
    CvBox2D box;
    int imageCnt = 1;
    double axisLong = 0.0, axisShort = 0.0;
    double temp;

    frame = cvQueryFrame( capture );  //讀取一幀數據
    if( !frame ) {
        cerr<<"cvQueryFrame fail!"<<endl;
        return -1;
    }
    out = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1); //深度8bit 單通道
    grayimg = cvCreateImage(cvGetSize(frame),IPL_DEPTH_8U,1);
    int cannyMax,cannyMin,threshod;
    cannyMax = 0;
    cannyMin = 50;
    threshod = 0;
    while(1)
    {
        frame = cvQueryFrame( capture );  //讀取一幀數據
        if( !frame ) break;     

        cvCvtColor( frame, grayimg, CV_RGB2GRAY );  //rgb轉換爲灰度圖像
        cvCanny( grayimg, out, cannyMin, cannyMax, 3 );       //邊緣檢測處理
        cvShowImage("cvCanny",out);  //顯示圖像 
        if( !cannyMax ) {
            cannyMax = 150;
            cannyMin = 50;
            cvCreateTrackbar("cannyMax", "cvCanny", &cannyMax, 255, NULL );
            cvSetTrackbarPos( "cannyMax", "cvCanny", cannyMax );
            cvCreateTrackbar("cannyMin", "cvCanny", &cannyMin, 255, NULL );
            cvSetTrackbarPos( "cannyMin", "cvCanny", cannyMin );
        }
        //尋找輪廓
        CvMemStorage *storage = cvCreateMemStorage(0);
        CvSeq * seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
        CvSeq * tempSeq = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);
        int cnt = cvFindContours( out, storage, &seq );//返回輪廓的數目
        cout<<"number of contours   "<<cnt<<endl;

        for (tempSeq = seq;tempSeq != NULL; tempSeq = tempSeq->h_next) 
        {
            length = cvArcLength(tempSeq);
            area =  cvContourArea(tempSeq);

            //篩選面積比較大的區域
            if( area > 10000 ) {
                //外接矩形
                rect = cvBoundingRect(tempSeq,1);
                //繪製輪廓和外接矩形
                //cvDrawContours(frame,tempSeq,CV_RGB(255,0,0),CV_RGB(255,0,0),0);
                //cvRectangleR(frame,rect,CV_RGB(0,255,0));
                //cvShowImage("dst",frame);
                //cvWaitKey(0);
                //繪製外接最小矩形
                CvPoint2D32f pt[4];
                box = cvMinAreaRect2(tempSeq,0);
                cvBoxPoints(box,pt);
                //下面開始分析圖形的形狀特徵 
                //長軸 短軸
                axisLong = sqrt(pow(pt[1].x -pt[0].x,2) + pow(pt[1].y -pt[0].y,2));
                axisShort = sqrt(pow(pt[2].x -pt[1].x,2) + pow(pt[2].y -pt[1].y,2));

                DirectFlag = 0;
                if( axisShort > axisLong ) {  
                    temp = axisLong;
                    axisLong = axisShort;
                    axisShort= temp;
                    DirectFlag = 1;
                }
                rectArea = axisLong * axisShort; 
                rectDegree =  area / rectArea;  
                //體態比or長寬比 最下外接矩形的長軸和短軸的比值
                long2Short = axisLong/axisShort;
                cout<<"long2Short:   "<<long2Short<<endl;
                cout<<"rectDegree:   "<<rectDegree<<endl;
                cout<<"rectArea  :   "<<rectArea<<endl;
                if( long2Short> 1.5 && long2Short < 1.8 && rectDegree > 0.9 && rectArea > 10000 && rectArea < 80000 )
                {
                    cout<<"Length:  "<<length<<endl;
                    cout<<"Area  :  "<<area<<endl;
                    cout<<"long axis : "<<axisLong<<endl;
                    cout<<"short axis: "<<axisShort<<endl;
                    cout<<"long2Short: "<<long2Short<<endl;
                    cout<<"rectArea  : "<<rectArea<<endl;
                    cout<<"rectDegree: "<<rectDegree<<endl;

                    for(int i = 0;i<4;++i) {
                        cvLine(frame,cvPointFrom32f(pt[i]),cvPointFrom32f(pt[((i+1)%4)?(i+1):0]),CV_RGB(255,0,0));
                    }
                    cvShowImage("out",frame);
                    IplImage *cutimg = NULL;
                    IplImage *cutthreshimg = NULL,*cuttmpimg;

                    cvSetImageROI(frame,rect);

                    cutimg = cvCreateImage(cvSize(rect.width,rect.height),IPL_DEPTH_8U,3);
                    cutthreshimg = cvCreateImage(cvGetSize(cutimg),IPL_DEPTH_8U,1);
                    cuttmpimg = cvCreateImage(cvGetSize(cutimg),IPL_DEPTH_8U,1);

                    cvCopy(frame,cutimg,0);
                    //cvCvtColor( cutimg, cutthreshimg, CV_RGB2GRAY ); //rgb轉換爲灰度圖像
                    //cvThreshold( cuttmpimg, cutthreshimg, threshod, 255, CV_THRESH_BINARY );//圖像二值化
                    //cvAdaptiveThreshold( cuttmpimg, cutthreshimg, 255, CV_ADAPTIVE_THRESH_GAUSSIAN_C/*CV_ADAPTIVE_THRESH_MEAN_C*/, 
                    //                     CV_THRESH_BINARY, 3, 5 ); //自適應閾值化
                    //cout<<"box.angle:  "<<box.angle<<endl;
                    //圖像旋轉
                    if( abs(box.angle) < 90 ) //旋轉角度在0度附近時會出現0<>90 震盪! 實際使用時旋轉角度也不會超過30度!
                        WarpAffine( cutimg, DirectFlag ?box.angle:box.angle+90, 1.0 );
                        //WarpAffine( cutthreshimg, DirectFlag ?box.angle:box.angle+90, 1.0 );
                    cvShowImage("cutimg",cutimg);
                    if( !threshod ) {
                        threshod = 150;
                        cvCreateTrackbar("cvThreshold", "cutimg", &threshod, 255, NULL );
                        cvSetTrackbarPos( "cvThreshold", "cutimg", threshod );
                    }
                    cvResetImageROI(frame);

                    cvReleaseImage( &cutimg );
                    cvReleaseImage( &cuttmpimg );
                    cvReleaseImage( &cutthreshimg );
                }
            }
        }
        char c = cvWaitKey(50);   //等待按鍵輸入
        if( c == 27 ) {
            cvReleaseMemStorage( &storage );
            break;
        }
    }       

    cvReleaseCapture( &capture );
    cvReleaseImage( &frame );
    cvReleaseImage( &out );
    cvReleaseImage( &grayimg );
    cvDestroyWindow("out");

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