user1388142
user1388142

Reputation: 603

shape analysis to differentiate rectangles from other shapes

I have been trying to perform shape analysis to distinguish rectangular objects from the non-rectangular objects (such as semi-circles) using binary images

Some possible examples

Rectangles

enter image description here enter image description here

Non-Rectangles

enter image description here enter image description here

My algorithm works as follow:

  1. Extract the object mask using contours - openCV (as you can see in the above examples)
  2. Perform shape analysis or compute statistics to detect if object is rectangular or not

So far, I have tried eccentricity and rectangularity measures.

For example: Ideally, rectangularity should be high for rectangles only. In my experiments, I get similar rectangularity for a rectangle or circular object sometimes. Therefore, I cannot use this measure for analysis because it is not reliable

Same problem happens with eccentricity. Ideally, a circle has eccentricity of zero and for rectangular object it should be very high. But it turns out to be very similar for rectangles or circles

Is there a way to figure out if object is roughly a rectangle or not using any geometrical information ??

Any help will be really appreciated

Upvotes: 2

Views: 744

Answers (1)

LBerger
LBerger

Reputation: 623

I think that you can use approxPolyDP. I give you program in C++ and I think it's easy to translate in python. Idea is looking for shape with four corners which approximate real contour and then calculate four angle (corner angle). while number of contour point is greater than 4 error between new contour and real contour is increased. You have to choose a threshold angle (90+/- x°) after when you think it's not rectangle. (Sorry for bad english)

#include "opencv2/opencv.hpp"
#include <iostream>

using namespace cv;
using namespace std;


int main(int argc, char **argv)
{
vector<String> fileName;
fileName.push_back("2nrTo.jpg");
fileName.push_back("G3I4t.jpg");
fileName.push_back("Q4ZtM.jpg");
fileName.push_back("vWgKx.jpg");
for (int i = 0; i < static_cast<int>(fileName.size()); i++)
{
    Mat mThresh;
    Mat m=imread(fileName[i],CV_LOAD_IMAGE_GRAYSCALE);
    Mat mc;
    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    threshold(m,mThresh,80,255,THRESH_BINARY);
    findContours(mThresh,contours,hierarchy, cv::RETR_CCOMP, cv::CHAIN_APPROX_NONE, cv::Point(0,0));
    cout << "Image " << fileName[i] << "\n";
    imshow(fileName[i],m);
    mc = Mat::zeros(m.size(),CV_8UC3);
    drawContours(mc,contours,0,Scalar(255,0,0),1);
    vector<Point> approx;
    double d=0;
    do
    {
        d=d+1;
        approxPolyDP(contours[0],approx,d,true);
    }
    while (approx.size()>4);
    cout << "#vertices =" <<approx.size() << "\t error max= " <<d<<endl;
    if (approx.size() == 4)
    {
        cout << "Angles\n";
        Point2d u(approx[1]-approx[0]),v(approx[2]-approx[1]),w(approx[3]-approx[2]),x(approx[3]-approx[0]);
        cout<<acos(u.dot(v) / norm(u) / norm(v))<<"\n";
        cout<<acos(v.dot(w) / norm(v) / norm(w))<<"\n";
        cout<<acos(w.dot(x) / norm(w) / norm(x))<<"\n";
        cout<<acos(x.dot(u) / norm(x) / norm(u))<<"\n";

    }
    else
        cout << "looks like a triangle\n";
    contours.push_back(approx);
    drawContours(mc,contours,contours.size()-1,Scalar(0,0,255),1);
    imshow("Ctr",mc);
    waitKey();
}

return 0;
}

With previous images program gives thoses results :

Image 2nrTo.jpg
#vertices =4     error max= 17
Angles
93.3283
90.2247
90
93.553
Image G3I4t.jpg
#vertices =4     error max= 15
Angles
112.503
46.3837
110.346
48.5412
Image Q4ZtM.jpg
#vertices =4     error max= 6
Angles
88.9191
90.0297
88.9488
90
Image vWgKx.jpg
#vertices =4     error max= 49
Angles
87.0753
117.999
90.3148
114.76

Upvotes: 2

Related Questions