# Detect different shaped contours?

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

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 close merge delete

( 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.

( 2015-11-13 14:14:06 -0600 )edit

Sort by ยป oldest newest most voted

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

input & output Image:

#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;
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:

#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;
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

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..

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

You can use moment and contour.length()

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

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

( 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

( 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..

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

you can modify as you need

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

Official site

GitHub

Wiki

Documentation

## Stats

Seen: 2,608 times

Last updated: Nov 14 '15