Ask Your Question
2

Detect different shaped contours?

asked 2015-11-13 11:48:54 -0600

215 gravatar image

updated 2015-12-30 14:44:11 -0600

How do i use detect certain shaped contours found using findContours. I want to bound contours which are thin and long, leave everything else away.. but cannot seem to adjust the parameter correctly, or would it be better to use simple blob detector??.. I tried it, but it doesn't seem to work that well..

here is a sample image image description

I find conturs using findContours, and store them as vector<vector <points>> contour.

I then check the area of each contour, those below 1000 are filtered out, and not drawn in the output image.

So the one i am interested in is the one the red rect, and everything else is noise.

the contour has a distinct shape which is always long. and thin as seen in contour down below.

edit retag flag offensive close merge delete

Comments

please share your code and a sample image

sturkmen gravatar imagesturkmen ( 2015-11-13 11:53:23 -0600 )edit

then from the bounding box that you are applying just filter the blobs that you want by filtering the height and width of the the bounding box.

theodore gravatar imagetheodore ( 2015-11-13 14:14:06 -0600 )edit

1 answer

Sort by ยป oldest newest most voted
3

answered 2015-11-13 14:11:36 -0600

updated 2015-11-14 08:57:27 -0600

EDIT 2 : you can change width&height ratio if(dist0 > dist1 *4) and angle if( fabs(angle) > 35 & fabs(angle) < 150 )

input & output Image:

image description image description

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

//! Compute the distance between two points
/*! Compute the Euclidean distance between two points
*
* @Param a Point a
* @Param b Point b
*/
static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b)
{
    double xDiff = a.x - b.x;
    double yDiff = a.y - b.y;

    return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}

int main( int argc, char** argv )
{
    Mat src,gray;
    src = imread(argv[1]);
    if(src.empty())
        return -1;

    cvtColor( src, gray, COLOR_BGR2GRAY );
    gray = gray < 200;

    vector<vector<Point> > contours;

    findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    RotatedRect _minAreaRect;

    for (size_t i = 0; i < contours.size(); ++i)
    {
        _minAreaRect = minAreaRect( Mat(contours[i]) );
        Point2f pts[4];
        _minAreaRect.points(pts);

        double dist0 = distanceBtwPoints(pts[0], pts[1]);
        double dist1 = distanceBtwPoints(pts[1], pts[2]);

        double angle = 0;
        if(dist0 > dist1 *4)
            angle =atan2(pts[0].y - pts[1].y,pts[0].x - pts[1].x) * 180.0 / CV_PI;
        if(dist1 > dist0 *4)
            angle =atan2(pts[1].y - pts[2].y,pts[1].x - pts[2].x) * 180.0 / CV_PI;

        if( fabs(angle) > 35 & fabs(angle) < 150 )
            for( int j = 0; j < 4; j++ )
                line(src, pts[j], pts[(j+1)%4], Scalar(0, 0, 255), 1, LINE_AA);
    }
    imshow("result", src);
    waitKey(0);
    return 0;
}

EDIT 1: you can improve the code below by changing

 if( _minAreaRect.angle < -30 & (dist0 > dist1 *4 | dist1 > dist0 *4) )

here you can change width&height ratio and angle of RotatedRect ( need your care )

input & output Image:

image description image description

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

//! Compute the distance between two points
/*! Compute the Euclidean distance between two points
*
* @Param a Point a
* @Param b Point b
*/
static double distanceBtwPoints(const cv::Point2f &a, const cv::Point2f &b)
{
    double xDiff = a.x - b.x;
    double yDiff = a.y - b.y;

    return std::sqrt((xDiff * xDiff) + (yDiff * yDiff));
}

int main( int argc, char** argv )
{
    Mat src,gray;
    src = imread(argv[1]);
    if(src.empty())
        return -1;

    cvtColor( src, gray, COLOR_BGR2GRAY );
    gray = gray < 200;

    vector<vector<Point> > contours;

    findContours(gray.clone(), contours, CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);

    RotatedRect _minAreaRect;

    for (size_t i = 0; i < contours.size(); ++i)
    {
        _minAreaRect = minAreaRect( Mat(contours[i]) );
        Point2f pts[4];
        _minAreaRect.points(pts);

        double dist0 = distanceBtwPoints(pts[0], pts[1]);
        double dist1 = distanceBtwPoints(pts[1], pts[2]);

        if( _minAreaRect.angle < -30 & (dist0 > dist1 *4 | dist1 > dist0 *4) )
            for( int j = 0; j < 4; j++ )
                line(src, pts[j], pts[(j+1)%4], Scalar(0, 0, 255), 1, LINE_AA);
    }
    imshow("result", src);
    waitKey(0);
    return 0;
}

you can filter contours by using height and width of bounding rectangels .

like if ( minRect.height > minRect.width*4 ) as shown with the code below:

#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"

using namespace cv;
using namespace std;

int main( int argc, char** argv )
{
    Mat src,gray;
    src = imread(argv ...
(more)
edit flag offensive delete link more

Comments

I know that i've only provided one case, but this shape wouldn't be detected if it was rotated 45 degrees as the bounding box just would be a square.. and thereby not a solid solution..

215 gravatar image215 ( 2015-11-14 04:12:08 -0600 )edit

You can use moment and contour.length()

LBerger gravatar imageLBerger ( 2015-11-14 04:45:38 -0600 )edit

as an extra check, or as a substitute for the one provided?

215 gravatar image215 ( 2015-11-14 04:58:48 -0600 )edit

After findContour you can calculate moment and contour length. After you can calculate ratio surface/length or major axis/ minor axis

LBerger gravatar imageLBerger ( 2015-11-14 05:21:30 -0600 )edit

Does the function know that the shape exist?.. I mean wouldn't be able to change it to an boolean function..

215 gravatar image215 ( 2015-11-15 12:28:47 -0600 )edit

you can modify as you need

sturkmen gravatar imagesturkmen ( 2015-11-15 12:40:42 -0600 )edit

Question Tools

2 followers

Stats

Asked: 2015-11-13 11:48:54 -0600

Seen: 2,713 times

Last updated: Nov 14 '15