2012-08-11 77 views
1

我用程序檢測圖像中的正方形。這與我從互聯網下載的圖像效果很好。但我應該做的是檢測從相機拍攝的圖像的正方形。首先我從視頻中提取圖像,然後嘗試從這些圖像集合中檢測出正方形,但代碼不適用於那些提取的圖像(但與其他圖像協同工作)。我該怎麼做才能完成這項任務?使用opencv2.4檢測正方形

#ifdef _CH_ 
#pragma package <opencv> 
#endif 

#define CV_NO_BACKWARD_COMPATIBILITY 

#include <opencv2/opencv.hpp> 
#include "stdafx.h" 
#include "cv.h" 
#include "highgui.h" 
#include <stdio.h> 
#include <math.h> 
#include <string.h> 

int thresh = 50; 
IplImage* img = 0; 
IplImage* img0 = 0; 
CvMemStorage* storage = 0; 
//const char* wndname = "Square Detection Demo"; 

// helper function: 
// finds a cosine of angle between vectors 
// from pt0->pt1 and from pt0->pt2 
double angle(CvPoint* pt1, CvPoint* pt2, CvPoint* pt0) 
{ 
    double dx1 = pt1->x - pt0->x; 
    double dy1 = pt1->y - pt0->y; 
    double dx2 = pt2->x - pt0->x; 
    double dy2 = pt2->y - pt0->y; 
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); 
} 

// returns sequence of squares detected on the image. 
// the sequence is stored in the specified memory storage 
CvSeq* findSquares4(IplImage* img, CvMemStorage* storage) 
{ 
    CvSeq* contours; 
    int i, c, l, N = 11; 
    CvSize sz = cvSize(img->width & -2, img->height & -2); 
    IplImage* timg = cvCloneImage(img); // make a copy of input image 
    IplImage* gray = cvCreateImage(sz, 8, 1); 
    IplImage* pyr = cvCreateImage(cvSize(sz.width/2, sz.height/2), 8, 3); 
    IplImage* tgray; 
    CvSeq* result; 
    double s, t; 
    // create empty sequence that will contain points - 
    // 4 points per square (the square's vertices) 
    CvSeq* squares = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvPoint), storage); 

    // select the maximum ROI in the image 
    // with the width and height divisible by 2 
    cvSetImageROI(timg, cvRect(0, 0, sz.width, sz.height)); 

    // down-scale and upscale the image to filter out the noise 
    cvPyrDown(timg, pyr, 7); 
    cvPyrUp(pyr, timg, 7); 
    tgray = cvCreateImage(sz, 8, 1); 

    // find squares in every color plane of the image 
    for(c = 0; c < 3; c++) 
    { 
     // extract the c-th color plane 
     cvSetImageCOI(timg, c+1); 
     cvCopy(timg, tgray, 0); 

     // try several threshold levels 
     for(l = 0; l < N; l++) 
     { 
      // hack: use Canny instead of zero threshold level. 
      // Canny helps to catch squares with gradient shading 
      if(l == 0) 
      { 
       // apply Canny. Take the upper threshold from slider 
       // and set the lower to 0 (which forces edges merging) 
       cvCanny(tgray, gray, 0, thresh, 5); 
       // dilate canny output to remove potential 
       // holes between edge segments 
       cvDilate(gray, gray, 0, 1); 
      } 
      else 
      { 
       // apply threshold if l!=0: 
       //  tgray(x,y) = gray(x,y) < (l+1)*255/N ? 255 : 0 
       cvThreshold(tgray, gray, (l+1)*255/N, 255, CV_THRESH_BINARY); 
      } 

      // find contours and store them all as a list 
      cvFindContours(gray, storage, &contours, sizeof(CvContour), 
       CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0)); 

      // test each contour 
      while(contours) 
      { 
       // approximate contour with accuracy proportional 
       // to the contour perimeter 
       result = cvApproxPoly(contours, sizeof(CvContour), storage, 
        CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0); 
       // square contours should have 4 vertices after approximation 
       // relatively large area (to filter out noisy contours) 
       // and be convex. 
       // Note: absolute value of an area is used because 
       // area may be positive or negative - in accordance with the 
       // contour orientation 
       if(result->total == 4 && 
        cvContourArea(result,CV_WHOLE_SEQ,0) > 1000 && 
        cvCheckContourConvexity(result)) 
       { 
        s = 0; 

        for(i = 0; i < 5; i++) 
        { 
         // find minimum angle between joint 
         // edges (maximum of cosine) 
         if(i >= 2) 
         { 
          t = fabs(angle(
          (CvPoint*)cvGetSeqElem(result, i), 
          (CvPoint*)cvGetSeqElem(result, i-2), 
          (CvPoint*)cvGetSeqElem(result, i-1))); 
          s = s > t ? s : t; 
         } 
        } 

        // if cosines of all angles are small 
        // (all angles are ~90 degree) then write quandrange 
        // vertices to resultant sequence 
        if(s < 0.3) 
         for(i = 0; i < 4; i++) 
          cvSeqPush(squares, 
           (CvPoint*)cvGetSeqElem(result, i)); 
       } 

       // take the next contour 
       contours = contours->h_next; 
      } 
     } 
    } 

    // release all the temporary images 
    cvReleaseImage(&gray); 
    cvReleaseImage(&pyr); 
    cvReleaseImage(&tgray); 
    cvReleaseImage(&timg); 

    return squares; 
} 


