我试图在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;
}
执行此图片上的程序时: 没有绘图形状。
提前致谢。
答案 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);