Doxygen tutorials: python final edits
This commit is contained in:
@@ -17,52 +17,55 @@ Canny Edge Detection is a popular edge detection algorithm. It was developed by
|
||||
|
||||
-# **Noise Reduction**
|
||||
|
||||
Since edge detection is susceptible to noise in the image, first step is to remove the noise in the
|
||||
image with a 5x5 Gaussian filter. We have already seen this in previous chapters.
|
||||
Since edge detection is susceptible to noise in the image, first step is to remove the noise in the
|
||||
image with a 5x5 Gaussian filter. We have already seen this in previous chapters.
|
||||
|
||||
-# **Finding Intensity Gradient of the Image**
|
||||
|
||||
Smoothened image is then filtered with a Sobel kernel in both horizontal and vertical direction to
|
||||
get first derivative in horizontal direction (\f$G_x\f$) and vertical direction (\f$G_y\f$). From these two
|
||||
images, we can find edge gradient and direction for each pixel as follows:
|
||||
Smoothened image is then filtered with a Sobel kernel in both horizontal and vertical direction to
|
||||
get first derivative in horizontal direction (\f$G_x\f$) and vertical direction (\f$G_y\f$). From these two
|
||||
images, we can find edge gradient and direction for each pixel as follows:
|
||||
|
||||
\f[Edge_Gradient \; (G) = \sqrt{G_x^2 + G_y^2}\f]\f[Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg)\f]
|
||||
\f[
|
||||
Edge\_Gradient \; (G) = \sqrt{G_x^2 + G_y^2} \\
|
||||
Angle \; (\theta) = \tan^{-1} \bigg(\frac{G_y}{G_x}\bigg)
|
||||
\f]
|
||||
|
||||
Gradient direction is always perpendicular to edges. It is rounded to one of four angles
|
||||
representing vertical, horizontal and two diagonal directions.
|
||||
Gradient direction is always perpendicular to edges. It is rounded to one of four angles
|
||||
representing vertical, horizontal and two diagonal directions.
|
||||
|
||||
-# **Non-maximum Suppression**
|
||||
|
||||
After getting gradient magnitude and direction, a full scan of image is done to remove any unwanted
|
||||
pixels which may not constitute the edge. For this, at every pixel, pixel is checked if it is a
|
||||
local maximum in its neighborhood in the direction of gradient. Check the image below:
|
||||
After getting gradient magnitude and direction, a full scan of image is done to remove any unwanted
|
||||
pixels which may not constitute the edge. For this, at every pixel, pixel is checked if it is a
|
||||
local maximum in its neighborhood in the direction of gradient. Check the image below:
|
||||
|
||||

|
||||

|
||||
|
||||
Point A is on the edge ( in vertical direction). Gradient direction is normal to the edge. Point B
|
||||
and C are in gradient directions. So point A is checked with point B and C to see if it forms a
|
||||
local maximum. If so, it is considered for next stage, otherwise, it is suppressed ( put to zero).
|
||||
Point A is on the edge ( in vertical direction). Gradient direction is normal to the edge. Point B
|
||||
and C are in gradient directions. So point A is checked with point B and C to see if it forms a
|
||||
local maximum. If so, it is considered for next stage, otherwise, it is suppressed ( put to zero).
|
||||
|
||||
In short, the result you get is a binary image with "thin edges".
|
||||
In short, the result you get is a binary image with "thin edges".
|
||||
|
||||
-# **Hysteresis Thresholding**
|
||||
|
||||
This stage decides which are all edges are really edges and which are not. For this, we need two
|
||||
threshold values, minVal and maxVal. Any edges with intensity gradient more than maxVal are sure to
|
||||
be edges and those below minVal are sure to be non-edges, so discarded. Those who lie between these
|
||||
two thresholds are classified edges or non-edges based on their connectivity. If they are connected
|
||||
to "sure-edge" pixels, they are considered to be part of edges. Otherwise, they are also discarded.
|
||||
See the image below:
|
||||
This stage decides which are all edges are really edges and which are not. For this, we need two
|
||||
threshold values, minVal and maxVal. Any edges with intensity gradient more than maxVal are sure to
|
||||
be edges and those below minVal are sure to be non-edges, so discarded. Those who lie between these
|
||||
two thresholds are classified edges or non-edges based on their connectivity. If they are connected
|
||||
to "sure-edge" pixels, they are considered to be part of edges. Otherwise, they are also discarded.
|
||||
See the image below:
|
||||
|
||||

|
||||