// the function draws all the squares in the image 
void drawSquares(IplImage* img, CvSeq* squares) 
{ 
    CvSeqReader reader; 
    IplImage* cpy = cvCloneImage(img); 
    int i; 

    // initialize reader of the sequence 
    cvStartReadSeq(squares, &reader, 0); 

    // read 4 sequence elements at a time (all vertices of a square) 
    for(i = 0; i < squares->total; i += 4) 
    { 
     CvPoint pt[4], *rect = pt; 
     int count = 4; 

     // read 4 vertices 
     CV_READ_SEQ_ELEM(pt[0], reader); 
     CV_READ_SEQ_ELEM(pt[1], reader); 
     CV_READ_SEQ_ELEM(pt[2], reader); 
     CV_READ_SEQ_ELEM(pt[3], reader); 

     // draw the square as a closed polyline 
     cvPolyLine(cpy, &rect, &count, 1, 1, CV_RGB(0,255,0), 3, CV_AA, 0); 
    } 

    // show the resultant image 
    cvShowImage("Square Detection Demo", cpy); 
    cvReleaseImage(&cpy); 
} 


//char* names[] = { "pic1.png", "pic2.png", "pic3.png", 
       // "pic4.png", "pic5.png", "pic6.png", 0 }; 

int main(int argc, char** argv) 
{ 
    int i, c; 
    // create memory storage that will contain all the dynamic data 
    storage = cvCreateMemStorage(0); 

    //for(i = 0; names[i] != 0; i++) 
    //{ 
    // // load i-th image 
    // img0 = cvLoadImage(names[i], 1); 
    // if(!img0) 
    // { 
    //  printf("Couldn't load %s\n", names[i]); 
    //  continue; 
    // } 
     img0 = cvLoadImage("frame_21.jpg"); 
     img = cvCloneImage(img0); 

     // create window and a trackbar (slider) with parent "image" and set callback 
     // (the slider regulates upper threshold, passed to Canny edge detector) 
     // cvNamedWindow("qq"); 

     // find and draw the squares 
     drawSquares(img, findSquares4(img, storage)); 

     // wait for key. 
     // Also the function cvWaitKey takes care of event processing 
     c = cvWaitKey(0); 
     // release both images 
     cvReleaseImage(&img); 
     cvReleaseImage(&img0); 
     // clear memory storage - reset free space position 
     cvClearMemStorage(storage); 
     /*if((char)c == 27) 
      break;*/ 
    /* }*/ 

// cvDestroyWindow("qq"); 

    return 0; 
} 

這是從視頻----->萃取road sign

回答

1

我測試上它是爲所有圖像工作正常不同的圖像代碼中的樣本圖像,有一個如果條件是findsuqares4函數

   if(result->total == 4 && 
       cvContourArea(result,CV_WHOLE_SEQ,0) > 10000 && 
       cvCheckContourConvexity(result)) 

10000是要檢測的方格的閾值。我的意思是有超過10000的面積的廣場被發現休息都將被丟棄。因此,您需要根據您的要求更改閾值。我上傳了一個閾值爲100的結果。查看結果。

Squares detected

+0

感謝您replying.yes我也有,我從互聯網上下載和代碼給正確的輸出多個圖像檢查代碼。但事情是我應該開發一個檢測道路標誌的系統。系統從攝像頭捕捉視頻,然後從視頻中提取幀。我將從這些提取的圖像中檢測具有方形板(可能是道路標誌或廣告板)的幀,並將這些幀(其具有正方形)發送到其他功能以用於更多作品。附加提取的圖像之一這個問題。有沒有解決這個問題的方法。 – Thar1988 2012-08-11 12:23:54