Sie sind auf Seite 1von 9

Shape Detection Using Contouring

Contours can be explained simply as a curve joining all the continuous points (along the
boundary), having same color or intensity. The contours are a useful tool for shape analysis and
object detection and recognition.

For better accuracy, use binary images. So before finding contours, apply threshold or
canny edge detection.

findContours function modifies the source image. So if you want source image even after
finding contours, already store it to some other variables.

In OpenCV, finding contours is like finding white object from black background. So
remember, object to be found should be white and background should be black.

void findContours(InputOutputArray image, OutputArrayOfArrays contours, OutputArray


hierarchy,

int

mode,

int

method,

Point

offset=Point())

Parameters:

image Source, an 8-bit single-channel image. Non-zero pixels are treated as 1s. Zero
pixels remain 0s, so the image is treated as binary . You can use compare() , inRange() ,
threshold() , adaptiveThreshold() , Canny() , and others to create a binary image out of a
grayscale or color one. The function modifies the image while extracting the contours.

contours Detected contours. Each contour is stored as a vector of points.

mode Contour retrieval mode (if you use Python see also a note below).
o CV_RETR_EXTERNAL retrieves only the extreme outer contours. It sets
hierarchy[i][2]=hierarchy[i][3]=-1 for all the contours.

method Contour approximation method (if you use Python see also a note below). .

o CV_CHAIN_APPROX_SIMPLE compresses horizontal, vertical, and diagonal


segments and leaves only their end points. For example, an up-right rectangular
contour is encoded with 4 points.
How To Work
To detect pentagon, hexagon, and circle, we will use their properties as shown below.
Pentagon:
1. Has 5 vertices.
2. All angles are ~108 degree.
Hexagon:
1. Has 6 vertices.
2. All angles are ~120 degree.
Circle:
1. Has more than 6 vertices.
2. Has diameter of the same size in each direction.
3. The area of the contour is ~r2
In addition, I also want to detect square objects. A square is defined by a rectangle with four
equal sides. We need to convert the source image to binary image. We do this by converting the
image to grayscale first and threshold the grayscaled image. But as suggested in this code, well
use Canny operator rather than thresholding since Canny is able to catch squares with gradient
shading. The detection was made after the grayscale (Canny) then performed contouring with
reference sides are owned and angle values to which every waking flat different. This is exactly
what the reference how flat wake can be detected using this method.

CODE
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>

using namespace std;


using namespace cv;

static double angle(Point pt1, Point pt2, Point pt3)


{
double dx1 = pt1.x - pt3.x;
double dy1 = pt1.y - pt3.y;
double dx2 = pt2.x - pt3.x;
double dy2 = pt2.y - pt3.y;
return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
void setLabel(Mat& im, const string label, vector<Point>& contour) {
int font = FONT_HERSHEY_SIMPLEX;

double scale = 0.75;


int thickness = 0.75;
int baseline = 1;

Size text = getTextSize(label, font, scale, thickness, &baseline);


Rect r = boundingRect(contour);
Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
rectangle(im,

pt

Point(0,

baseline),

pt

Point(text.width,

CV_RGB(255,255,255), CV_FILLED);
putText(im, label, pt, font, scale, CV_RGB(0,0,0), thickness, 8);
}

int main() {
VideoCapture cap(0);
Mat frame;
while (true) {
cap.read(frame);
Mat image = frame.clone();
//Mat image = imread("shape1.png");

-text.height),

//imshow("test", image);
//waitKey(10);
if (image.empty()) {return -1;}

// Convert to grayscale
Mat gray;
cvtColor(image, gray, CV_BGR2GRAY);

// Use Canny instead of threshold to catch squares with gradient shading


Mat bw;
Mat blur;
Canny(gray, bw, 50, 200, 3);
// Find contours
vector<vector<Point> > contours;
findContours(bw.clone(),
CV_CHAIN_APPROX_SIMPLE);
vector<Point> approx;
Mat result = image.clone();

contours,

CV_RETR_EXTERNAL,

for (int i = 0; i < contours.size(); i++)


{
// Approximate contour with accuracy proportional
// to the contour perimeter
approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02,
true);

// Skip small or non-convex objects


if (fabs(contourArea(contours[i])) < 100 || !isContourConvex(approx))
continue;
if (approx.size() >= 3 && approx.size() <= 7)
{
int sisi = approx.size();

// Get the cosines of all corners


vector<double> cos;
for (int j = 2; j < sisi+1; j++)
cos.push_back(angle(approx[j%sisi], approx[j-2], approx[j-1]));
// Sort ascending the cosine values

sort(cos.begin(), cos.end());
// Get the lowest and the highest cosine
double mincos = cos.front();
double maxcos = cos.back();
// Use the degrees obtained above and the number of vertices
// to determine the shape of the contour
if (sisi == 3 && mincos >= 0 && maxcos <= 1)
setLabel(result, "S3", contours[i]);
else if (sisi == 4 && mincos >= -0.26 && maxcos <= 0)
setLabel(result, "S4", contours[i]);
else if (sisi == 5 && mincos >= -0.34 && maxcos <= -0.27)
setLabel(result, "S5", contours[i]);
else if (sisi == 6 && mincos >= -0.6 && maxcos <= -0.45)
setLabel(result, "S6", contours[i]);
else if (sisi == 7 && mincos >= -0.66 && maxcos <= -0.6)
setLabel(result, "S7", contours[i]);
}
else
{

// Detect and label circles


double area = contourArea(contours[i]);
Rect r = boundingRect(contours[i]);
int radius = r.width / 2;

if (abs(1 - ((double)r.width / r.height)) <= 0.2 &&


abs(1 - (area / (CV_PI * pow(radius, 2)))) <= 0.2)
setLabel(result, "L", contours[i]);
}
}

imshow("image", image);
imshow("bw", bw);
imshow("result", result);
waitKey(250);
}
return 0;
}

CODE EXPLANATIONS

TESTING

Das könnte Ihnen auch gefallen