|
||||
|
||||
The edge A is above the maxVal, so considered as "sure-edge". Although edge C is below maxVal, it is
|
||||
connected to edge A, so that also considered as valid edge and we get that full curve. But edge B,
|
||||
although it is above minVal and is in same region as that of edge C, it is not connected to any
|
||||
"sure-edge", so that is discarded. So it is very important that we have to select minVal and maxVal
|
||||
accordingly to get the correct result.
|
||||
The edge A is above the maxVal, so considered as "sure-edge". Although edge C is below maxVal, it is
|
||||
connected to edge A, so that also considered as valid edge and we get that full curve. But edge B,
|
||||
although it is above minVal and is in same region as that of edge C, it is not connected to any
|
||||
"sure-edge", so that is discarded. So it is very important that we have to select minVal and maxVal
|
||||
accordingly to get the correct result.
|
||||
|
||||
This stage also removes small pixels noises on the assumption that edges are long lines.
|
||||
This stage also removes small pixels noises on the assumption that edges are long lines.
|
||||
|
||||
So what we finally get is strong edges in the image.
|
||||
|
||||
@@ -74,7 +77,7 @@ argument is our input image. Second and third arguments are our minVal and maxVa
|
||||
Third argument is aperture_size. It is the size of Sobel kernel used for find image gradients. By
|
||||
default it is 3. Last argument is L2gradient which specifies the equation for finding gradient
|
||||
magnitude. If it is True, it uses the equation mentioned above which is more accurate, otherwise it
|
||||
uses this function: \f$Edge_Gradient \; (G) = |G_x| + |G_y|\f$. By default, it is False.
|
||||
uses this function: \f$Edge\_Gradient \; (G) = |G_x| + |G_y|\f$. By default, it is False.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
@@ -98,8 +101,7 @@ Additional Resources
|
||||
--------------------
|
||||
|
||||
-# Canny edge detector at [Wikipedia](http://en.wikipedia.org/wiki/Canny_edge_detector)
|
||||
2. [Canny Edge Detection
|
||||
Tutorial](http://dasl.mem.drexel.edu/alumni/bGreen/www.pages.drexel.edu/_weg22/can_tut.html) by
|
||||
-# [Canny Edge Detection Tutorial](http://dasl.mem.drexel.edu/alumni/bGreen/www.pages.drexel.edu/_weg22/can_tut.html) by
|
||||
Bill Green, 2002.
|
||||
|
||||
Exercises
|
||||
@@ -107,4 +109,3 @@ Exercises
|
||||
|
||||
-# Write a small application to find the Canny edge detection whose threshold values can be varied
|
||||
using two trackbars. This way, you can understand the effect of threshold values.
|
||||
|
||||
|
@@ -22,13 +22,16 @@ For BGR \f$\rightarrow\f$ Gray conversion we use the flags cv2.COLOR_BGR2GRAY. S
|
||||
\f$\rightarrow\f$ HSV, we use the flag cv2.COLOR_BGR2HSV. To get other flags, just run following
|
||||
commands in your Python terminal :
|
||||
@code{.py}
|
||||
import cv2
|
||||
flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
|
||||
print flags
|
||||
>>> import cv2
|
||||
>>> flags = [i for i in dir(cv2) if i.startswith('COLOR_')]
|
||||
>>> print flags
|
||||
@endcode
|
||||
@note For HSV, Hue range is [0,179], Saturation range is [0,255] and Value range is [0,255].
|
||||
Different softwares use different scales. So if you are comparing OpenCV values with them, you need
|
||||
to normalize these ranges. Object Tracking ==================
|
||||
to normalize these ranges.
|
||||
|
||||
Object Tracking
|
||||
---------------
|
||||
|
||||
Now we know how to convert BGR image to HSV, we can use this to extract a colored object. In HSV, it
|
||||
is more easier to represent a color than RGB color-space. In our application, we will try to extract
|
||||
@@ -81,15 +84,19 @@ Below image shows tracking of the blue object:
|
||||
|
||||
@note This is the simplest method in object tracking. Once you learn functions of contours, you can
|
||||
do plenty of things like find centroid of this object and use it to track the object, draw diagrams
|
||||
just by moving your hand in front of camera and many other funny stuffs. How to find HSV values to
|
||||
track? -----------------------------------This is a common question found in
|
||||
[stackoverflow.com](www.stackoverflow.com). It is very simple and you can use the same function,
|
||||
cv2.cvtColor(). Instead of passing an image, you just pass the BGR values you want. For example, to
|
||||
find the HSV value of Green, try following commands in Python terminal:
|
||||
just by moving your hand in front of camera and many other funny stuffs.
|
||||
|
||||
How to find HSV values to track?
|
||||
--------------------------------
|
||||
|
||||
This is a common question found in [stackoverflow.com](www.stackoverflow.com). It is very simple and
|
||||
you can use the same function, cv2.cvtColor(). Instead of passing an image, you just pass the BGR
|
||||
values you want. For example, to find the HSV value of Green, try following commands in Python
|
||||
terminal:
|
||||
@code{.py}
|
||||
green = np.uint8([[[0,255,0 ]]])
|
||||
hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
|
||||
print hsv_green
|
||||
>>> green = np.uint8([[[0,255,0 ]]])
|
||||
>>> hsv_green = cv2.cvtColor(green,cv2.COLOR_BGR2HSV)
|
||||
>>> print hsv_green
|
||||
[[[ 60 255 255]]]
|
||||
@endcode
|
||||
Now you take [H-10, 100,100] and [H+10, 255, 255] as lower bound and upper bound respectively. Apart
|
||||
@@ -104,4 +111,3 @@ Exercises
|
||||
|
||||
-# Try to find a way to extract more than one colored objects, for eg, extract red, blue, green
|
||||
objects simultaneously.
|
||||
|
||||
|
@@ -9,7 +9,7 @@ In this article, we will learn
|
||||
- To find the different features of contours, like area, perimeter, centroid, bounding box etc
|
||||
- You will see plenty of functions related to contours.
|
||||
|
||||
-# Moments
|
||||
1. Moments
|
||||
----------
|
||||
|
||||
Image moments help you to calculate some features like center of mass of the object, area of the
|
||||
@@ -36,6 +36,7 @@ follows:
|
||||
cx = int(M['m10']/M['m00'])
|
||||
cy = int(M['m01']/M['m00'])
|
||||
@endcode
|
||||
|
||||
2. Contour Area
|
||||
---------------
|
||||
|
||||
@@ -43,6 +44,7 @@ Contour area is given by the function **cv2.contourArea()** or from moments, **M
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
@endcode
|
||||
|
||||
3. Contour Perimeter
|
||||
--------------------
|
||||
|
||||
@@ -51,6 +53,7 @@ argument specify whether shape is a closed contour (if passed True), or just a c
|
||||
@code{.py}
|
||||
perimeter = cv2.arcLength(cnt,True)
|
||||
@endcode
|
||||
|
||||
4. Contour Approximation
|
||||
------------------------
|
||||
|
||||
@@ -74,7 +77,7 @@ curve is closed or not.
|
||||
|
||||

|
||||
|
||||
-# Convex Hull
|
||||
5. Convex Hull
|
||||
--------------
|
||||
|
||||
Convex Hull will look similar to contour approximation, but it is not (Both may provide same results
|
||||
@@ -113,7 +116,7 @@ cnt[129] = [[234, 202]] which is same as first result (and so on for others).
|
||||
|
||||
You will see it again when we discuss about convexity defects.
|
||||
|
||||
-# Checking Convexity
|
||||
6. Checking Convexity
|
||||
---------------------
|
||||
|
||||
There is a function to check if a curve is convex or not, **cv2.isContourConvex()**. It just return
|
||||
@@ -121,6 +124,7 @@ whether True or False. Not a big deal.
|
||||
@code{.py}
|
||||
k = cv2.isContourConvex(cnt)
|
||||
@endcode
|
||||
|
||||
7. Bounding Rectangle
|
||||
---------------------
|
||||
|
||||
@@ -136,6 +140,7 @@ Let (x,y) be the top-left coordinate of the rectangle and (w,h) be its width and
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
|
||||
@endcode
|
||||
|
||||
### 7.b. Rotated Rectangle
|
||||
|
||||
Here, bounding rectangle is drawn with minimum area, so it considers the rotation also. The function
|
||||
@@ -153,7 +158,7 @@ rectangle is the rotated rect.
|
||||
|
||||

|
||||
|
||||
-# Minimum Enclosing Circle
|
||||
8. Minimum Enclosing Circle
|
||||
---------------------------
|
||||
|
||||
Next we find the circumcircle of an object using the function **cv2.minEnclosingCircle()**. It is a
|
||||
@@ -166,7 +171,7 @@ cv2.circle(img,center,radius,(0,255,0),2)
|
||||
@endcode
|
||||

|
||||
|
||||
-# Fitting an Ellipse
|
||||
9. Fitting an Ellipse
|
||||
---------------------
|
||||
|
||||
Next one is to fit an ellipse to an object. It returns the rotated rectangle in which the ellipse is
|
||||
@@ -177,7 +182,7 @@ cv2.ellipse(img,ellipse,(0,255,0),2)
|
||||
@endcode
|
||||

|
||||
|
||||
-# Fitting a Line
|
||||
10. Fitting a Line
|
||||
------------------
|
||||
|
||||
Similarly we can fit a line to a set of points. Below image contains a set of white points. We can
|
||||
|
@@ -8,50 +8,54 @@ documentation](http://www.mathworks.in/help/images/ref/regionprops.html).
|
||||
*(NB : Centroid, Area, Perimeter etc also belong to this category, but we have seen it in last
|
||||
chapter)*
|
||||
|
||||
-# Aspect Ratio
|
||||
1. Aspect Ratio
|
||||
---------------
|
||||
|
||||
It is the ratio of width to height of bounding rect of the object.
|
||||
|
||||
\f[Aspect \; Ratio = \frac{Width}{Height}\f]
|
||||
@code{.python}
|
||||
@code{.py}
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
aspect_ratio = float(w)/h
|
||||
@endcode
|
||||
|
||||
2. Extent
|
||||
---------
|
||||
|
||||
Extent is the ratio of contour area to bounding rectangle area.
|
||||
|
||||
\f[Extent = \frac{Object \; Area}{Bounding \; Rectangle \; Area}\f]
|
||||
@code{.python}
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
rect_area = w*h
|
||||
extent = float(area)/rect_area
|
||||
@endcode
|
||||
|
||||
3. Solidity
|
||||
-----------
|
||||
|
||||
Solidity is the ratio of contour area to its convex hull area.
|
||||
|
||||
\f[Solidity = \frac{Contour \; Area}{Convex \; Hull \; Area}\f]
|
||||
@code{.python}
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
hull = cv2.convexHull(cnt)
|
||||
hull_area = cv2.contourArea(hull)
|
||||
solidity = float(area)/hull_area
|
||||
@endcode
|
||||
|
||||
4. Equivalent Diameter
|
||||
----------------------
|
||||
|
||||
Equivalent Diameter is the diameter of the circle whose area is same as the contour area.
|
||||
|
||||
\f[Equivalent \; Diameter = \sqrt{\frac{4 \times Contour \; Area}{\pi}}\f]
|
||||
@code{.python}
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
equi_diameter = np.sqrt(4*area/np.pi)
|
||||
@endcode
|
||||
|
||||
5. Orientation
|
||||
--------------
|
||||
|
||||
@@ -60,6 +64,7 @@ Minor Axis lengths.
|
||||
@code{.py}
|
||||
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
|
||||
@endcode
|
||||
|
||||
6. Mask and Pixel Points
|
||||
------------------------
|
||||
|
||||
@@ -75,13 +80,14 @@ are given to do the same. Results are also same, but with a slight difference. N
|
||||
coordinates in **(row, column)** format, while OpenCV gives coordinates in **(x,y)** format. So
|
||||
basically the answers will be interchanged. Note that, **row = x** and **column = y**.
|
||||
|
||||
-# Maximum Value, Minimum Value and their locations
|
||||
7. Maximum Value, Minimum Value and their locations
|
||||
---------------------------------------------------
|
||||
|
||||
We can find these parameters using a mask image.
|
||||
@code{.py}
|
||||
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
|
||||
@endcode
|
||||
|
||||
8. Mean Color or Mean Intensity
|
||||
-------------------------------
|
||||
|
||||
@@ -90,6 +96,7 @@ grayscale mode. We again use the same mask to do it.
|
||||
@code{.py}
|
||||
mean_val = cv2.mean(im,mask = mask)
|
||||
@endcode
|
||||
|
||||
9. Extreme Points
|
||||
-----------------
|
||||
|
||||
@@ -111,4 +118,3 @@ Exercises
|
||||
---------
|
||||
|
||||
-# There are still some features left in matlab regionprops doc. Try to implement them.
|
||||
|
||||
|
@@ -62,8 +62,11 @@ But most of the time, below method will be useful:
|
||||
cnt = contours[4]
|
||||
cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
|
||||
@endcode
|
||||
|
||||
@note Last two methods are same, but when you go forward, you will see last one is more useful.
|
||||
Contour Approximation Method ================================
|
||||
|
||||
Contour Approximation Method
|
||||
============================
|
||||
|
||||
This is the third argument in cv2.findContours function. What does it denote actually?
|
||||
|
||||
|
@@ -55,26 +55,35 @@ So each contour has its own information regarding what hierarchy it is, who is i
|
||||
parent etc. OpenCV represents it as an array of four values : **[Next, Previous, First_Child,
|
||||
Parent]**
|
||||
|
||||
<center>*"Next denotes next contour at the same hierarchical level."*</center>
|
||||
|
||||
For eg, take contour-0 in our picture. Who is next contour in its same level ? It is contour-1. So
|
||||
simply put Next = 1. Similarly for Contour-1, next is contour-2. So Next = 2.
|
||||
|
||||
What about contour-2? There is no next contour in the same level. So simply, put Next = -1. What
|
||||
about contour-4? It is in same level with contour-5. So its next contour is contour-5, so Next = 5.
|
||||
|
||||
<center>*"Previous denotes previous contour at the same hierarchical level."*</center>
|
||||
|
||||
It is same as above. Previous contour of contour-1 is contour-0 in the same level. Similarly for
|
||||
contour-2, it is contour-1. And for contour-0, there is no previous, so put it as -1.
|
||||
|
||||
<center>*"First_Child denotes its first child contour."*</center>
|
||||
|
||||
There is no need of any explanation. For contour-2, child is contour-2a. So it gets the
|
||||
corresponding index value of contour-2a. What about contour-3a? It has two children. But we take
|
||||
only first child. And it is contour-4. So First_Child = 4 for contour-3a.
|
||||
|
||||
<center>*"Parent denotes index of its parent contour."*</center>
|
||||
|
||||
It is just opposite of **First_Child**. Both for contour-4 and contour-5, parent contour is
|
||||
contour-3a. For contour-3a, it is contour-3 and so on.
|
||||
|
||||
@note If there is no child or parent, that field is taken as -1 So now we know about the hierarchy
|
||||
style used in OpenCV, we can check into Contour Retrieval Modes in OpenCV with the help of same
|
||||
image given above. ie what do flags like cv2.RETR_LIST, cv2.RETR_TREE, cv2.RETR_CCOMP,
|
||||
cv2.RETR_EXTERNAL etc mean?
|
||||
@note If there is no child or parent, that field is taken as -1
|
||||
|
||||
So now we know about the hierarchy style used in OpenCV, we can check into Contour Retrieval Modes
|
||||
in OpenCV with the help of same image given above. ie what do flags like cv2.RETR_LIST,
|
||||
cv2.RETR_TREE, cv2.RETR_CCOMP, cv2.RETR_EXTERNAL etc mean?
|
||||
|
||||
Contour Retrieval Mode
|
||||
----------------------
|
||||
@@ -92,7 +101,7 @@ Below is the result I got, and each row is hierarchy details of corresponding co
|
||||
row corresponds to contour 0. Next contour is contour 1. So Next = 1. There is no previous contour,
|
||||
so Previous = 0. And the remaining two, as told before, it is -1.
|
||||
@code{.py}
|
||||
hierarchy
|
||||
>>> hierarchy
|
||||
array([[[ 1, -1, -1, -1],
|
||||
[ 2, 0, -1, -1],
|
||||
[ 3, 1, -1, -1],
|
||||
@@ -114,7 +123,7 @@ So, in our image, how many extreme outer contours are there? ie at hierarchy-0 l
|
||||
contours 0,1,2, right? Now try to find the contours using this flag. Here also, values given to each
|
||||
element is same as above. Compare it with above result. Below is what I got :
|
||||
@code{.py}
|
||||
hierarchy
|
||||
>>> hierarchy
|
||||
array([[[ 1, -1, -1, -1],
|
||||
[ 2, 0, -1, -1],
|
||||
[-1, 1, -1, -1]]])
|
||||
@@ -159,7 +168,7 @@ no child, parent is contour-3. So array is [-1,-1,-1,3].
|
||||
|
||||
Remaining you can fill up. This is the final answer I got:
|
||||
@code{.py}
|
||||
hierarchy
|
||||
>>> hierarchy
|
||||
array([[[ 3, -1, 1, -1],
|
||||
[ 2, -1, -1, 0],
|
||||
[-1, 1, -1, 0],
|
||||
@@ -170,6 +179,7 @@ array([[[ 3, -1, 1, -1],
|
||||
[ 8, 5, -1, -1],
|
||||
[-1, 7, -1, -1]]])
|
||||
@endcode
|
||||
|
||||
### 4. RETR_TREE
|
||||
|
||||
And this is the final guy, Mr.Perfect. It retrieves all the contours and creates a full family
|
||||
@@ -189,7 +199,7 @@ contour-2. Parent is contour-0. So array is [-1,-1,2,0].
|
||||
|
||||
And remaining, try yourself. Below is the full answer:
|
||||
@code{.py}
|
||||
hierarchy
|
||||
>>> hierarchy
|
||||
array([[[ 7, -1, 1, -1],
|
||||
[-1, -1, 2, 0],
|
||||
[-1, -1, 3, 1],
|
||||
@@ -200,6 +210,7 @@ array([[[ 7, -1, 1, -1],
|
||||
[ 8, 0, -1, -1],
|
||||
[-1, 7, -1, -1]]])
|
||||
@endcode
|
||||
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter, we will learn about
|
||||
- Convexity defects and how to find them.
|
||||
- Convexity defects and how to find them.
|
||||
- Finding shortest distance from a point to a polygon
|
||||
- Matching different shapes
|
||||
|
||||
@@ -23,11 +23,15 @@ call would look like below:
|
||||
hull = cv2.convexHull(cnt,returnPoints = False)
|
||||
defects = cv2.convexityDefects(cnt,hull)
|
||||
@endcode
|
||||
|
||||
@note Remember we have to pass returnPoints = False while finding convex hull, in order to find
|
||||
convexity defects. It returns an array where each row contains these values - **[ start point, end
|
||||
point, farthest point, approximate distance to farthest point ]**. We can visualize it using an
|
||||
image. We draw a line joining start point and end point, then draw a circle at the farthest point.
|
||||
Remember first three values returned are indices of cnt. So we have to bring those values from cnt.
|
||||
convexity defects.
|
||||
|
||||
It returns an array where each row contains these values - **[ start point, end point, farthest
|
||||
point, approximate distance to farthest point ]**. We can visualize it using an image. We draw a
|
||||
line joining start point and end point, then draw a circle at the farthest point. Remember first
|
||||
three values returned are indices of cnt. So we have to bring those values from cnt.
|
||||
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
@@ -72,8 +76,9 @@ False, it finds whether the point is inside or outside or on the contour (it ret
|
||||
respectively).
|
||||
|
||||
@note If you don't want to find the distance, make sure third argument is False, because, it is a
|
||||
time consuming process. So, making it False gives about 2-3X speedup. 3. Match
|
||||
Shapes -----------------
|
||||
time consuming process. So, making it False gives about 2-3X speedup.
|
||||
|
||||
### 3. Match Shapes
|
||||
|
||||
OpenCV comes with a function **cv2.matchShapes()** which enables us to compare two shapes, or two
|
||||
contours and returns a metric showing the similarity. The lower the result, the better match it is.
|
||||
@@ -110,7 +115,10 @@ See, even image rotation doesn't affect much on this comparison.
|
||||
|
||||
@sa [Hu-Moments](http://en.wikipedia.org/wiki/Image_moment#Rotation_invariant_moments) are seven
|
||||
moments invariant to translation, rotation and scale. Seventh one is skew-invariant. Those values
|
||||
can be found using **cv2.HuMoments()** function. Additional Resources =====================
|
||||
can be found using **cv2.HuMoments()** function.
|
||||
|
||||
Additional Resources
|
||||
====================
|
||||
|
||||
Exercises
|
||||
---------
|
||||
@@ -120,6 +128,5 @@ Exercises
|
||||
inside curve is blue depending on the distance. Similarly outside points are red. Contour edges
|
||||
are marked with White. So problem is simple. Write a code to create such a representation of
|
||||
distance.
|
||||
2. Compare images of digits or letters using **cv2.matchShapes()**. ( That would be a simple step
|
||||
-# Compare images of digits or letters using **cv2.matchShapes()**. ( That would be a simple step
|
||||
towards OCR )
|
||||
|
||||
|
@@ -5,7 +5,7 @@ Goals
|
||||
-----
|
||||
|
||||
Learn to:
|
||||
- Blur the images with various low pass filters
|
||||
- Blur the images with various low pass filters
|
||||
- Apply custom-made filters to images (2D convolution)
|
||||
|
||||
2D Convolution ( Image Filtering )
|
||||
@@ -61,7 +61,9 @@ specify the width and height of kernel. A 3x3 normalized box filter would look l
|
||||
\f[K = \frac{1}{9} \begin{bmatrix} 1 & 1 & 1 \\ 1 & 1 & 1 \\ 1 & 1 & 1 \end{bmatrix}\f]
|
||||
|
||||
@note If you don't want to use normalized box filter, use **cv2.boxFilter()**. Pass an argument
|
||||
normalize=False to the function. Check a sample demo below with a kernel of 5x5 size:
|
||||
normalize=False to the function.
|
||||
|
||||
Check a sample demo below with a kernel of 5x5 size:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter
|
||||
- We will see GrabCut algorithm to extract foreground in images
|
||||
- We will see GrabCut algorithm to extract foreground in images
|
||||
- We will create an interactive application for this.
|
||||
|
||||
Theory
|
||||
@@ -59,7 +59,7 @@ So what happens in background ?
|
||||
|
||||
It is illustrated in below image (Image Courtesy: <http://www.cs.ru.ac.za/research/g02m1682/>)
|
||||
|
||||

|
||||

|
||||
|
||||
Demo
|
||||
----
|
||||
@@ -152,6 +152,5 @@ Exercises
|
||||
|
||||
-# OpenCV samples contain a sample grabcut.py which is an interactive tool using grabcut. Check it.
|
||||
Also watch this [youtube video](http://www.youtube.com/watch?v=kAwxLTDDAwU) on how to use it.
|
||||
2. Here, you can make this into a interactive sample with drawing rectangle and strokes with mouse,
|
||||
-# Here, you can make this into a interactive sample with drawing rectangle and strokes with mouse,
|
||||
create trackbar to adjust stroke width etc.
|
||||
|
||||
|
@@ -36,7 +36,7 @@ So what happens in background ?
|
||||
|
||||
It is illustrated in below image (Image Courtesy: http://www.cs.ru.ac.za/research/g02m1682/)
|
||||
|
||||
.. image:: images/grabcut.jpg
|
||||
.. image:: images/grabcut_scheme.jpg
|
||||
:alt: Simplified Diagram of GrabCut Algorithm
|
||||
:align: center
|
||||
|
||||
|
@@ -82,6 +82,7 @@ idea what color is there on a first look, unless you know the Hue values of diff
|
||||
I prefer this method. It is simple and better.
|
||||
|
||||
@note While using this function, remember, interpolation flag should be nearest for better results.
|
||||
|
||||
Consider code:
|
||||
@code{.py}
|
||||
import cv2
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
Learn to
|
||||
- Find histograms, using both OpenCV and Numpy functions
|
||||
- Find histograms, using both OpenCV and Numpy functions
|
||||
- Plot histograms, using OpenCV and Matplotlib functions
|
||||
- You will see these functions : **cv2.calcHist()**, **np.histogram()** etc.
|
||||
|
||||
@@ -39,8 +39,8 @@ terminologies related with histograms.
|
||||
**BINS** :The above histogram shows the number of pixels for every pixel value, ie from 0 to 255. ie
|
||||
you need 256 values to show the above histogram. But consider, what if you need not find the number
|
||||
of pixels for all pixel values separately, but number of pixels in a interval of pixel values? say
|
||||
for example, you need to find the number of pixels lying between 0 to 15, then 16 to 31, ..., 240 to
|
||||
255. You will need only 16 values to represent the histogram. And that is what is shown in example
|
||||
for example, you need to find the number of pixels lying between 0 to 15, then 16 to 31, ..., 240 to 255.
|
||||
You will need only 16 values to represent the histogram. And that is what is shown in example
|
||||
given in [OpenCV Tutorials on
|
||||
histograms](http://docs.opencv.org/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html#histogram-calculation).
|
||||
|
||||
@@ -60,18 +60,20 @@ intensity values.
|
||||
So now we use **cv2.calcHist()** function to find the histogram. Let's familiarize with the function
|
||||
and its parameters :
|
||||
|
||||
<center><em>cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate]])</em></center>
|
||||
|
||||
-# images : it is the source image of type uint8 or float32. it should be given in square brackets,
|
||||
ie, "[img]".
|
||||
2. channels : it is also given in square brackets. It is the index of channel for which we
|
||||
-# channels : it is also given in square brackets. It is the index of channel for which we
|
||||
calculate histogram. For example, if input is grayscale image, its value is [0]. For color
|
||||
image, you can pass [0], [1] or [2] to calculate histogram of blue, green or red channel
|
||||
respectively.
|
||||
3. mask : mask image. To find histogram of full image, it is given as "None". But if you want to
|
||||
-# mask : mask image. To find histogram of full image, it is given as "None". But if you want to
|
||||
find histogram of particular region of image, you have to create a mask image for that and give
|
||||
it as mask. (I will show an example later.)
|
||||
4. histSize : this represents our BIN count. Need to be given in square brackets. For full scale,
|
||||
-# histSize : this represents our BIN count. Need to be given in square brackets. For full scale,
|
||||
we pass [256].
|
||||
5. ranges : this is our RANGE. Normally, it is [0,256].
|
||||
-# ranges : this is our RANGE. Normally, it is [0,256].
|
||||
|
||||
So let's start with a sample image. Simply load an image in grayscale mode and find its full
|
||||
histogram.
|
||||
@@ -98,13 +100,15 @@ np.histogram(). So for one-dimensional histograms, you can better try that. Don'
|
||||
minlength = 256 in np.bincount. For example, hist = np.bincount(img.ravel(),minlength=256)
|
||||
|
||||
@note OpenCV function is more faster than (around 40X) than np.histogram(). So stick with OpenCV
|
||||
function. Now we should plot histograms, but how ?
|
||||
function.
|
||||
|
||||
Now we should plot histograms, but how?
|
||||
|
||||
Plotting Histograms
|
||||
-------------------
|
||||
|
||||
There are two ways for this,
|
||||
-# Short Way : use Matplotlib plotting functions
|
||||
-# Short Way : use Matplotlib plotting functions
|
||||
-# Long Way : use OpenCV drawing functions
|
||||
|
||||
### 1. Using Matplotlib
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will learn to use Hough Transform to find circles in an image.
|
||||
- We will learn to use Hough Transform to find circles in an image.
|
||||
- We will see these functions: **cv2.HoughCircles()**
|
||||
|
||||
Theory
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will understand the concept of Hough Tranform.
|
||||
- We will understand the concept of Hough Tranform.
|
||||
- We will see how to use it detect lines in an image.
|
||||
- We will see following functions: **cv2.HoughLines()**, **cv2.HoughLinesP()**
|
||||
|
||||
@@ -49,19 +49,15 @@ each point, the cell (50,90) will be incremented or voted up, while other cells
|
||||
voted up. This way, at the end, the cell (50,90) will have maximum votes. So if you search the
|
||||
accumulator for maximum votes, you get the value (50,90) which says, there is a line in this image
|
||||
at distance 50 from origin and at angle 90 degrees. It is well shown in below animation (Image
|
||||
Courtesy: Amos Storkey _ )
|
||||
Courtesy: [Amos Storkey](http://homepages.inf.ed.ac.uk/amos/hough.html) )
|
||||
|
||||
.. image:: images/houghlinesdemo.gif
|
||||
|
||||
|
||||
|
||||
|
||||
This is how hough transform for lines works. It is simple, and may be you can implement it using Numpy on your own. Below is an image which shows the accumulator. Bright spots at some locations denotes they are the parameters of possible lines in the image. (Image courtesy: Wikipedia
|
||||
\<<http://en.wikipedia.org/wiki/Hough_transform>\>_ )
|
||||
|
||||
.. image:: images/houghlines2.jpg
|
||||

|
||||
|
||||
This is how hough transform for lines works. It is simple, and may be you can implement it using
|
||||
Numpy on your own. Below is an image which shows the accumulator. Bright spots at some locations
|
||||
denotes they are the parameters of possible lines in the image. (Image courtesy: [Wikipedia](http://en.wikipedia.org/wiki/Hough_transform))
|
||||
|
||||

|
||||
|
||||
Hough Tranform in OpenCV
|
||||
=========================
|
||||
@@ -112,9 +108,11 @@ Bettinger's home page](http://phdfb1.free.fr/robot/mscthesis/node14.html)
|
||||
|
||||

|
||||
|
||||
OpenCV implementation is based on Robust Detection of Lines Using the Progressive Probabilistic Hough Transform by Matas, J. and Galambos, C. and Kittler, J.V.. The function used is **cv2.HoughLinesP()**. It has two new arguments.
|
||||
- **minLineLength** - Minimum length of line. Line segments shorter than this are rejected.
|
||||
- **maxLineGap** - Maximum allowed gap between line segments to treat them as single line.
|
||||
OpenCV implementation is based on Robust Detection of Lines Using the Progressive Probabilistic
|
||||
Hough Transform by Matas, J. and Galambos, C. and Kittler, J.V.. The function used is
|
||||
**cv2.HoughLinesP()**. It has two new arguments.
|
||||
- **minLineLength** - Minimum length of line. Line segments shorter than this are rejected.
|
||||
- **maxLineGap** - Maximum allowed gap between line segments to treat them as single line.
|
||||
|
||||
Best thing is that, it directly returns the two endpoints of lines. In previous case, you got only
|
||||
the parameters of lines, and you had to find all the points. Here, everything is direct and simple.
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will learn different morphological operations like Erosion, Dilation, Opening, Closing
|
||||
- We will learn different morphological operations like Erosion, Dilation, Opening, Closing
|
||||
etc.
|
||||
- We will see different functions like : **cv2.erode()**, **cv2.dilate()**,
|
||||
**cv2.morphologyEx()** etc.
|
||||
@@ -122,9 +122,9 @@ We manually created a structuring elements in the previous examples with help of
|
||||
rectangular shape. But in some cases, you may need elliptical/circular shaped kernels. So for this
|
||||
purpose, OpenCV has a function, **cv2.getStructuringElement()**. You just pass the shape and size of
|
||||
the kernel, you get the desired kernel.
|
||||
@code{.python}
|
||||
@code{.py}
|
||||
# Rectangular Kernel
|
||||
cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
|
||||
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
|
||||
array([[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
@@ -132,7 +132,7 @@ array([[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1]], dtype=uint8)
|
||||
|
||||
# Elliptical Kernel
|
||||
cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
|
||||
>>> cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
|
||||
array([[0, 0, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
[1, 1, 1, 1, 1],
|
||||
@@ -140,7 +140,7 @@ array([[0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0]], dtype=uint8)
|
||||
|
||||
# Cross-shaped Kernel
|
||||
cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
|
||||
>>> cv2.getStructuringElement(cv2.MORPH_CROSS,(5,5))
|
||||
array([[0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will learn about Image Pyramids
|
||||
- We will learn about Image Pyramids
|
||||
- We will use Image pyramids to create a new fruit, "Orapple"
|
||||
- We will see these functions: **cv2.pyrUp()**, **cv2.pyrDown()**
|
||||
|
||||
|
@@ -5,7 +5,7 @@ Goals
|
||||
-----
|
||||
|
||||
In this chapter, you will learn
|
||||
- To find objects in an image using Template Matching
|
||||
- To find objects in an image using Template Matching
|
||||
- You will see these functions : **cv2.matchTemplate()**, **cv2.minMaxLoc()**
|
||||
|
||||
Theory
|
||||
@@ -24,7 +24,9 @@ is the maximum/minimum value. Take it as the top-left corner of rectangle and ta
|
||||
and height of the rectangle. That rectangle is your region of template.
|
||||
|
||||
@note If you are using cv2.TM_SQDIFF as comparison method, minimum value gives the best match.
|
||||
Template Matching in OpenCV ============================
|
||||
|
||||
Template Matching in OpenCV
|
||||
---------------------------
|
||||
|
||||
Here, as an example, we will search for Messi's face in his photo. So I created a template as below:
|
||||
|
||||
|
@@ -54,7 +54,9 @@ for i in xrange(6):
|
||||
plt.show()
|
||||
@endcode
|
||||
@note To plot multiple images, we have used plt.subplot() function. Please checkout Matplotlib docs
|
||||
for more details. Result is given below :
|
||||
for more details.
|
||||
|
||||
Result is given below :
|
||||
|
||||

|
||||
|
||||
@@ -70,7 +72,7 @@ results for images with varying illumination.
|
||||
It has three ‘special’ input params and only one output argument.
|
||||
|
||||
**Adaptive Method** - It decides how thresholding value is calculated.
|
||||
- cv2.ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area.
|
||||
- cv2.ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area.
|
||||
- cv2.ADAPTIVE_THRESH_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood
|
||||
values where weights are a gaussian window.
|
||||
|
||||
@@ -229,4 +231,3 @@ Exercises
|
||||
---------
|
||||
|
||||
-# There are some optimizations available for Otsu's binarization. You can search and implement it.
|
||||
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this section, we will learn
|
||||
- To find the Fourier Transform of images using OpenCV
|
||||
- To find the Fourier Transform of images using OpenCV
|
||||
- To utilize the FFT functions available in Numpy
|
||||
- Some applications of Fourier Transform
|
||||
- We will see following functions : **cv2.dft()**, **cv2.idft()** etc
|
||||
@@ -134,11 +134,14 @@ plt.subplot(122),plt.imshow(magnitude_spectrum, cmap = 'gray')
|
||||
plt.title('Magnitude Spectrum'), plt.xticks([]), plt.yticks([])
|
||||
plt.show()
|
||||
@endcode
|
||||
|
||||
@note You can also use **cv2.cartToPolar()** which returns both magnitude and phase in a single shot
|
||||
|
||||
So, now we have to do inverse DFT. In previous session, we created a HPF, this time we will see how
|
||||
to remove high frequency contents in the image, ie we apply LPF to image. It actually blurs the
|
||||
image. For this, we create a mask first with high value (1) at low frequencies, ie we pass the LF
|
||||
content, and 0 at HF region.
|
||||
|
||||
@code{.py}
|
||||
rows, cols = img.shape
|
||||
crow,ccol = rows/2 , cols/2
|
||||
@@ -165,7 +168,10 @@ See the result:
|
||||
|
||||
@note As usual, OpenCV functions **cv2.dft()** and **cv2.idft()** are faster than Numpy
|
||||
counterparts. But Numpy functions are more user-friendly. For more details about performance issues,
|
||||
see below section. Performance Optimization of DFT ==================================
|
||||
see below section.
|
||||
|
||||
Performance Optimization of DFT
|
||||
===============================
|
||||
|
||||
Performance of DFT calculation is better for some array size. It is fastest when array size is power
|
||||
of two. The arrays whose size is a product of 2’s, 3’s, and 5’s are also processed quite
|
||||
|
@@ -5,7 +5,7 @@ Goal
|
||||
----
|
||||
|
||||
In this chapter,
|
||||
- We will learn to use marker-based image segmentation using watershed algorithm
|
||||
- We will learn to use marker-based image segmentation using watershed algorithm
|
||||
- We will see: **cv2.watershed()**
|
||||
|
||||
Theory
|
||||
@@ -146,4 +146,3 @@ Exercises
|
||||
|
||||
-# OpenCV samples has an interactive sample on watershed segmentation, watershed.py. Run it, Enjoy
|
||||
it, then learn it.
|
||||
|
||||
|
Reference in New Issue
Block a user