合并轮廓

5
我正在开发一个实时运动检测程序。在使用背景相减法后,我发现我的不同图像中有许多轮廓线。我想问是否有任何方法可以将这些轮廓合并在一起或者创建一个较大的矩形框包含所有的轮廓线?
现在的情况是: http://singhgaganpreet.files.wordpress.com/2012/07/motioncolour.jpg 这是我的代码:
#include <iostream>
#include <OpenCV/cv.h>
#include <OPenCV/highgui.h>

using namespace cv;
using namespace std;

CvRect rect;
CvSeq* contours = 0;
CvMemStorage* storage = NULL;
CvCapture *cam;
IplImage *currentFrame, *currentFrame_grey, *differenceImg, *oldFrame_grey;

bool first = true;

int main(int argc, char* argv[])
{
   //Create a new movie capture object.
   cam = cvCaptureFromCAM(0);

   //create storage for contours
   storage = cvCreateMemStorage(0);

   //capture current frame from webcam
   currentFrame = cvQueryFrame(cam);

   //Size of the image.
   CvSize imgSize;
   imgSize.width = currentFrame->width;
   imgSize.height = currentFrame->height;

   //Images to use in the program.
   currentFrame_grey = cvCreateImage( imgSize, IPL_DEPTH_8U, 1);                           

   while(1)
   {
          currentFrame = cvQueryFrame( cam );
          if( !currentFrame ) break;

          //Convert the image to grayscale.
          cvCvtColor(currentFrame,currentFrame_grey,CV_RGB2GRAY);

          if(first) //Capturing Background for the first time
          {
                 differenceImg = cvCloneImage(currentFrame_grey);
                 oldFrame_grey = cvCloneImage(currentFrame_grey);
                 cvConvertScale(currentFrame_grey, oldFrame_grey, 1.0, 0.0);
                 first = false;
                 continue;
          }

          //Minus the current frame from the moving average.
          cvAbsDiff(oldFrame_grey,currentFrame_grey,differenceImg);

          //bluring the differnece image
          cvSmooth(differenceImg, differenceImg, CV_BLUR);             

          //apply threshold to discard small unwanted movements
          cvThreshold(differenceImg, differenceImg, 25, 255, CV_THRESH_BINARY);

          //find contours
          cvFindContours( differenceImg, storage, &contours );

          //draw bounding box around each contour
          for(; contours!=0; contours = contours->h_next)
          {
                 rect = cvBoundingRect(contours, 0); //extract bounding box for current contour

                 //drawing rectangle
                 cvRectangle(currentFrame,                  
                              cvPoint(rect.x, rect.y),    
                              cvPoint(rect.x+rect.width, rect.y+rect.height),
                              cvScalar(0, 0, 255, 0),
                              2, 8, 0);                 
          }

          //display colour image with bounding box
          cvShowImage("Output Image", currentFrame);

          //display threshold image
          cvShowImage("Difference image", differenceImg);

          //New Background
          cvConvertScale(currentFrame_grey, oldFrame_grey, 1.0, 0.0);

          //clear memory and contours
          cvClearMemStorage( storage );
          contours = 0;

          //press Esc to exit
          char c = cvWaitKey(33);
          if( c == 27 ) break;

   }

   // Destroy the image & movies objects
   cvReleaseImage(&oldFrame_grey);
   cvReleaseImage(&differenceImg);
   cvReleaseImage(&currentFrame);
   cvReleaseImage(&currentFrame_grey);
   //cvReleaseCapture(&cam);

   return 0;

}

3个回答

10

你试过这个吗?

std::vector<cv::Point> points;
points.insert(points.end(), contour1.begin(), contour1.end());
points.insert(points.end(), contour2.begin(), contour2.end());
convexHull(cv::Mat(points), contour);

PS. 对于某些应用程序,使用approxPoly()可能比convexHull()更好。 只需尝试两者即可。

PPS. 尝试使用高斯平滑来平滑处理生成的轮廓。 这也可能有所帮助。


不,我们转换到了C++。 - MOHRE

1

我遇到了类似的问题。在我的情况下,我创建了一个空序列,然后用每个轮廓的点填充它,之后我使用该序列拟合了一个边界椭圆。以下是我的代码片段...

CvMemStorage *storage = cvCreateMemStorage ();
CvMemStorage *storage1 = cvCreateMemStorage ();
CvSeq *contours = 0;

//find contour in BInv
cvFindContours (BInv, storage, &contours, sizeof(CvContour), CV_RETR_LIST,CV_CHAIN_APPROX_NONE ,cvPoint(0,0)); 

//creating empty sequence of CvPoint
CvSeq* seq = cvCreateSeq(CV_SEQ_ELTYPE_POINT/*| CV_SEQ_KIND_SET | CV_SEQ_FLAG_SIMPLE*/,sizeof(CvSeq),sizeof(CvPoint),storage1);

