0

I have try to get a minRect of a contours(Actually is a triangle). but the result confuse me.!

All of the contours are the same triangle but different rotate angles. but their minRect is different from eachothers. but I think the result should independent of Angle.

brown Rect is 0°
Pink & Green Rect is 45°
other Rect is random。
(I don't have enough reputation to post images,sorry.)

My problem is can I get a minRect which independent of Angle by opencv?

Himanshu
  • 4,327
  • 16
  • 31
  • 39

3 Answers3

0

I assume that you mean minAreaRect which by definition finds a rotated rectangle. From the documentation

The function calculates and returns the minimum-area bounding rectangle (possibly rotated) for a specified point set.

Is what you are looking for a function that fits a rectangle that is not rotated?

There is the function boundingRect that does just that

The function calculates and returns the minimal up-right bounding rectangle for the specified point set.

In Python, an example would be to load an image, find the contours and pass the contours to the function.

img =cv2.imread(fileName,0)
#convert the image to B&W with the given threshold. 'thresh' is the 
# the B&W image
ret, thresh = cv2.threshold(img,threshold,255,cv2.THRESH_BINARY) 

contours, hierarchy = cv2.findContours(thresh, cv2.cv.CV_RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)

cnt = contours[ID] #ID is the index of the contour you want

#find bounding rectangle of countour
x,y,w,h = cv2.boundingRect(cnt)
Edgar H
  • 1,376
  • 2
  • 17
  • 31
  • @user119540 So you want a rotated rectangle that is independent of of the rotation angle of the triangle? Cannot you just check which side is longer and add/subtract 90 degrees as needed? – Edgar H Apr 22 '15 at 08:55
  • @user119540 Alternativly, have a look at this question and answer [here](http://stackoverflow.com/questions/10767863/opencv-rotatedrect-with-specified-angle?rq=1), especailly the last comment under the question. – Edgar H Apr 22 '15 at 10:50
  • ,if you try with some triangle(like I do by Excel),you will find it out. One triangle have 3 sides which names are A,B,C (A – user119540 Apr 22 '15 at 14:50
  • So just add/subtract can not solve the problems. minRect's angle is not liner to the rotate angle, cause the minRect jumps a little. – user119540 Apr 22 '15 at 14:57
  • @user119540 I will write an example later today and see what is happening. I get the following results Triangle rotation: 0, 15, 30, 45, 60 , 75, 90 Rotation angle found by minRect : 0 , 15, 30, 0, 60, 75, 0 so it works as expected, except for the case of a 45 degrees of rotation. A working example is [here](http://www.negative-probability.co.uk/docs/ExampleTriangle.zip) – Edgar H Apr 24 '15 at 08:41
  • The problem of 45 degrees confuses me. I have seen your pictures. I think the angle of triangle is 45-90-45. if your triangle is 80-80-20, then when you rotate 10deg(20deg/2),the minRect jump again. if I want to get the angle and position of contours by minRect, I need to be careful of this jump. In view of morphology, the minRects of 15 and 45 returned by the opencv is different. 15 is like equal-side-square, 45 is like normal rectangle. but actually they are same triangle with different rotate angle. later i will post the code. Here is my email :704804684@qq.com ,if you want to contract me. – user119540 Apr 25 '15 at 03:52
0

Actually,I want to get the rotate angle of the countour (a triangle). You can use Excel to draw a triangle(2 sides equal), rotate it. Copy that triangle and rotate it in another angle. Now we got 2 triangle which are the same but different rotate angle. Copy those 2 triangle and copy to MSpaint, save it as image. Use opencv function minAreaRect to find the rotate of the countour(2 triangle).you will find that: if the triangle rotate 0deg or 45deg you will get one type of rect,but if the triangle rotate like 20deg or 60 deg, you will get another type of rect. One type it use the short side to construct the rect, another type it use long side to construct the rect.

0
#include "stdafx.h"  
/**
 * @function generalContours_demo2.cpp
 * @brief Demo code to obtain ellipses and rotated rectangles that contain detected contours
 * @author OpenCV team
 */

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

using namespace cv;
using namespace std;

Mat src; Mat src_gray;
int thresh = 100;
int max_thresh = 255;
RNG rng(12345);

/// Function header
void GetImPath();
void thresh_callback(int, void* );
void ReflashContours();
float trueAngle(Point2f centerP,Point2f midP,float a);

string mypath;
string impath;
/**
 * @function main
 */
int main( int argc, char** argv )
{
  /// Load source image and convert it to gray
    mypath=argv[0];
    int pos0=mypath.rfind("\\");
    mypath=mypath.substr(0,pos0+1);

    if(1==argc)
    {
        char c='0';
        impath=mypath+"t"+ c +".jpg";
    }
    else
    {
        impath=argv[1];
    }
    cout<<impath<<endl;
  const char* source_window = "Source";
  char k;

while(1){
    src = imread (impath, 1 );
  /// Convert image to gray and blur it
  cvtColor( src, src_gray, COLOR_BGR2GRAY );
  blur( src_gray, src_gray, Size(3,3) );

  /// Create Window

  namedWindow( source_window, WINDOW_AUTOSIZE );
  imshow( source_window, src );

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

  k=waitKey(0);
  if (27==k) break;
  GetImPath();
  cout<<impath<<endl;
}
  return(0);
}
void GetImPath()
{
    static char c='0';
    impath=mypath+"t"+ c +".jpg";
    c++;
    if( '3'<c) c='0';
    return ;
}

void ReflashContours()
{
  Mat proc_output;
  vector<vector<Point> > contours;
  vector<Vec4i> hierarchy;

  /// Detect edges using Threshold
  //threshold( src_gray, proc_output, thresh, 255, THRESH_BINARY );

  // detect edges using canny
  Canny(src_gray,proc_output,thresh,thresh*2,3);

  //namedWindow( "Proc", WINDOW_AUTOSIZE );
  //imshow( "Proc", proc_output );

  /// Find contours
  findContours( proc_output, contours, hierarchy, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE, Point(0, 0) );
  cout<< contours.size() <<" Lens found."<<endl;
  /// Find the rotated rectangles and ellipses for each contour
  vector<RotatedRect> minRect( contours.size() );
  vector<RotatedRect> minEllipse( contours.size() );

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

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

  for( size_t i = 0; i < contours.size(); i++ )
  {
    minRect[i] = minAreaRect( Mat(contours[i]) );
    minEllipse[i] = fitEllipse( Mat(contours[i]) );
    cout<<"Angle: " << trueAngle(mc[i],minRect[i].center, minRect[i].angle)<<"\t [X , Y] = " <<minRect[i].center <<endl;
    //cout<<"Angle: " << trueAngle(mc[i],minEllipse[i].center, minEllipse[i].angle)<<"\t [X , Y] = " <<minEllipse[i].center <<endl;
    cout<<endl;
  }
  cout<<endl;
  cout<<endl;


  /// Draw contours + rotated rects + ellipses
  Mat drawing = Mat::zeros( proc_output.size(), CV_8UC3 );
  //cout<< "drawing type :"<< drawing.type() <<endl;
  drawing=src.clone();

  for( size_t i = 0; i< contours.size(); i++ )
     {
       Scalar color = Scalar( rng.uniform(0, 255), rng.uniform(0,255), rng.uniform(0,255) );
       // contour
       drawContours( drawing, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );
       //drawContours( src, contours, (int)i, color, 1, 8, vector<Vec4i>(), 0, Point() );

       /**/
       // rotated rectangle
       Point2f rect_points[4]; minRect[i].points( rect_points );
       for( int j = 0; j < 4; j++ )
       {
          line( drawing, rect_points[j], rect_points[(j+1)%4], color, 1, 8 );
          //line( src, rect_points[j], rect_points[(j+1)%4], color,1 , 8 );
          circle(drawing,rect_points[j],j*2,color,-1,8,0);
       }


       //center point
       circle( drawing, mc[i], 1, color, -1, 8, 0 );

       circle(drawing,minRect[i].center,1,color,-1,8,0);
        //circle(drawing,minEllipse[i].center,1,color,-1,8,0);
        //ellipse( drawing, minEllipse[i], color, 1, 8 );
     }

  /// Show in a window
  namedWindow( "Contours", WINDOW_AUTOSIZE );
  imshow( "Contours", drawing );
}
/**
 * @function thresh_callback
 */
void thresh_callback(int, void* )
{
    ReflashContours();
}

float trueAngle(Point2f centerP,Point2f midP,float a)
{
    cout<<"centerp: "<<centerP<<"\tmidp: "<<midP<<"\tangle: "<<a<<endl;
    //1
    if ((midP.x>centerP.x) && (midP.y<centerP.y ))
    {
        cout<<"1"<<endl;
        return -a;
    }
    //2
    else if((midP.x<centerP.x) && (midP.y<centerP.y ))
    {
        cout<<"2"<<endl;
        return 90-a;
    }
    //3
    else if((midP.x<centerP.x) && (midP.y>centerP.y ))
    {
        cout<<"3"<<endl;
        return -180-a;
    }
    //4
    else
    {
        cout<<"4"<<endl;
        return -90-a;
    }
}