如何在MemoryStorage中绘制单个轮廓

时间:2014-05-26 15:30:44

标签: c++ opencv detection

我试图在C ++中使用OpenCv Library检测图像中最大的轮廓。我的算法正在努力检测所有的轮廓并完美地绘制它们。但今天我试图只画出最大的一个。

这是我在C ++中使用OpenCV的代码:

#include <cv.h>
#include <highgui.h>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include <iostream>
#include <stdio.h>

using namespace std;

int main()
{

IplImage* img =  cvLoadImage("contour.png");

//show the original image
cvNamedWindow("Raw");
cvShowImage("Raw",img);

//converting the original image into grayscale
IplImage* imgGrayScale = cvCreateImage(cvGetSize(img), 8, 1);
cvCvtColor(img,imgGrayScale,CV_BGR2GRAY);

//thresholding the grayscale image to get better results
cvThreshold(imgGrayScale,imgGrayScale,180,255,CV_THRESH_BINARY);

CvSeq* contours;  //hold the pointer to a contour in the memory block
CvSeq* result;   //hold sequence of points of a contour
CvMemStorage *storage = cvCreateMemStorage(0); //storage area for all contours

//finding all contours in the image
cvFindContours(imgGrayScale, storage, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));

int largest_area=0;
int largest_contour_index=0;

     for(int i = 0; i< contours->total; i++ ) // iterate through each contour.
      {
           double a = cvContourArea (contours, CV_WHOLE_SEQ);  //  Find the area of contour

           if( a > largest_area ){

               largest_area = a;
               largest_contour_index=i; //Store the index of largest contour

            }

      }

int j = 0;
        while (j != largest_contour_index) {

            if (j == largest_contour_index) {


                //obtain a sequence of points of contour, pointed by the variable 'contour'
                result = cvApproxPoly(contours, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(contours)*0.02, 0);

                     //if there are 3  vertices  in the contour(It should be a triangle)
                if(result->total==3 )
                {
                //iterating through each point
                CvPoint *pt[3];
                for(int i=0;i<3;i++){
                pt[i] = (CvPoint*)cvGetSeqElem(result, i);
                }

                //drawing lines around the triangle
                cvLine(img, *pt[0], *pt[1], cvScalar(255,0,0),4);
                cvLine(img, *pt[1], *pt[2], cvScalar(255,0,0),4);
                cvLine(img, *pt[2], *pt[0], cvScalar(255,0,0),4);

                }

                //if there are 4 vertices in the contour(It should be a quadrilateral)
                else if(result->total==4 )
                {
                    //iterating through each point
                    CvPoint *pt[4];
                    for(int i=0;i<4;i++){
                    pt[i] = (CvPoint*)cvGetSeqElem(result, i);
                }

                //drawing lines around the quadrilateral
                cvLine(img, *pt[0], *pt[1], cvScalar(0,255,0),4);
                cvLine(img, *pt[1], *pt[2], cvScalar(0,255,0),4);
                cvLine(img, *pt[2], *pt[3], cvScalar(0,255,0),4);
                cvLine(img, *pt[3], *pt[0], cvScalar(0,255,0),4);
                }

                //if there are 7  vertices  in the contour(It should be a heptagon)
                else if(result->total ==7 )
                {
                    //iterating through each point
                    CvPoint *pt[7];
                    for(int i=0;i<7;i++){
                    pt[i] = (CvPoint*)cvGetSeqElem(result, i);
                    }

                    //drawing lines around the heptagon
                    cvLine(img, *pt[0], *pt[1], cvScalar(0,0,255),4);
                    cvLine(img, *pt[1], *pt[2], cvScalar(0,0,255),4);
                    cvLine(img, *pt[2], *pt[3], cvScalar(0,0,255),4);
                    cvLine(img, *pt[3], *pt[4], cvScalar(0,0,255),4);
                    cvLine(img, *pt[4], *pt[5], cvScalar(0,0,255),4);
                    cvLine(img, *pt[5], *pt[6], cvScalar(0,0,255),4);
                    cvLine(img, *pt[6], *pt[0], cvScalar(0,0,255),4);
                }
            }

            contours = contours -> h_next;
            j++;
        }


