Repository: opencv
Issue: Bug in RotatedRect::boundingRect() method
Labels: auto-transferred,feature,priority: low,category: core

Transferred from http://code.opencv.org/issues/3396

```
|| Hamed Habibi Aghdam on 2013-11-25 14:15
|| Priority: Low
|| Affected: None
|| Category: core
|| Tracker: Feature
|| Difficulty: Easy
|| PR: 
|| Platform: None / None
```
## Bug in RotatedRect::boundingRect() method

```
I tried to get the smallest bounding box for a rotated rectangle. However, the result of RotatedRect::boundingRect() method is not correct all time and in some cases it return rectangles much bigger than the original one. 

I checked the source code for of this method. There is a mathematical solution to this problem. I implemented and tested it. Given the major and minor axis as well as the amount of the rotation of the RotatedRect, the smallest bounding box can be calculated as follow:

///////////////////////////////////////////////////////////////////

float t1 = atan(-(majorAxe*sin(degree))/(minorAxe*cos(degree)));
float t2 = t1 + 3.1415;

float maxX = x + majorAxe*cos(t1)*cos(degree)-minorAxe*sin(t1)*sin(degree);
float minX = x + majorAxe*cos(t2)*cos(degree)-minorAxe*sin(t2)*sin(degree);

t1 = atan((minorAxe*cos(degree))/(majorAxe*sin(degree)));
t2 = t1 + 3.1415;

float maxY = y + minorAxe*sin(t1)*cos(degree)+majorAxe*cos(t1)*sin(degree);
float minY = y + minorAxe*sin(t2)*cos(degree)+majorAxe*cos(t2)*sin(degree);
if (minY > maxY)
{
    float temp = minY;
    minY = maxY;
    maxY = temp;
}
if (minX > maxX)
{
    float temp = minX;
    minX = maxX;
    maxX = temp;        
}

Rect r(minX,minY,maxX-minX,maxY-minY);

///////////////////////////////////////////////////////
*To speed up the computations, the code can be optimized to avoid redundant sin and cos calls. Also, the code can be more optimized by utilizing simple Trigonometric equations.* So the more optimized code can be as follows:

float c_degree = cos(degree);
float s_degree = sin(degree);
float t1 = atan(-(majorAxe*s_degree)/(minorAxe*c_degree));
float c_t1 = cos(t1);
float s_t1 = sin(t1);
float w1 = majorAxe*c_t1*c_degree;
float w2 = minorAxe*s_t1*s_degree;
float maxX = x + w1-w2;
float minX = x - w1+w2;

t1 = atan((minorAxe*c_degree)/(majorAxe*s_degree));
c_t1 = cos(t1);
s_t1 = sin(t1);

w1 = minorAxe*s_t1*c_degree;
w2 = majorAxe*c_t1*s_degree;
float maxY = y + w1+w2;
float minY = y - w1-w2;

if (minY > maxY)
{
float temp = minY;
minY = maxY;
maxY = temp;
}

if (minX > maxX)
{
    float temp = minX;
    minX = maxX;
    maxX = temp;
}

Rect r(minX,minY,maxX-minX,maxY-minY);
```
## History
##### Hamed Habibi Aghdam on 2013-11-25 16:10

```
I changed the opencv code and tested it. it works:


Rect RotatedRect::boundingRect() const
{ 
    float degree = angle*3.1415/180;
    float majorAxe = this->size.width/2;
    float minorAxe = this->size.height/2;
    float x = this->center.x;
    float y =this->center.y;
    float c_degree = cos(degree);
    float s_degree = sin(degree);
    float t1 = atan(-(majorAxe*s_degree)/(minorAxe*c_degree));          
    float c_t1 = cos(t1);
    float s_t1 = sin(t1);
    float w1 = majorAxe*c_t1*c_degree;
    float w2 = minorAxe*s_t1*s_degree;
    float maxX = x + w1-w2;
    float minX = x - w1+w2;
/*#ifdef _DEBUG
    printf("major=%f minor=%f x=%f y=%f deg=%f",majorAxe,minorAxe,x,y,degree);
#endif*/
    t1 = atan((minorAxe*c_degree)/(majorAxe*s_degree));         
    c_t1 = cos(t1);
    s_t1 = sin(t1);
    w1 = minorAxe*s_t1*c_degree;
    w2 = majorAxe*c_t1*s_degree;
    float maxY = y + w1+w2;
    float minY = y - w1-w2;
    if (minY > maxY)
    {
        float temp = minY;
        minY = maxY;
        maxY = temp;
    }
    if (minX > maxX)
    {
        float temp = minX;
        minX = maxX;
        maxX = temp;
    }
    Rect r(minX,minY,maxX-minX+1,maxY-minY+1);
    return r;
}
```
##### Steven Puttemans on 2013-11-25 18:30

```
Are you up for submitting a pull request? It will help the adaptation of the repository alot! Some hints on how to do so can be found here: code.opencv.org/projects/opencv/wiki/How_to_contribute! By submitting a pull request, the review process becomes more easier and build problems on different operating systems can be tested.

If you are not up for it, then give a shout so that someone can pick up your work and submit a pull.
-   % Done changed from 0 to 50
-   Target version set to 2.4.8
-   Assignee set to Hamed Habibi Aghdam
-   Status changed from New to Open
```
##### Daniil Osokin on 2013-12-03 07:57

```
-   Category set to core
```
##### Alexander Smorkalov on 2013-12-30 10:38

```
-   Target version changed from 2.4.8 to 2.4.9
```
##### Daniil Osokin on 2014-01-11 08:24

```
Hamed, please, attach a test sample with wrong bounding rect, otherwise this ticket will be closed.
-   Affected version changed from 2.4.7 (latest release) to 2.4.8
    (latest release)
```
##### Hamed Habibi Aghdam on 2014-01-16 16:10

```
Daniil,

I just saw your message. I will attach a picture of the wrong bounding rect in the next 4 days.

Regards,
```
##### Hamed Habibi Aghdam on 2014-01-16 16:57

```
Using following:

Mat mm = Mat::zeros(220,220,CV_8UC1);
RotatedRect rect2(Point(101.33,109.84),Size2f(177.04,109.25),73.71);

Rect r = rect2.boundingRect();
ellipse(mm,rect2,Scalar(255,255,255),2);            
rectangle(mm,r,Scalar(255,255,255),2);
imshow("test",mm);
waitKey(0);

We get the following result:
!http://oi44.tinypic.com/27xjvxe.jpg!

However, after I changed the source code to the one that I mentioned before we can get the following result:
!http://i39.tinypic.com/2d7zypv.jpg!

You can also test the previous code and the modified code on following RotatedRect:

RotatedRect rect1(Point(144.52,89.47),Size2f(186.35,138.56),68.28);
```
##### Alexander Smorkalov on 2014-04-30 19:05

```
-   Target version changed from 2.4.9 to 2.4.10
```
##### Vadim Pisarevsky on 2015-05-01 20:22

```
RotatedRect::boundingBox is (as the name implies) finds bounding box for a rotated rectangle, not for a rotated ellipse. The proposed algorithm should be put into a separate function. I change it from bug to a feature request.
-   Priority changed from Normal to Low
-   Assignee deleted (Hamed Habibi Aghdam)
-   Tracker changed from Bug to Feature
```