~paparazzi-uav/paparazzi/v5.0-manual

« back to all changes in this revision

Viewing changes to sw/ext/opencv_bebop/opencv/doc/py_tutorials/py_imgproc/py_contours/py_contour_features/py_contour_features.markdown

  • Committer: Paparazzi buildbot
  • Date: 2016-05-18 15:00:29 UTC
  • Revision ID: felix.ruess+docbot@gmail.com-20160518150029-e8lgzi5kvb4p7un9
Manual import commit 4b8bbb730080dac23cf816b98908dacfabe2a8ec from v5.0 branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
Contour Features {#tutorial_py_contour_features}
 
2
================
 
3
 
 
4
Goal
 
5
----
 
6
 
 
7
In this article, we will learn
 
8
 
 
9
-   To find the different features of contours, like area, perimeter, centroid, bounding box etc
 
10
-   You will see plenty of functions related to contours.
 
11
 
 
12
1. Moments
 
13
----------
 
14
 
 
15
Image moments help you to calculate some features like center of mass of the object, area of the
 
16
object etc. Check out the wikipedia page on [Image
 
17
Moments](http://en.wikipedia.org/wiki/Image_moment)
 
18
 
 
19
The function **cv2.moments()** gives a dictionary of all moment values calculated. See below:
 
20
@code{.py}
 
21
import cv2
 
22
import numpy as np
 
23
 
 
24
img = cv2.imread('star.jpg',0)
 
25
ret,thresh = cv2.threshold(img,127,255,0)
 
26
contours,hierarchy = cv2.findContours(thresh, 1, 2)
 
27
 
 
28
cnt = contours[0]
 
29
M = cv2.moments(cnt)
 
30
print M
 
31
@endcode
 
32
From this moments, you can extract useful data like area, centroid etc. Centroid is given by the
 
33
relations, \f$C_x = \frac{M_{10}}{M_{00}}\f$ and \f$C_y = \frac{M_{01}}{M_{00}}\f$. This can be done as
 
34
follows:
 
35
@code{.py}
 
36
cx = int(M['m10']/M['m00'])
 
37
cy = int(M['m01']/M['m00'])
 
38
@endcode
 
39
 
 
40
2. Contour Area
 
41
---------------
 
42
 
 
43
Contour area is given by the function **cv2.contourArea()** or from moments, **M['m00']**.
 
44
@code{.py}
 
45
area = cv2.contourArea(cnt)
 
46
@endcode
 
47
 
 
48
3. Contour Perimeter
 
49
--------------------
 
50
 
 
51
It is also called arc length. It can be found out using **cv2.arcLength()** function. Second
 
52
argument specify whether shape is a closed contour (if passed True), or just a curve.
 
53
@code{.py}
 
54
perimeter = cv2.arcLength(cnt,True)
 
55
@endcode
 
56
 
 
57
4. Contour Approximation
 
58
------------------------
 
59
 
 
60
It approximates a contour shape to another shape with less number of vertices depending upon the
 
61
precision we specify. It is an implementation of [Douglas-Peucker
 
62
algorithm](http://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm). Check the wikipedia page
 
63
for algorithm and demonstration.
 
64
 
 
65
To understand this, suppose you are trying to find a square in an image, but due to some problems in
 
66
the image, you didn't get a perfect square, but a "bad shape" (As shown in first image below). Now
 
67
you can use this function to approximate the shape. In this, second argument is called epsilon,
 
68
which is maximum distance from contour to approximated contour. It is an accuracy parameter. A wise
 
69
selection of epsilon is needed to get the correct output.
 
70
@code{.py}
 
71
epsilon = 0.1*cv2.arcLength(cnt,True)
 
72
approx = cv2.approxPolyDP(cnt,epsilon,True)
 
73
@endcode
 
74
Below, in second image, green line shows the approximated curve for epsilon = 10% of arc length.
 
75
Third image shows the same for epsilon = 1% of the arc length. Third argument specifies whether
 
76
curve is closed or not.
 
77
 
 
78
![image](images/approx.jpg)
 
79
 
 
80
5. Convex Hull
 
81
--------------
 
82
 
 
83
Convex Hull will look similar to contour approximation, but it is not (Both may provide same results
 
84
in some cases). Here, **cv2.convexHull()** function checks a curve for convexity defects and
 
85
corrects it. Generally speaking, convex curves are the curves which are always bulged out, or
 
86
at-least flat. And if it is bulged inside, it is called convexity defects. For example, check the
 
87
below image of hand. Red line shows the convex hull of hand. The double-sided arrow marks shows the
 
88
convexity defects, which are the local maximum deviations of hull from contours.
 
89
 
 
90
![image](images/convexitydefects.jpg)
 
91
 
 
92
There is a little bit things to discuss about it its syntax:
 
93
@code{.py}
 
94
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
 
95
@endcode
 
96
Arguments details:
 
97
 
 
98
-   **points** are the contours we pass into.
 
99
-   **hull** is the output, normally we avoid it.
 
100
-   **clockwise** : Orientation flag. If it is True, the output convex hull is oriented clockwise.
 
101
    Otherwise, it is oriented counter-clockwise.
 
102
-   **returnPoints** : By default, True. Then it returns the coordinates of the hull points. If
 
103
    False, it returns the indices of contour points corresponding to the hull points.
 
104
 
 
105
So to get a convex hull as in above image, following is sufficient:
 
106
@code{.py}
 
107
hull = cv2.convexHull(cnt)
 
108
@endcode
 
109
But if you want to find convexity defects, you need to pass returnPoints = False. To understand it,
 
110
we will take the rectangle image above. First I found its contour as cnt. Now I found its convex
 
111
hull with returnPoints = True, I got following values:
 
112
[[[234 202]], [[ 51 202]], [[ 51 79]], [[234 79]]] which are the four corner points of rectangle.
 
113
Now if do the same with returnPoints = False, I get following result: [[129],[ 67],[ 0],[142]].
 
114
These are the indices of corresponding points in contours. For eg, check the first value:
 
115
cnt[129] = [[234, 202]] which is same as first result (and so on for others).
 
116
 
 
117
You will see it again when we discuss about convexity defects.
 
118
 
 
119
6. Checking Convexity
 
120
---------------------
 
121
 
 
122
There is a function to check if a curve is convex or not, **cv2.isContourConvex()**. It just return
 
123
whether True or False. Not a big deal.
 
124
@code{.py}
 
125
k = cv2.isContourConvex(cnt)
 
126
@endcode
 
127
 
 
128
7. Bounding Rectangle
 
129
---------------------
 
130
 
 
131
There are two types of bounding rectangles.
 
132
 
 
133
### 7.a. Straight Bounding Rectangle
 
134
 
 
135
It is a straight rectangle, it doesn't consider the rotation of the object. So area of the bounding
 
136
rectangle won't be minimum. It is found by the function **cv2.boundingRect()**.
 
137
 
 
138
Let (x,y) be the top-left coordinate of the rectangle and (w,h) be its width and height.
 
139
@code{.py}
 
140
x,y,w,h = cv2.boundingRect(cnt)
 
141
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
 
142
@endcode
 
143
 
 
144
### 7.b. Rotated Rectangle
 
145
 
 
146
Here, bounding rectangle is drawn with minimum area, so it considers the rotation also. The function
 
147
used is **cv2.minAreaRect()**. It returns a Box2D structure which contains following detals - (
 
148
center (x,y), (width, height), angle of rotation ). But to draw this rectangle, we need 4 corners of
 
149
the rectangle. It is obtained by the function **cv2.boxPoints()**
 
150
@code{.py}
 
151
rect = cv2.minAreaRect(cnt)
 
152
box = cv2.boxPoints(rect)
 
153
box = np.int0(box)
 
154
cv2.drawContours(img,[box],0,(0,0,255),2)
 
155
@endcode
 
156
Both the rectangles are shown in a single image. Green rectangle shows the normal bounding rect. Red
 
157
rectangle is the rotated rect.
 
158
 
 
159
![image](images/boundingrect.png)
 
160
 
 
161
8. Minimum Enclosing Circle
 
162
---------------------------
 
163
 
 
164
Next we find the circumcircle of an object using the function **cv2.minEnclosingCircle()**. It is a
 
165
circle which completely covers the object with minimum area.
 
166
@code{.py}
 
167
(x,y),radius = cv2.minEnclosingCircle(cnt)
 
168
center = (int(x),int(y))
 
169
radius = int(radius)
 
170
cv2.circle(img,center,radius,(0,255,0),2)
 
171
@endcode
 
172
![image](images/circumcircle.png)
 
173
 
 
174
9. Fitting an Ellipse
 
175
---------------------
 
176
 
 
177
Next one is to fit an ellipse to an object. It returns the rotated rectangle in which the ellipse is
 
178
inscribed.
 
179
@code{.py}
 
180
ellipse = cv2.fitEllipse(cnt)
 
181
cv2.ellipse(img,ellipse,(0,255,0),2)
 
182
@endcode
 
183
![image](images/fitellipse.png)
 
184
 
 
185
10. Fitting a Line
 
186
------------------
 
187
 
 
188
Similarly we can fit a line to a set of points. Below image contains a set of white points. We can
 
189
approximate a straight line to it.
 
190
@code{.py}
 
191
rows,cols = img.shape[:2]
 
192
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
 
193
lefty = int((-x*vy/vx) + y)
 
194
righty = int(((cols-x)*vy/vx)+y)
 
195
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
 
196
@endcode
 
197
![image](images/fitline.jpg)
 
198
 
 
199
Additional Resources
 
200
--------------------
 
201
 
 
202
Exercises
 
203
---------