//populating seq with all contours
for(; contours!=0; contours = contours->h_next)
  for(int i=0;i<contours->total;i++)
     {  
         CvPoint* p;
        p = (CvPoint*)cvGetSeqElem (contours, i );
        cvSeqPush(seq,p);   
      }

//bounding box and drawing
CvBox2D bbox=cvMinAreaRect2(seq, NULL );
cvEllipseBox(color,bbox,cvScalarAll(0),5,8,0);

希望这能帮到您。

0
如果您想根据距离合并轮廓,则可以执行类似以下代码的操作:
    struct hash_pair {
    template <class T1, class T2>
    size_t operator()(const pair<T1, T2>& p) const
    {
        auto hash1 = hash<T1>{}(p.first);
        auto hash2 = hash<T2>{}(p.second);

        if (hash1 != hash2) {
            return hash1 ^ hash2;
        }

        return hash1;
    }
};
void findPixelsNearby(unordered_map<pair<int, int>,bool,hash_pair>&res, Point px,int pxlVal) {
    for (int itr1 = (px.x) - pxlVal; itr1 <= (px.x) + pxlVal; itr1++) {
        for (int itr2 = (px.y - pxlVal); itr2 <= (px.y) + pxlVal; itr2++) {
            res[{itr1, itr2}] = true;
        }
    }
}
unordered_map<pair<int, int>, bool, hash_pair> createSets(vector<Point2f>Contour, int rect) {
    unordered_map<pair<int,int>,bool,hash_pair>res;
    for (auto tra : Contour) {
        Point px = (Point)tra;
        findPixelsNearby(res,px,rect);
    
    }

    return res;
}

//void drawContour(Mat& img, vector<Point2f>s1,int px,int py,int pz) {
//  for (auto x : s1) {
//      line(img, x, x, Scalar(px, py, pz), 4, 0);
//
//  }
//  resShow("temp",img,1);
    
//}

bool hasCommon(unordered_map<pair<int,int>,bool,hash_pair>s1, unordered_map<pair<int, int>, bool, hash_pair>s2){
    for (auto x : s1) {
        if (s2.find(x.first) != s2.end()) {
            return true;
        }
    }
    return false;

}
                                                            
void MergeContours(Mat image, vector<Contour>&usableContours,int distance_considered, vector<Contour>& finalContours) {
    

    int numberContours = usableContours.size();
    vector<vector<int>>ids_for_contour_merge(numberContours);
    vector<unordered_map<pair<int, int>, bool, hash_pair>>ContourSets;  
    vector<bool>boolVals(numberContours,false); 

    for (int i = 0; i < numberContours; i++) {
        ContourSets.push_back(createSets(usableContours[i].points, distance_considered/2));
    }

    for (int i = 0; i < numberContours; i++) {
        
        if (boolVals[i] == false) {
            boolVals[i] = true;
            for (int j = i+1; j < numberContours; j++) {
                if (boolVals[j] == false) {
                    
                    if(hasCommon(ContourSets[i], ContourSets[j])==true){
                        ContourSets[i].insert(ContourSets[j].begin(), ContourSets[j].end());
                        boolVals[j] = true;
                        ids_for_contour_merge[i].push_back(j);
                        j = i;

                    }
                }
            }
        }
    }
    vector<bool>Visited(ids_for_contour_merge.size(), false);
    
    for (int mr = 0; mr < ids_for_contour_merge.size(); mr++) {
        if (Visited[mr] == false) {
            vector<Point2f>temp=usableContours[mr].points;
            if (ids_for_contour_merge[mr].size() > 0) {
                for (int mc = 0; mc < ids_for_contour_merge[mr].size(); mc++) {

                    int valPtr = ids_for_contour_merge[mr][mc];
                    
                    copy(usableContours[valPtr].points.begin(), usableContours[valPtr].points.end(), std::back_inserter(temp));
                    Visited[valPtr] = true;
                    

                }
            }
            else {
                Visited[mr] = true;
            }
            Contour newCtr;
            newCtr.points = temp;
            finalContours.push_back(newCtr);
        }
        
    }

    ///////////////////////////////////////////////////////////////DRAWING CONTOURS
        /*for (auto x : finalContours) {
            cout <<"CONTOURS FINAL SIZE IS : " <<x.points.size()<<endl;
            int px = 0;
            int py = 0;
            int pz = 0;
            drawContour(image, x.points, ((px+rand())%255), ((py + rand()) % 255), ((pz + rand()) % 255));
        
        }*/
    //////////////////////////////////////////////////////////////////////////////


}

更多关于Github的内容:https://github.com/HimanshuYadav117/Merge-Contours/blob/main/MergeContours.cpp


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接