Search code examples
opencvroi

Find Contours inside ROI


I was searching for this question and haven't received any specific answers. I am already finding my contours and also i have defined my ROI.

QUESTION: How can i find these contours only inside my ROI?

I have defined my ROI at the beginning.

Here is the code:

    int main( int argc, char** argv )
{
    Mat img_prev, img_curr, result;
    int counter = 0;

        //string filename = "/home/zubair/Downloads/Contours/1.jpg";
        //VideoCapture cap(filename);

  //while(1)
  //{

  img_curr = imread(argv[1], CV_LOAD_IMAGE_COLOR); 
    //cap >> img_curr;
    //counter++;
    //img_curr.copyTo(img_prev);

    while(1)
       {
      // SetImageRoi    
      cv::Rect roi(1,250, 640, 200);
      cv::rectangle(img_curr,roi,cv::Scalar(255,255,255),1,8,0);


      //cv::Mat image_roi = img_curr(roi);  // note: this assignment does not copy data, frame and   image_roi now share data



   imshow ("current frame",img_curr);

   if(! img_curr.data )                              // Check for invalid input
    {
        cout <<  "Could not open or find the image" << std::endl ;
        return -1;
    }

   //imshow("previous frame", img_prev);

   cvtColor( img_curr, src_gray, CV_BGR2GRAY );



//--------------------------------------------------------------------------------------------------------------------------------------//
//----------------------------------- to find the contours AND Detect edges using Threshold---------------------------------------------//
//--------------------------------------------------------------------------------------------------------------------------------------//


  Mat canny_output;
  Mat threshold_output;
  vector<vector<Point> > contours;
  vector<Vec4i> hierarchy;

  /// Detect edges using canny
  Canny(src_gray, canny_output, thresh, thresh*2, 3 );

  blur( src_gray, src_gray, Size(3,3) );

  ///threshold control
  threshold( src_gray, threshold_output, thresh, 255, THRESH_BINARY );

  /// Find contours
  findContours( threshold_output, contours, hierarchy, RETR_TREE, CHAIN_APPROX_SIMPLE, Point(0, 0) );

  /// Get the moments
      vector<Moments> mu(contours.size() );
      for( int i = 0; i < contours.size(); i++ )
         { mu[i] = moments( contours[i], false ); }


    cv::erode(threshold_output,threshold_output, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));
    cv::dilate(threshold_output, threshold_output, cv::getStructuringElement(cv::MORPH_ELLIPSE, cv::Size(5, 5)));



  ///  Get the mass centers:
       vector<Point2f> mc( contours.size() );
       for( int i = 0; i < contours.size(); i++ )
          { mc[i] = Point2f( mu[i].m10/mu[i].m00 , mu[i].m01/mu[i].m00 ); }

  /// Approximate contours to polygons + get bounding rects and circles
  vector<vector<Point> > contours_poly( contours.size() );
  vector<Rect> boundRect( contours.size() );
  vector<Point2f>center( contours.size() );
  vector<float>radius( contours.size() );
    for( int i = 0; i < contours.size(); i++ )
        { approxPolyDP( Mat(contours[i]), contours_poly[i], 3, true );
         boundRect[i] = boundingRect( Mat(contours_poly[i]) );
         minEnclosingCircle( (Mat)contours_poly[i], center[i], radius[i] );
        }


   Mat drawing = Mat::zeros( threshold_output.size(), CV_8UC3 );
   bool is_inside = (roi & cv::Rect(0, 0, drawing.cols, drawing.rows)) == roi;

   //printf("\t Info: Area and Contour Length \n");
   for( int i = 0; i< contours.size(); i++ )
     {


      if(contourArea(contours[i]) > 2000 && contourArea(contours[i]) < 50000  )
         {

            printf(" * Contour[%d] - Area (M_00) = %.2f - Area OpenCV: %.2f - Length: %.2f \n", i, mu[i].m00, contourArea(contours[i]), arcLength    ( contours[i], true ) );
            Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );

            drawContours( drawing, contours, i, color, 2, 8, hierarchy, 0, Point(0,0) );
            rectangle( drawing, boundRect[i].tl(), boundRect[i].br(), color, 2, 8, 0 );
            Point center_obstacle = (boundRect[i].br() + boundRect[i].tl())*0.5;
            circle(drawing,center_obstacle,3,Scalar(0,0,255));
            cout<<"     obstale     "<<i<<"     position is at     "<< center_obstacle.x <<"     and     "<< center_obstacle.y <<endl;
         }

      }



        createTrackbar( " Canny thresh:", "Source", &thresh, max_thresh );
        createTrackbar( " Threshold:", "Source", &thresh, max_thresh);

    namedWindow( "Contours", WINDOW_AUTOSIZE );
    imshow( "Contours", drawing );

//--------------------------------------------------------------------------------------------------------------------------------------------



        waitKey(0);

}
      return 0;
  }

SOLUTION: I wanted to give a condition before drawing my contours with that contours should be in my ROI range. I don't know how do this.


Solution

  • I define a function to judge whether Rect rect is in Rect roi or not.

    bool isInside(const Rect& rect, const Rect& roi) {
        return (roi|rect) == roi;
    }
    

    This is the test example:

    enter image description here


    //! 2018.01.18 09:37:20 CST
    //! 2018.01.18 10:29:16 CST
    #include <opencv2/opencv.hpp>
    #include <vector>
    #include <string>
    using namespace std;
    using namespace cv;
    
    // To judge whether rect is in roi or not?
    bool isInside(const Rect& rect, const Rect& roi) {
        return (roi|rect) == roi;
    }
    
    int main() {
    
        Mat img(600,600, CV_8UC3, Scalar::all(0));
    
        Rect roi(100, 100, 400, 400);
        Rect rect1(200, 200, 200, 200);
        Rect rect2(10,10, 200, 200);
    
        Scalar blue(255,0,0), green(0,255,0), red(0,0,255);
    
        string msg("Roi in blue; Inside in green, Outside in red!");
        cout<<msg<<endl;
        rectangle(img, roi, blue, 1);
        rectangle(img, rect1, isInside(rect1, roi)?green:red, 1);
        rectangle(img, rect2, isInside(rect2, roi)?green:red, 1);
        imshow(msg, img);
        waitKey();
    }
    

    Ok, now return back to your program, to judge whether the contours is inside of roi or not, just compare their boundingRect with roi.

    Your code:

    bool is_inside = (roi & cv::Rect(0, 0, drawing.cols, drawing.rows)) == roi;
    

    Modified:

    for( int i = 0; i< contours.size(); i++ )
    {
        Rect rect = boundingRect(contours[i]);
        // bool is_inside = (roi|rect) == roi;
        if(!isInside(rect, roi)){
            cout <<"Not in side, continue to the next."<<endl;
            continue;
        }
    
        // ...
    
    }
    

    Here is my result, draw all contours in white, then the inside ones(whose area is meet some area standard)in color:

    enter image description here