//sow the image in which identified shapes are marked
cvNamedWindow("Tracked");
cvShowImage("Tracked",img);

cvWaitKey(0); //wait for a key press

//cleaning up
cvDestroyAllWindows();
cvReleaseMemStorage(&storage);
cvReleaseImage(&img);
cvReleaseImage(&imgGrayScale);

return 0;

}

执行此图片上的程序时:enter image description here 没有绘图形状。

提前致谢。

1 个答案:

答案 0 :(得分:0)

在第一个循环中,我认为,你并没有真正遍历所有轮廓。 您应该像在第二个循环中一样使用h_next进行迭代。 此外,当您搜索最大轮廓时,您可以存储其指针以便稍后访问它

CvSeq* biggestContour;
double a = 0;
for(int i = 0; i< contours->total; i++ ) // iterate through each contour.
{
    a = cvContourArea (contours, CV_WHOLE_SEQ);  //  Find the area of contour

    if( a > largest_area ){
        larget_area = a;
        biggestContour = contours; // store the biggest one

    }

    contours = contours -> h_next;

}

// do your work using the above biggestContour

//obtain a sequence of points of contour, pointed by the variable 'contour'
result = cvApproxPoly(biggestContour, sizeof(CvContour), storage, CV_POLY_APPROX_DP, cvContourPerimeter(biggestContour)*0.02, 0);

[...] 
编辑:我会发布一些您可能觉得有用的代码。您不能按原样使用它,但是您将看到如何遍历轮廓。我用它来查找图像中的所有轮廓,然后根据各种标准过滤其中一些

// we are going to use these
CvMemStorage* strgContours;
CvSeq* seqContours;
CvSeq* seqCurrent;

// create the MemStorage
strgContours = cvCreateMemStorage(0);

// you can clone your input image and work on the new one, if you wish
IplImage* imgTemp = (IplImage*)cvClone(input);

// scan the image for contours
CvContourScanner scanner;
scanner = cvStartFindContours( imgTemp, strgContours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0) );

double maxContourArea = 0;
while( (seqCurrent = cvFindNextContour( scanner )) != 0 ) 
{
    // Now you can work with seqCurrent, that holds current contour

    [...] 

    //the area is computed using the Green formula, 
    //thus the returned area and the number 
    //of non-zero pixels can be different.
    double area = cvContourArea( seqCurrent );   //same as "cvContourArea( c , CV_WHOLE_SEQ );"   

    [...]                   

    // you can even discard contours that do not match your criteria
    if( area < 100 ) {
        cvSubstituteContour( scanner, 0 );
        continue;
    }

    [...]

    // This is how you draw your contour on an IplImage
    // create your image
    IplImage* imgTest = cvCreateImage( size , IPL_DEPTH_8U , 3);            
    // make it black
    cvZero( imgTest );
    // draw the contour
    cvDrawContours( imgTest, seqCurrent, cvScalarAll(255), cvScalarAll(0), -1, CV_FILLED, 8, cvPoint(0,0));                     
    // do what you want to do with your image       
    [...]       
    // and then release it
    cvReleaseImage( &imgTest);                                  
}

// seqContours will hold all contours found and were not discarded
seqContours = cvEndFindContours( &scanner );

// paint the found regions back into the image
IplImage* imgContours = cvCreateImage( size , IPL_DEPTH_8U , 3);            
cvZero( imgContours );
for( seqCurrent=seqContours; seqCurrent != 0; seqCurrent = seqCurrent->h_next ) 
{               
    cvDrawContours( imgContours, seqCurrent, cvScalarAll(255), cvScalarAll(0), -1, CV_FILLED, 8, cvPoint(0,0));
}

// do things...

// Free memory
cvReleaseImage( &imgContours);  
cvReleaseImage( &imgTemp);  
cvReleaseMemStorage(&strgContours);