mirror of
https://github.com/opencv/opencv.git
synced 2026-07-30 15:53:03 +04:00
python: 'cv2.' -> 'cv.' via 'import cv2 as cv'
This commit is contained in:
@@ -7,7 +7,7 @@ Goal
|
||||
In this chapter, we will learn about
|
||||
|
||||
- Concept of Canny edge detection
|
||||
- OpenCV functions for that : **cv2.Canny()**
|
||||
- OpenCV functions for that : **cv.Canny()**
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -72,19 +72,19 @@ So what we finally get is strong edges in the image.
|
||||
Canny Edge Detection in OpenCV
|
||||
------------------------------
|
||||
|
||||
OpenCV puts all the above in single function, **cv2.Canny()**. We will see how to use it. First
|
||||
OpenCV puts all the above in single function, **cv.Canny()**. We will see how to use it. First
|
||||
argument is our input image. Second and third arguments are our minVal and maxVal respectively.
|
||||
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.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
edges = cv2.Canny(img,100,200)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
edges = cv.Canny(img,100,200)
|
||||
|
||||
plt.subplot(121),plt.imshow(img,cmap = 'gray')
|
||||
plt.title('Original Image'), plt.xticks([]), plt.yticks([])
|
||||
|
||||
@@ -7,7 +7,7 @@ Goal
|
||||
- In this tutorial, you will learn how to convert images from one color-space to another, like
|
||||
BGR \f$\leftrightarrow\f$ Gray, BGR \f$\leftrightarrow\f$ HSV etc.
|
||||
- In addition to that, we will create an application which extracts a colored object in a video
|
||||
- You will learn following functions : **cv2.cvtColor()**, **cv2.inRange()** etc.
|
||||
- You will learn following functions : **cv.cvtColor()**, **cv.inRange()** etc.
|
||||
|
||||
Changing Color-space
|
||||
--------------------
|
||||
@@ -15,15 +15,15 @@ Changing Color-space
|
||||
There are more than 150 color-space conversion methods available in OpenCV. But we will look into
|
||||
only two which are most widely used ones, BGR \f$\leftrightarrow\f$ Gray and BGR \f$\leftrightarrow\f$ HSV.
|
||||
|
||||
For color conversion, we use the function cv2.cvtColor(input_image, flag) where flag determines the
|
||||
For color conversion, we use the function cv.cvtColor(input_image, flag) where flag determines the
|
||||
type of conversion.
|
||||
|
||||
For BGR \f$\rightarrow\f$ Gray conversion we use the flags cv2.COLOR_BGR2GRAY. Similarly for BGR
|
||||
\f$\rightarrow\f$ HSV, we use the flag cv2.COLOR_BGR2HSV. To get other flags, just run following
|
||||
For BGR \f$\rightarrow\f$ Gray conversion we use the flags cv.COLOR_BGR2GRAY. Similarly for BGR
|
||||
\f$\rightarrow\f$ HSV, we use the flag cv.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_')]
|
||||
>>> import cv2 as cv
|
||||
>>> flags = [i for i in dir(cv) 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].
|
||||
@@ -44,10 +44,10 @@ a blue colored object. So here is the method:
|
||||
|
||||
Below is the code which are commented in detail :
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
cap = cv2.VideoCapture(0)
|
||||
cap = cv.VideoCapture(0)
|
||||
|
||||
while(1):
|
||||
|
||||
@@ -55,26 +55,26 @@ while(1):
|
||||
_, frame = cap.read()
|
||||
|
||||
# Convert BGR to HSV
|
||||
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
|
||||
hsv = cv.cvtColor(frame, cv.COLOR_BGR2HSV)
|
||||
|
||||
# define range of blue color in HSV
|
||||
lower_blue = np.array([110,50,50])
|
||||
upper_blue = np.array([130,255,255])
|
||||
|
||||
# Threshold the HSV image to get only blue colors
|
||||
mask = cv2.inRange(hsv, lower_blue, upper_blue)
|
||||
mask = cv.inRange(hsv, lower_blue, upper_blue)
|
||||
|
||||
# Bitwise-AND mask and original image
|
||||
res = cv2.bitwise_and(frame,frame, mask= mask)
|
||||
res = cv.bitwise_and(frame,frame, mask= mask)
|
||||
|
||||
cv2.imshow('frame',frame)
|
||||
cv2.imshow('mask',mask)
|
||||
cv2.imshow('res',res)
|
||||
k = cv2.waitKey(5) & 0xFF
|
||||
cv.imshow('frame',frame)
|
||||
cv.imshow('mask',mask)
|
||||
cv.imshow('res',res)
|
||||
k = cv.waitKey(5) & 0xFF
|
||||
if k == 27:
|
||||
break
|
||||
|
||||
cv2.destroyAllWindows()
|
||||
cv.destroyAllWindows()
|
||||
@endcode
|
||||
Below image shows tracking of the blue object:
|
||||
|
||||
@@ -90,12 +90,12 @@ How to find HSV values to track?
|
||||
--------------------------------
|
||||
|
||||
This is a common question found in [stackoverflow.com](http://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
|
||||
you can use the same function, cv.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)
|
||||
>>> hsv_green = cv.cvtColor(green,cv.COLOR_BGR2HSV)
|
||||
>>> print( hsv_green )
|
||||
[[[ 60 255 255]]]
|
||||
@endcode
|
||||
|
||||
+32
-32
@@ -16,17 +16,17 @@ Image moments help you to calculate some features like center of mass of the obj
|
||||
object etc. Check out the wikipedia page on [Image
|
||||
Moments](http://en.wikipedia.org/wiki/Image_moment)
|
||||
|
||||
The function **cv2.moments()** gives a dictionary of all moment values calculated. See below:
|
||||
The function **cv.moments()** gives a dictionary of all moment values calculated. See below:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('star.jpg',0)
|
||||
ret,thresh = cv2.threshold(img,127,255,0)
|
||||
im2,contours,hierarchy = cv2.findContours(thresh, 1, 2)
|
||||
img = cv.imread('star.jpg',0)
|
||||
ret,thresh = cv.threshold(img,127,255,0)
|
||||
im2,contours,hierarchy = cv.findContours(thresh, 1, 2)
|
||||
|
||||
cnt = contours[0]
|
||||
M = cv2.moments(cnt)
|
||||
M = cv.moments(cnt)
|
||||
print( M )
|
||||
@endcode
|
||||
From this moments, you can extract useful data like area, centroid etc. Centroid is given by the
|
||||
@@ -40,18 +40,18 @@ cy = int(M['m01']/M['m00'])
|
||||
2. Contour Area
|
||||
---------------
|
||||
|
||||
Contour area is given by the function **cv2.contourArea()** or from moments, **M['m00']**.
|
||||
Contour area is given by the function **cv.contourArea()** or from moments, **M['m00']**.
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
area = cv.contourArea(cnt)
|
||||
@endcode
|
||||
|
||||
3. Contour Perimeter
|
||||
--------------------
|
||||
|
||||
It is also called arc length. It can be found out using **cv2.arcLength()** function. Second
|
||||
It is also called arc length. It can be found out using **cv.arcLength()** function. Second
|
||||
argument specify whether shape is a closed contour (if passed True), or just a curve.
|
||||
@code{.py}
|
||||
perimeter = cv2.arcLength(cnt,True)
|
||||
perimeter = cv.arcLength(cnt,True)
|
||||
@endcode
|
||||
|
||||
4. Contour Approximation
|
||||
@@ -68,8 +68,8 @@ you can use this function to approximate the shape. In this, second argument is
|
||||
which is maximum distance from contour to approximated contour. It is an accuracy parameter. A wise
|
||||
selection of epsilon is needed to get the correct output.
|
||||
@code{.py}
|
||||
epsilon = 0.1*cv2.arcLength(cnt,True)
|
||||
approx = cv2.approxPolyDP(cnt,epsilon,True)
|
||||
epsilon = 0.1*cv.arcLength(cnt,True)
|
||||
approx = cv.approxPolyDP(cnt,epsilon,True)
|
||||
@endcode
|
||||
Below, in second image, green line shows the approximated curve for epsilon = 10% of arc length.
|
||||
Third image shows the same for epsilon = 1% of the arc length. Third argument specifies whether
|
||||
@@ -81,7 +81,7 @@ curve is closed or not.
|
||||
--------------
|
||||
|
||||
Convex Hull will look similar to contour approximation, but it is not (Both may provide same results
|
||||
in some cases). Here, **cv2.convexHull()** function checks a curve for convexity defects and
|
||||
in some cases). Here, **cv.convexHull()** function checks a curve for convexity defects and
|
||||
corrects it. Generally speaking, convex curves are the curves which are always bulged out, or
|
||||
at-least flat. And if it is bulged inside, it is called convexity defects. For example, check the
|
||||
below image of hand. Red line shows the convex hull of hand. The double-sided arrow marks shows the
|
||||
@@ -91,7 +91,7 @@ convexity defects, which are the local maximum deviations of hull from contours.
|
||||
|
||||
There is a little bit things to discuss about it its syntax:
|
||||
@code{.py}
|
||||
hull = cv2.convexHull(points[, hull[, clockwise[, returnPoints]]
|
||||
hull = cv.convexHull(points[, hull[, clockwise[, returnPoints]]
|
||||
@endcode
|
||||
Arguments details:
|
||||
|
||||
@@ -104,7 +104,7 @@ Arguments details:
|
||||
|
||||
So to get a convex hull as in above image, following is sufficient:
|
||||
@code{.py}
|
||||
hull = cv2.convexHull(cnt)
|
||||
hull = cv.convexHull(cnt)
|
||||
@endcode
|
||||
But if you want to find convexity defects, you need to pass returnPoints = False. To understand it,
|
||||
we will take the rectangle image above. First I found its contour as cnt. Now I found its convex
|
||||
@@ -119,10 +119,10 @@ You will see it again when we discuss about convexity defects.
|
||||
6. Checking Convexity
|
||||
---------------------
|
||||
|
||||
There is a function to check if a curve is convex or not, **cv2.isContourConvex()**. It just return
|
||||
There is a function to check if a curve is convex or not, **cv.isContourConvex()**. It just return
|
||||
whether True or False. Not a big deal.
|
||||
@code{.py}
|
||||
k = cv2.isContourConvex(cnt)
|
||||
k = cv.isContourConvex(cnt)
|
||||
@endcode
|
||||
|
||||
7. Bounding Rectangle
|
||||
@@ -133,25 +133,25 @@ There are two types of bounding rectangles.
|
||||
### 7.a. Straight Bounding Rectangle
|
||||
|
||||
It is a straight rectangle, it doesn't consider the rotation of the object. So area of the bounding
|
||||
rectangle won't be minimum. It is found by the function **cv2.boundingRect()**.
|
||||
rectangle won't be minimum. It is found by the function **cv.boundingRect()**.
|
||||
|
||||
Let (x,y) be the top-left coordinate of the rectangle and (w,h) be its width and height.
|
||||
@code{.py}
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,0),2)
|
||||
x,y,w,h = cv.boundingRect(cnt)
|
||||
cv.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
|
||||
used is **cv2.minAreaRect()**. It returns a Box2D structure which contains following detals - (
|
||||
used is **cv.minAreaRect()**. It returns a Box2D structure which contains following detals - (
|
||||
center (x,y), (width, height), angle of rotation ). But to draw this rectangle, we need 4 corners of
|
||||
the rectangle. It is obtained by the function **cv2.boxPoints()**
|
||||
the rectangle. It is obtained by the function **cv.boxPoints()**
|
||||
@code{.py}
|
||||
rect = cv2.minAreaRect(cnt)
|
||||
box = cv2.boxPoints(rect)
|
||||
rect = cv.minAreaRect(cnt)
|
||||
box = cv.boxPoints(rect)
|
||||
box = np.int0(box)
|
||||
cv2.drawContours(img,[box],0,(0,0,255),2)
|
||||
cv.drawContours(img,[box],0,(0,0,255),2)
|
||||
@endcode
|
||||
Both the rectangles are shown in a single image. Green rectangle shows the normal bounding rect. Red
|
||||
rectangle is the rotated rect.
|
||||
@@ -161,13 +161,13 @@ rectangle is the rotated rect.
|
||||
8. Minimum Enclosing Circle
|
||||
---------------------------
|
||||
|
||||
Next we find the circumcircle of an object using the function **cv2.minEnclosingCircle()**. It is a
|
||||
Next we find the circumcircle of an object using the function **cv.minEnclosingCircle()**. It is a
|
||||
circle which completely covers the object with minimum area.
|
||||
@code{.py}
|
||||
(x,y),radius = cv2.minEnclosingCircle(cnt)
|
||||
(x,y),radius = cv.minEnclosingCircle(cnt)
|
||||
center = (int(x),int(y))
|
||||
radius = int(radius)
|
||||
cv2.circle(img,center,radius,(0,255,0),2)
|
||||
cv.circle(img,center,radius,(0,255,0),2)
|
||||
@endcode
|
||||

|
||||
|
||||
@@ -177,8 +177,8 @@ cv2.circle(img,center,radius,(0,255,0),2)
|
||||
Next one is to fit an ellipse to an object. It returns the rotated rectangle in which the ellipse is
|
||||
inscribed.
|
||||
@code{.py}
|
||||
ellipse = cv2.fitEllipse(cnt)
|
||||
cv2.ellipse(img,ellipse,(0,255,0),2)
|
||||
ellipse = cv.fitEllipse(cnt)
|
||||
cv.ellipse(img,ellipse,(0,255,0),2)
|
||||
@endcode
|
||||

|
||||
|
||||
@@ -189,10 +189,10 @@ Similarly we can fit a line to a set of points. Below image contains a set of wh
|
||||
approximate a straight line to it.
|
||||
@code{.py}
|
||||
rows,cols = img.shape[:2]
|
||||
[vx,vy,x,y] = cv2.fitLine(cnt, cv2.DIST_L2,0,0.01,0.01)
|
||||
[vx,vy,x,y] = cv.fitLine(cnt, cv.DIST_L2,0,0.01,0.01)
|
||||
lefty = int((-x*vy/vx) + y)
|
||||
righty = int(((cols-x)*vy/vx)+y)
|
||||
cv2.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
|
||||
cv.line(img,(cols-1,righty),(0,lefty),(0,255,0),2)
|
||||
@endcode
|
||||

|
||||
|
||||
|
||||
+12
-12
@@ -15,7 +15,7 @@ It is the ratio of width to height of bounding rect of the object.
|
||||
|
||||
\f[Aspect \; Ratio = \frac{Width}{Height}\f]
|
||||
@code{.py}
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
x,y,w,h = cv.boundingRect(cnt)
|
||||
aspect_ratio = float(w)/h
|
||||
@endcode
|
||||
|
||||
@@ -26,8 +26,8 @@ Extent is the ratio of contour area to bounding rectangle area.
|
||||
|
||||
\f[Extent = \frac{Object \; Area}{Bounding \; Rectangle \; Area}\f]
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
x,y,w,h = cv2.boundingRect(cnt)
|
||||
area = cv.contourArea(cnt)
|
||||
x,y,w,h = cv.boundingRect(cnt)
|
||||
rect_area = w*h
|
||||
extent = float(area)/rect_area
|
||||
@endcode
|
||||
@@ -39,9 +39,9 @@ Solidity is the ratio of contour area to its convex hull area.
|
||||
|
||||
\f[Solidity = \frac{Contour \; Area}{Convex \; Hull \; Area}\f]
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
hull = cv2.convexHull(cnt)
|
||||
hull_area = cv2.contourArea(hull)
|
||||
area = cv.contourArea(cnt)
|
||||
hull = cv.convexHull(cnt)
|
||||
hull_area = cv.contourArea(hull)
|
||||
solidity = float(area)/hull_area
|
||||
@endcode
|
||||
|
||||
@@ -52,7 +52,7 @@ Equivalent Diameter is the diameter of the circle whose area is same as the cont
|
||||
|
||||
\f[Equivalent \; Diameter = \sqrt{\frac{4 \times Contour \; Area}{\pi}}\f]
|
||||
@code{.py}
|
||||
area = cv2.contourArea(cnt)
|
||||
area = cv.contourArea(cnt)
|
||||
equi_diameter = np.sqrt(4*area/np.pi)
|
||||
@endcode
|
||||
|
||||
@@ -62,7 +62,7 @@ equi_diameter = np.sqrt(4*area/np.pi)
|
||||
Orientation is the angle at which object is directed. Following method also gives the Major Axis and
|
||||
Minor Axis lengths.
|
||||
@code{.py}
|
||||
(x,y),(MA,ma),angle = cv2.fitEllipse(cnt)
|
||||
(x,y),(MA,ma),angle = cv.fitEllipse(cnt)
|
||||
@endcode
|
||||
|
||||
6. Mask and Pixel Points
|
||||
@@ -71,9 +71,9 @@ Minor Axis lengths.
|
||||
In some cases, we may need all the points which comprises that object. It can be done as follows:
|
||||
@code{.py}
|
||||
mask = np.zeros(imgray.shape,np.uint8)
|
||||
cv2.drawContours(mask,[cnt],0,255,-1)
|
||||
cv.drawContours(mask,[cnt],0,255,-1)
|
||||
pixelpoints = np.transpose(np.nonzero(mask))
|
||||
#pixelpoints = cv2.findNonZero(mask)
|
||||
#pixelpoints = cv.findNonZero(mask)
|
||||
@endcode
|
||||
Here, two methods, one using Numpy functions, next one using OpenCV function (last commented line)
|
||||
are given to do the same. Results are also same, but with a slight difference. Numpy gives
|
||||
@@ -85,7 +85,7 @@ basically the answers will be interchanged. Note that, **row = x** and **column
|
||||
|
||||
We can find these parameters using a mask image.
|
||||
@code{.py}
|
||||
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
|
||||
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(imgray,mask = mask)
|
||||
@endcode
|
||||
|
||||
8. Mean Color or Mean Intensity
|
||||
@@ -94,7 +94,7 @@ min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(imgray,mask = mask)
|
||||
Here, we can find the average color of an object. Or it can be average intensity of the object in
|
||||
grayscale mode. We again use the same mask to do it.
|
||||
@code{.py}
|
||||
mean_val = cv2.mean(im,mask = mask)
|
||||
mean_val = cv.mean(im,mask = mask)
|
||||
@endcode
|
||||
|
||||
9. Extreme Points
|
||||
|
||||
+16
-16
@@ -6,7 +6,7 @@ Goal
|
||||
|
||||
- Understand what contours are.
|
||||
- Learn to find contours, draw contours etc
|
||||
- You will see these functions : **cv2.findContours()**, **cv2.drawContours()**
|
||||
- You will see these functions : **cv.findContours()**, **cv.drawContours()**
|
||||
|
||||
What are contours?
|
||||
------------------
|
||||
@@ -24,14 +24,14 @@ detection and recognition.
|
||||
Let's see how to find contours of a binary image:
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
|
||||
im = cv2.imread('test.jpg')
|
||||
imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
|
||||
ret, thresh = cv2.threshold(imgray, 127, 255, 0)
|
||||
im2, contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
||||
im = cv.imread('test.jpg')
|
||||
imgray = cv.cvtColor(im, cv.COLOR_BGR2GRAY)
|
||||
ret, thresh = cv.threshold(imgray, 127, 255, 0)
|
||||
im2, contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
|
||||
@endcode
|
||||
See, there are three arguments in **cv2.findContours()** function, first one is source image, second
|
||||
See, there are three arguments in **cv.findContours()** function, first one is source image, second
|
||||
is contour retrieval mode, third is contour approximation method. And it outputs a modified image, the contours and
|
||||
hierarchy. contours is a Python list of all the contours in the image. Each individual contour is a
|
||||
Numpy array of (x,y) coordinates of boundary points of the object.
|
||||
@@ -42,7 +42,7 @@ the values given to them in code sample will work fine for all images.
|
||||
How to draw the contours?
|
||||
-------------------------
|
||||
|
||||
To draw the contours, cv2.drawContours function is used. It can also be used to draw any shape
|
||||
To draw the contours, cv.drawContours function is used. It can also be used to draw any shape
|
||||
provided you have its boundary points. Its first argument is source image, second argument is the
|
||||
contours which should be passed as a Python list, third argument is index of contours (useful when
|
||||
drawing individual contour. To draw all contours, pass -1) and remaining arguments are color,
|
||||
@@ -50,16 +50,16 @@ thickness etc.
|
||||
|
||||
* To draw all the contours in an image:
|
||||
@code{.py}
|
||||
cv2.drawContours(img, contours, -1, (0,255,0), 3)
|
||||
cv.drawContours(img, contours, -1, (0,255,0), 3)
|
||||
@endcode
|
||||
* To draw an individual contour, say 4th contour:
|
||||
@code{.py}
|
||||
cv2.drawContours(img, contours, 3, (0,255,0), 3)
|
||||
cv.drawContours(img, contours, 3, (0,255,0), 3)
|
||||
@endcode
|
||||
* But most of the time, below method will be useful:
|
||||
@code{.py}
|
||||
cnt = contours[4]
|
||||
cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
|
||||
cv.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.
|
||||
@@ -67,21 +67,21 @@ cv2.drawContours(img, [cnt], 0, (0,255,0), 3)
|
||||
Contour Approximation Method
|
||||
============================
|
||||
|
||||
This is the third argument in cv2.findContours function. What does it denote actually?
|
||||
This is the third argument in cv.findContours function. What does it denote actually?
|
||||
|
||||
Above, we told that contours are the boundaries of a shape with same intensity. It stores the (x,y)
|
||||
coordinates of the boundary of a shape. But does it store all the coordinates ? That is specified by
|
||||
this contour approximation method.
|
||||
|
||||
If you pass cv2.CHAIN_APPROX_NONE, all the boundary points are stored. But actually do we need all
|
||||
If you pass cv.CHAIN_APPROX_NONE, all the boundary points are stored. But actually do we need all
|
||||
the points? For eg, you found the contour of a straight line. Do you need all the points on the line
|
||||
to represent that line? No, we need just two end points of that line. This is what
|
||||
cv2.CHAIN_APPROX_SIMPLE does. It removes all redundant points and compresses the contour, thereby
|
||||
cv.CHAIN_APPROX_SIMPLE does. It removes all redundant points and compresses the contour, thereby
|
||||
saving memory.
|
||||
|
||||
Below image of a rectangle demonstrate this technique. Just draw a circle on all the coordinates in
|
||||
the contour array (drawn in blue color). First image shows points I got with cv2.CHAIN_APPROX_NONE
|
||||
(734 points) and second image shows the one with cv2.CHAIN_APPROX_SIMPLE (only 4 points). See, how
|
||||
the contour array (drawn in blue color). First image shows points I got with cv.CHAIN_APPROX_NONE
|
||||
(734 points) and second image shows the one with cv.CHAIN_APPROX_SIMPLE (only 4 points). See, how
|
||||
much memory it saves!!!
|
||||
|
||||

|
||||
|
||||
+7
-7
@@ -10,9 +10,9 @@ Theory
|
||||
------
|
||||
|
||||
In the last few articles on contours, we have worked with several functions related to contours
|
||||
provided by OpenCV. But when we found the contours in image using **cv2.findContours()** function,
|
||||
we have passed an argument, **Contour Retrieval Mode**. We usually passed **cv2.RETR_LIST** or
|
||||
**cv2.RETR_TREE** and it worked nice. But what does it actually mean ?
|
||||
provided by OpenCV. But when we found the contours in image using **cv.findContours()** function,
|
||||
we have passed an argument, **Contour Retrieval Mode**. We usually passed **cv.RETR_LIST** or
|
||||
**cv.RETR_TREE** and it worked nice. But what does it actually mean ?
|
||||
|
||||
Also, in the output, we got three arrays, first is the image, second is our contours, and one more
|
||||
output which we named as **hierarchy** (Please checkout the codes in previous articles). But we
|
||||
@@ -23,7 +23,7 @@ That is what we are going to deal in this article.
|
||||
|
||||
### What is Hierarchy?
|
||||
|
||||
Normally we use the **cv2.findContours()** function to detect objects in an image, right ? Sometimes
|
||||
Normally we use the **cv.findContours()** function to detect objects in an image, right ? Sometimes
|
||||
objects are in different locations. But in some cases, some shapes are inside other shapes. Just
|
||||
like nested figures. In this case, we call outer one as **parent** and inner one as **child**. This
|
||||
way, contours in an image has some relationship to each other. And we can specify how one contour is
|
||||
@@ -82,8 +82,8 @@ 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?
|
||||
in OpenCV with the help of same image given above. ie what do flags like cv.RETR_LIST,
|
||||
cv.RETR_TREE, cv.RETR_CCOMP, cv.RETR_EXTERNAL etc mean?
|
||||
|
||||
Contour Retrieval Mode
|
||||
----------------------
|
||||
@@ -185,7 +185,7 @@ array([[[ 3, -1, 1, -1],
|
||||
And this is the final guy, Mr.Perfect. It retrieves all the contours and creates a full family
|
||||
hierarchy list. **It even tells, who is the grandpa, father, son, grandson and even beyond... :)**.
|
||||
|
||||
For examle, I took above image, rewrite the code for cv2.RETR_TREE, reorder the contours as per the
|
||||
For examle, I took above image, rewrite the code for cv.RETR_TREE, reorder the contours as per the
|
||||
result given by OpenCV and analyze it. Again, red letters give the contour number and green letters
|
||||
give the hierarchy order.
|
||||
|
||||
|
||||
+28
-28
@@ -17,11 +17,11 @@ Theory and Code
|
||||
We saw what is convex hull in second chapter about contours. Any deviation of the object from this
|
||||
hull can be considered as convexity defect.
|
||||
|
||||
OpenCV comes with a ready-made function to find this, **cv2.convexityDefects()**. A basic function
|
||||
OpenCV comes with a ready-made function to find this, **cv.convexityDefects()**. A basic function
|
||||
call would look like below:
|
||||
@code{.py}
|
||||
hull = cv2.convexHull(cnt,returnPoints = False)
|
||||
defects = cv2.convexityDefects(cnt,hull)
|
||||
hull = cv.convexHull(cnt,returnPoints = False)
|
||||
defects = cv.convexityDefects(cnt,hull)
|
||||
@endcode
|
||||
|
||||
@note Remember we have to pass returnPoints = False while finding convex hull, in order to find
|
||||
@@ -33,29 +33,29 @@ line joining start point and end point, then draw a circle at the farthest point
|
||||
three values returned are indices of cnt. So we have to bring those values from cnt.
|
||||
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
img = cv2.imread('star.jpg')
|
||||
img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
|
||||
ret,thresh = cv2.threshold(img_gray, 127, 255,0)
|
||||
im2,contours,hierarchy = cv2.findContours(thresh,2,1)
|
||||
img = cv.imread('star.jpg')
|
||||
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
|
||||
ret,thresh = cv.threshold(img_gray, 127, 255,0)
|
||||
im2,contours,hierarchy = cv.findContours(thresh,2,1)
|
||||
cnt = contours[0]
|
||||
|
||||
hull = cv2.convexHull(cnt,returnPoints = False)
|
||||
defects = cv2.convexityDefects(cnt,hull)
|
||||
hull = cv.convexHull(cnt,returnPoints = False)
|
||||
defects = cv.convexityDefects(cnt,hull)
|
||||
|
||||
for i in range(defects.shape[0]):
|
||||
s,e,f,d = defects[i,0]
|
||||
start = tuple(cnt[s][0])
|
||||
end = tuple(cnt[e][0])
|
||||
far = tuple(cnt[f][0])
|
||||
cv2.line(img,start,end,[0,255,0],2)
|
||||
cv2.circle(img,far,5,[0,0,255],-1)
|
||||
cv.line(img,start,end,[0,255,0],2)
|
||||
cv.circle(img,far,5,[0,0,255],-1)
|
||||
|
||||
cv2.imshow('img',img)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
cv.imshow('img',img)
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
@endcode
|
||||
And see the result:
|
||||
|
||||
@@ -69,7 +69,7 @@ if point is on the contour.
|
||||
|
||||
For example, we can check the point (50,50) as follows:
|
||||
@code{.py}
|
||||
dist = cv2.pointPolygonTest(cnt,(50,50),True)
|
||||
dist = cv.pointPolygonTest(cnt,(50,50),True)
|
||||
@endcode
|
||||
In the function, third argument is measureDist. If it is True, it finds the signed distance. If
|
||||
False, it finds whether the point is inside or outside or on the contour (it returns +1, -1, 0
|
||||
@@ -80,25 +80,25 @@ 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
|
||||
OpenCV comes with a function **cv.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.
|
||||
It is calculated based on the hu-moment values. Different measurement methods are explained in the
|
||||
docs.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
img1 = cv2.imread('star.jpg',0)
|
||||
img2 = cv2.imread('star2.jpg',0)
|
||||
img1 = cv.imread('star.jpg',0)
|
||||
img2 = cv.imread('star2.jpg',0)
|
||||
|
||||
ret, thresh = cv2.threshold(img1, 127, 255,0)
|
||||
ret, thresh2 = cv2.threshold(img2, 127, 255,0)
|
||||
im2,contours,hierarchy = cv2.findContours(thresh,2,1)
|
||||
ret, thresh = cv.threshold(img1, 127, 255,0)
|
||||
ret, thresh2 = cv.threshold(img2, 127, 255,0)
|
||||
im2,contours,hierarchy = cv.findContours(thresh,2,1)
|
||||
cnt1 = contours[0]
|
||||
im2,contours,hierarchy = cv2.findContours(thresh2,2,1)
|
||||
im2,contours,hierarchy = cv.findContours(thresh2,2,1)
|
||||
cnt2 = contours[0]
|
||||
|
||||
ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
|
||||
ret = cv.matchShapes(cnt1,cnt2,1,0.0)
|
||||
print( ret )
|
||||
@endcode
|
||||
I tried matching shapes with different shapes given below:
|
||||
@@ -115,7 +115,7 @@ 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.
|
||||
can be found using **cv.HuMoments()** function.
|
||||
|
||||
Additional Resources
|
||||
====================
|
||||
@@ -123,10 +123,10 @@ Additional Resources
|
||||
Exercises
|
||||
---------
|
||||
|
||||
-# Check the documentation for **cv2.pointPolygonTest()**, you can find a nice image in Red and
|
||||
-# Check the documentation for **cv.pointPolygonTest()**, you can find a nice image in Red and
|
||||
Blue color. It represents the distance from all pixels to the white curve on it. All pixels
|
||||
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.
|
||||
-# Compare images of digits or letters using **cv2.matchShapes()**. ( That would be a simple step
|
||||
-# Compare images of digits or letters using **cv.matchShapes()**. ( That would be a simple step
|
||||
towards OCR )
|
||||
|
||||
@@ -15,7 +15,7 @@ As in one-dimensional signals, images also can be filtered with various low-pass
|
||||
high-pass filters(HPF) etc. LPF helps in removing noises, blurring the images etc. HPF filters helps
|
||||
in finding edges in the images.
|
||||
|
||||
OpenCV provides a function **cv2.filter2D()** to convolve a kernel with an image. As an example, we
|
||||
OpenCV provides a function **cv.filter2D()** to convolve a kernel with an image. As an example, we
|
||||
will try an averaging filter on an image. A 5x5 averaging filter kernel will look like below:
|
||||
|
||||
\f[K = \frac{1}{25} \begin{bmatrix} 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \\ 1 & 1 & 1 & 1 & 1 \end{bmatrix}\f]
|
||||
@@ -24,14 +24,14 @@ Operation is like this: keep this kernel above a pixel, add all the 25 pixels be
|
||||
take its average and replace the central pixel with the new average value. It continues this
|
||||
operation for all the pixels in the image. Try this code and check the result:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('opencv_logo.png')
|
||||
img = cv.imread('opencv_logo.png')
|
||||
|
||||
kernel = np.ones((5,5),np.float32)/25
|
||||
dst = cv2.filter2D(img,-1,kernel)
|
||||
dst = cv.filter2D(img,-1,kernel)
|
||||
|
||||
plt.subplot(121),plt.imshow(img),plt.title('Original')
|
||||
plt.xticks([]), plt.yticks([])
|
||||
@@ -55,23 +55,23 @@ blur the edges too). OpenCV provides mainly four types of blurring techniques.
|
||||
|
||||
This is done by convolving image with a normalized box filter. It simply takes the average of all
|
||||
the pixels under kernel area and replace the central element. This is done by the function
|
||||
**cv2.blur()** or **cv2.boxFilter()**. Check the docs for more details about the kernel. We should
|
||||
**cv.blur()** or **cv.boxFilter()**. Check the docs for more details about the kernel. We should
|
||||
specify the width and height of kernel. A 3x3 normalized box filter would look like below:
|
||||
|
||||
\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
|
||||
@note If you don't want to use normalized box filter, use **cv.boxFilter()**. Pass an argument
|
||||
normalize=False to the function.
|
||||
|
||||
Check a sample demo below with a kernel of 5x5 size:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('opencv-logo-white.png')
|
||||
img = cv.imread('opencv-logo-white.png')
|
||||
|
||||
blur = cv2.blur(img,(5,5))
|
||||
blur = cv.blur(img,(5,5))
|
||||
|
||||
plt.subplot(121),plt.imshow(img),plt.title('Original')
|
||||
plt.xticks([]), plt.yticks([])
|
||||
@@ -86,17 +86,17 @@ Result:
|
||||
### 2. Gaussian Blurring
|
||||
|
||||
In this, instead of box filter, gaussian kernel is used. It is done with the function,
|
||||
**cv2.GaussianBlur()**. We should specify the width and height of kernel which should be positive
|
||||
**cv.GaussianBlur()**. We should specify the width and height of kernel which should be positive
|
||||
and odd. We also should specify the standard deviation in X and Y direction, sigmaX and sigmaY
|
||||
respectively. If only sigmaX is specified, sigmaY is taken as same as sigmaX. If both are given as
|
||||
zeros, they are calculated from kernel size. Gaussian blurring is highly effective in removing
|
||||
gaussian noise from the image.
|
||||
|
||||
If you want, you can create a Gaussian kernel with the function, **cv2.getGaussianKernel()**.
|
||||
If you want, you can create a Gaussian kernel with the function, **cv.getGaussianKernel()**.
|
||||
|
||||
The above code can be modified for Gaussian blurring:
|
||||
@code{.py}
|
||||
blur = cv2.GaussianBlur(img,(5,5),0)
|
||||
blur = cv.GaussianBlur(img,(5,5),0)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -104,7 +104,7 @@ Result:
|
||||
|
||||
### 3. Median Blurring
|
||||
|
||||
Here, the function **cv2.medianBlur()** takes median of all the pixels under kernel area and central
|
||||
Here, the function **cv.medianBlur()** takes median of all the pixels under kernel area and central
|
||||
element is replaced with this median value. This is highly effective against salt-and-pepper noise
|
||||
in the images. Interesting thing is that, in the above filters, central element is a newly
|
||||
calculated value which may be a pixel value in the image or a new value. But in median blurring,
|
||||
@@ -113,7 +113,7 @@ effectively. Its kernel size should be a positive odd integer.
|
||||
|
||||
In this demo, I added a 50% noise to our original image and applied median blur. Check the result:
|
||||
@code{.py}
|
||||
median = cv2.medianBlur(img,5)
|
||||
median = cv.medianBlur(img,5)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -121,7 +121,7 @@ Result:
|
||||
|
||||
### 4. Bilateral Filtering
|
||||
|
||||
**cv2.bilateralFilter()** is highly effective in noise removal while keeping edges sharp. But the
|
||||
**cv.bilateralFilter()** is highly effective in noise removal while keeping edges sharp. But the
|
||||
operation is slower compared to other filters. We already saw that gaussian filter takes the a
|
||||
neighbourhood around the pixel and find its gaussian weighted average. This gaussian filter is a
|
||||
function of space alone, that is, nearby pixels are considered while filtering. It doesn't consider
|
||||
@@ -136,7 +136,7 @@ pixels at edges will have large intensity variation.
|
||||
|
||||
Below samples shows use bilateral filter (For details on arguments, visit docs).
|
||||
@code{.py}
|
||||
blur = cv2.bilateralFilter(img,9,75,75)
|
||||
blur = cv.bilateralFilter(img,9,75,75)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
|
||||
+33
-33
@@ -6,35 +6,35 @@ Goals
|
||||
|
||||
- Learn to apply different geometric transformation to images like translation, rotation, affine
|
||||
transformation etc.
|
||||
- You will see these functions: **cv2.getPerspectiveTransform**
|
||||
- You will see these functions: **cv.getPerspectiveTransform**
|
||||
|
||||
Transformations
|
||||
---------------
|
||||
|
||||
OpenCV provides two transformation functions, **cv2.warpAffine** and **cv2.warpPerspective**, with
|
||||
which you can have all kinds of transformations. **cv2.warpAffine** takes a 2x3 transformation
|
||||
matrix while **cv2.warpPerspective** takes a 3x3 transformation matrix as input.
|
||||
OpenCV provides two transformation functions, **cv.warpAffine** and **cv.warpPerspective**, with
|
||||
which you can have all kinds of transformations. **cv.warpAffine** takes a 2x3 transformation
|
||||
matrix while **cv.warpPerspective** takes a 3x3 transformation matrix as input.
|
||||
|
||||
### Scaling
|
||||
|
||||
Scaling is just resizing of the image. OpenCV comes with a function **cv2.resize()** for this
|
||||
Scaling is just resizing of the image. OpenCV comes with a function **cv.resize()** for this
|
||||
purpose. The size of the image can be specified manually, or you can specify the scaling factor.
|
||||
Different interpolation methods are used. Preferable interpolation methods are **cv2.INTER_AREA**
|
||||
for shrinking and **cv2.INTER_CUBIC** (slow) & **cv2.INTER_LINEAR** for zooming. By default,
|
||||
interpolation method used is **cv2.INTER_LINEAR** for all resizing purposes. You can resize an
|
||||
Different interpolation methods are used. Preferable interpolation methods are **cv.INTER_AREA**
|
||||
for shrinking and **cv.INTER_CUBIC** (slow) & **cv.INTER_LINEAR** for zooming. By default,
|
||||
interpolation method used is **cv.INTER_LINEAR** for all resizing purposes. You can resize an
|
||||
input image either of following methods:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('messi5.jpg')
|
||||
img = cv.imread('messi5.jpg')
|
||||
|
||||
res = cv2.resize(img,None,fx=2, fy=2, interpolation = cv2.INTER_CUBIC)
|
||||
res = cv.resize(img,None,fx=2, fy=2, interpolation = cv.INTER_CUBIC)
|
||||
|
||||
#OR
|
||||
|
||||
height, width = img.shape[:2]
|
||||
res = cv2.resize(img,(2*width, 2*height), interpolation = cv2.INTER_CUBIC)
|
||||
res = cv.resize(img,(2*width, 2*height), interpolation = cv.INTER_CUBIC)
|
||||
@endcode
|
||||
### Translation
|
||||
|
||||
@@ -43,25 +43,25 @@ be \f$(t_x,t_y)\f$, you can create the transformation matrix \f$\textbf{M}\f$ as
|
||||
|
||||
\f[M = \begin{bmatrix} 1 & 0 & t_x \\ 0 & 1 & t_y \end{bmatrix}\f]
|
||||
|
||||
You can take make it into a Numpy array of type np.float32 and pass it into **cv2.warpAffine()**
|
||||
You can take make it into a Numpy array of type np.float32 and pass it into **cv.warpAffine()**
|
||||
function. See below example for a shift of (100,50):
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
rows,cols = img.shape
|
||||
|
||||
M = np.float32([[1,0,100],[0,1,50]])
|
||||
dst = cv2.warpAffine(img,M,(cols,rows))
|
||||
dst = cv.warpAffine(img,M,(cols,rows))
|
||||
|
||||
cv2.imshow('img',dst)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
cv.imshow('img',dst)
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
@endcode
|
||||
**warning**
|
||||
|
||||
Third argument of the **cv2.warpAffine()** function is the size of the output image, which should
|
||||
Third argument of the **cv.warpAffine()** function is the size of the output image, which should
|
||||
be in the form of **(width, height)**. Remember width = number of columns, and height = number of
|
||||
rows.
|
||||
|
||||
@@ -84,14 +84,14 @@ where:
|
||||
|
||||
\f[\begin{array}{l} \alpha = scale \cdot \cos \theta , \\ \beta = scale \cdot \sin \theta \end{array}\f]
|
||||
|
||||
To find this transformation matrix, OpenCV provides a function, **cv2.getRotationMatrix2D**. Check
|
||||
To find this transformation matrix, OpenCV provides a function, **cv.getRotationMatrix2D**. Check
|
||||
below example which rotates the image by 90 degree with respect to center without any scaling.
|
||||
@code{.py}
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
rows,cols = img.shape
|
||||
|
||||
M = cv2.getRotationMatrix2D((cols/2,rows/2),90,1)
|
||||
dst = cv2.warpAffine(img,M,(cols,rows))
|
||||
M = cv.getRotationMatrix2D((cols/2,rows/2),90,1)
|
||||
dst = cv.warpAffine(img,M,(cols,rows))
|
||||
@endcode
|
||||
See the result:
|
||||
|
||||
@@ -101,20 +101,20 @@ See the result:
|
||||
|
||||
In affine transformation, all parallel lines in the original image will still be parallel in the
|
||||
output image. To find the transformation matrix, we need three points from input image and their
|
||||
corresponding locations in output image. Then **cv2.getAffineTransform** will create a 2x3 matrix
|
||||
which is to be passed to **cv2.warpAffine**.
|
||||
corresponding locations in output image. Then **cv.getAffineTransform** will create a 2x3 matrix
|
||||
which is to be passed to **cv.warpAffine**.
|
||||
|
||||
Check below example, and also look at the points I selected (which are marked in Green color):
|
||||
@code{.py}
|
||||
img = cv2.imread('drawing.png')
|
||||
img = cv.imread('drawing.png')
|
||||
rows,cols,ch = img.shape
|
||||
|
||||
pts1 = np.float32([[50,50],[200,50],[50,200]])
|
||||
pts2 = np.float32([[10,100],[200,50],[100,250]])
|
||||
|
||||
M = cv2.getAffineTransform(pts1,pts2)
|
||||
M = cv.getAffineTransform(pts1,pts2)
|
||||
|
||||
dst = cv2.warpAffine(img,M,(cols,rows))
|
||||
dst = cv.warpAffine(img,M,(cols,rows))
|
||||
|
||||
plt.subplot(121),plt.imshow(img),plt.title('Input')
|
||||
plt.subplot(122),plt.imshow(dst),plt.title('Output')
|
||||
@@ -130,20 +130,20 @@ For perspective transformation, you need a 3x3 transformation matrix. Straight l
|
||||
straight even after the transformation. To find this transformation matrix, you need 4 points on the
|
||||
input image and corresponding points on the output image. Among these 4 points, 3 of them should not
|
||||
be collinear. Then transformation matrix can be found by the function
|
||||
**cv2.getPerspectiveTransform**. Then apply **cv2.warpPerspective** with this 3x3 transformation
|
||||
**cv.getPerspectiveTransform**. Then apply **cv.warpPerspective** with this 3x3 transformation
|
||||
matrix.
|
||||
|
||||
See the code below:
|
||||
@code{.py}
|
||||
img = cv2.imread('sudoku.png')
|
||||
img = cv.imread('sudoku.png')
|
||||
rows,cols,ch = img.shape
|
||||
|
||||
pts1 = np.float32([[56,65],[368,52],[28,387],[389,390]])
|
||||
pts2 = np.float32([[0,0],[300,0],[0,300],[300,300]])
|
||||
|
||||
M = cv2.getPerspectiveTransform(pts1,pts2)
|
||||
M = cv.getPerspectiveTransform(pts1,pts2)
|
||||
|
||||
dst = cv2.warpPerspective(img,M,(300,300))
|
||||
dst = cv.warpPerspective(img,M,(300,300))
|
||||
|
||||
plt.subplot(121),plt.imshow(img),plt.title('Input')
|
||||
plt.subplot(122),plt.imshow(dst),plt.title('Output')
|
||||
|
||||
@@ -64,24 +64,24 @@ It is illustrated in below image (Image Courtesy: <http://www.cs.ru.ac.za/resear
|
||||
Demo
|
||||
----
|
||||
|
||||
Now we go for grabcut algorithm with OpenCV. OpenCV has the function, **cv2.grabCut()** for this. We
|
||||
Now we go for grabcut algorithm with OpenCV. OpenCV has the function, **cv.grabCut()** for this. We
|
||||
will see its arguments first:
|
||||
|
||||
- *img* - Input image
|
||||
- *mask* - It is a mask image where we specify which areas are background, foreground or
|
||||
probable background/foreground etc. It is done by the following flags, **cv2.GC_BGD,
|
||||
cv2.GC_FGD, cv2.GC_PR_BGD, cv2.GC_PR_FGD**, or simply pass 0,1,2,3 to image.
|
||||
probable background/foreground etc. It is done by the following flags, **cv.GC_BGD,
|
||||
cv.GC_FGD, cv.GC_PR_BGD, cv.GC_PR_FGD**, or simply pass 0,1,2,3 to image.
|
||||
- *rect* - It is the coordinates of a rectangle which includes the foreground object in the
|
||||
format (x,y,w,h)
|
||||
- *bdgModel*, *fgdModel* - These are arrays used by the algorithm internally. You just create
|
||||
two np.float64 type zero arrays of size (1,65).
|
||||
- *iterCount* - Number of iterations the algorithm should run.
|
||||
- *mode* - It should be **cv2.GC_INIT_WITH_RECT** or **cv2.GC_INIT_WITH_MASK** or combined
|
||||
- *mode* - It should be **cv.GC_INIT_WITH_RECT** or **cv.GC_INIT_WITH_MASK** or combined
|
||||
which decides whether we are drawing rectangle or final touchup strokes.
|
||||
|
||||
First let's see with rectangular mode. We load the image, create a similar mask image. We create
|
||||
*fgdModel* and *bgdModel*. We give the rectangle parameters. It's all straight-forward. Let the
|
||||
algorithm run for 5 iterations. Mode should be *cv2.GC_INIT_WITH_RECT* since we are using
|
||||
algorithm run for 5 iterations. Mode should be *cv.GC_INIT_WITH_RECT* since we are using
|
||||
rectangle. Then run the grabcut. It modifies the mask image. In the new mask image, pixels will be
|
||||
marked with four flags denoting background/foreground as specified above. So we modify the mask such
|
||||
that all 0-pixels and 2-pixels are put to 0 (ie background) and all 1-pixels and 3-pixels are put to
|
||||
@@ -89,17 +89,17 @@ that all 0-pixels and 2-pixels are put to 0 (ie background) and all 1-pixels and
|
||||
segmented image.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('messi5.jpg')
|
||||
img = cv.imread('messi5.jpg')
|
||||
mask = np.zeros(img.shape[:2],np.uint8)
|
||||
|
||||
bgdModel = np.zeros((1,65),np.float64)
|
||||
fgdModel = np.zeros((1,65),np.float64)
|
||||
|
||||
rect = (50,50,450,290)
|
||||
cv2.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_RECT)
|
||||
cv.grabCut(img,mask,rect,bgdModel,fgdModel,5,cv.GC_INIT_WITH_RECT)
|
||||
|
||||
mask2 = np.where((mask==2)|(mask==0),0,1).astype('uint8')
|
||||
img = img*mask2[:,:,np.newaxis]
|
||||
@@ -122,14 +122,14 @@ remaining background with gray. Then loaded that mask image in OpenCV, edited or
|
||||
got with corresponding values in newly added mask image. Check the code below:*
|
||||
@code{.py}
|
||||
# newmask is the mask image I manually labelled
|
||||
newmask = cv2.imread('newmask.png',0)
|
||||
newmask = cv.imread('newmask.png',0)
|
||||
|
||||
# whereever it is marked white (sure foreground), change mask=1
|
||||
# whereever it is marked black (sure background), change mask=0
|
||||
mask[newmask == 0] = 0
|
||||
mask[newmask == 255] = 1
|
||||
|
||||
mask, bgdModel, fgdModel = cv2.grabCut(img,mask,None,bgdModel,fgdModel,5,cv2.GC_INIT_WITH_MASK)
|
||||
mask, bgdModel, fgdModel = cv.grabCut(img,mask,None,bgdModel,fgdModel,5,cv.GC_INIT_WITH_MASK)
|
||||
|
||||
mask = np.where((mask==2)|(mask==0),0,1).astype('uint8')
|
||||
img = img*mask[:,:,np.newaxis]
|
||||
|
||||
@@ -7,7 +7,7 @@ Goal
|
||||
In this chapter, we will learn to:
|
||||
|
||||
- Find Image gradients, edges etc
|
||||
- We will see following functions : **cv2.Sobel()**, **cv2.Scharr()**, **cv2.Laplacian()** etc
|
||||
- We will see following functions : **cv.Sobel()**, **cv.Scharr()**, **cv.Laplacian()** etc
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -38,15 +38,15 @@ Code
|
||||
Below code shows all operators in a single diagram. All kernels are of 5x5 size. Depth of output
|
||||
image is passed -1 to get the result in np.uint8 type.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('dave.jpg',0)
|
||||
img = cv.imread('dave.jpg',0)
|
||||
|
||||
laplacian = cv2.Laplacian(img,cv2.CV_64F)
|
||||
sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
|
||||
sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5)
|
||||
laplacian = cv.Laplacian(img,cv.CV_64F)
|
||||
sobelx = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
|
||||
sobely = cv.Sobel(img,cv.CV_64F,0,1,ksize=5)
|
||||
|
||||
plt.subplot(2,2,1),plt.imshow(img,cmap = 'gray')
|
||||
plt.title('Original'), plt.xticks([]), plt.yticks([])
|
||||
@@ -66,26 +66,26 @@ Result:
|
||||
One Important Matter!
|
||||
---------------------
|
||||
|
||||
In our last example, output datatype is cv2.CV_8U or np.uint8. But there is a slight problem with
|
||||
In our last example, output datatype is cv.CV_8U or np.uint8. But there is a slight problem with
|
||||
that. Black-to-White transition is taken as Positive slope (it has a positive value) while
|
||||
White-to-Black transition is taken as a Negative slope (It has negative value). So when you convert
|
||||
data to np.uint8, all negative slopes are made zero. In simple words, you miss that edge.
|
||||
|
||||
If you want to detect both edges, better option is to keep the output datatype to some higher forms,
|
||||
like cv2.CV_16S, cv2.CV_64F etc, take its absolute value and then convert back to cv2.CV_8U.
|
||||
like cv.CV_16S, cv.CV_64F etc, take its absolute value and then convert back to cv.CV_8U.
|
||||
Below code demonstrates this procedure for a horizontal Sobel filter and difference in results.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('box.png',0)
|
||||
img = cv.imread('box.png',0)
|
||||
|
||||
# Output dtype = cv2.CV_8U
|
||||
sobelx8u = cv2.Sobel(img,cv2.CV_8U,1,0,ksize=5)
|
||||
# Output dtype = cv.CV_8U
|
||||
sobelx8u = cv.Sobel(img,cv.CV_8U,1,0,ksize=5)
|
||||
|
||||
# Output dtype = cv2.CV_64F. Then take its absolute and convert to cv2.CV_8U
|
||||
sobelx64f = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5)
|
||||
# Output dtype = cv.CV_64F. Then take its absolute and convert to cv.CV_8U
|
||||
sobelx64f = cv.Sobel(img,cv.CV_64F,1,0,ksize=5)
|
||||
abs_sobel64f = np.absolute(sobelx64f)
|
||||
sobel_8u = np.uint8(abs_sobel64f)
|
||||
|
||||
|
||||
+14
-14
@@ -23,7 +23,7 @@ will be useful in understanding further topics like Histogram Back-Projection.
|
||||
2D Histogram in OpenCV
|
||||
----------------------
|
||||
|
||||
It is quite simple and calculated using the same function, **cv2.calcHist()**. For color histograms,
|
||||
It is quite simple and calculated using the same function, **cv.calcHist()**. For color histograms,
|
||||
we need to convert the image from BGR to HSV. (Remember, for 1D histogram, we converted from BGR to
|
||||
Grayscale). For 2D histograms, its parameters will be modified as follows:
|
||||
|
||||
@@ -34,13 +34,13 @@ Grayscale). For 2D histograms, its parameters will be modified as follows:
|
||||
|
||||
Now check the code below:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('home.jpg')
|
||||
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
|
||||
img = cv.imread('home.jpg')
|
||||
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
|
||||
|
||||
hist = cv2.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
|
||||
hist = cv.calcHist([hsv], [0, 1], None, [180, 256], [0, 180, 0, 256])
|
||||
@endcode
|
||||
That's it.
|
||||
|
||||
@@ -50,12 +50,12 @@ That's it.
|
||||
Numpy also provides a specific function for this : **np.histogram2d()**. (Remember, for 1D histogram
|
||||
we used **np.histogram()** ).
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('home.jpg')
|
||||
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
|
||||
img = cv.imread('home.jpg')
|
||||
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
|
||||
|
||||
hist, xbins, ybins = np.histogram2d(h.ravel(),s.ravel(),[180,256],[[0,180],[0,256]])
|
||||
@endcode
|
||||
@@ -67,10 +67,10 @@ Now we can check how to plot this color histogram.
|
||||
Plotting 2D Histograms
|
||||
----------------------
|
||||
|
||||
### Method - 1 : Using cv2.imshow()
|
||||
### Method - 1 : Using cv.imshow()
|
||||
|
||||
The result we get is a two dimensional array of size 180x256. So we can show them as we do normally,
|
||||
using cv2.imshow() function. It will be a grayscale image and it won't give much idea what colors
|
||||
using cv.imshow() function. It will be a grayscale image and it won't give much idea what colors
|
||||
are there, unless you know the Hue values of different colors.
|
||||
|
||||
### Method - 2 : Using Matplotlib
|
||||
@@ -84,13 +84,13 @@ I prefer this method. It is simple and better.
|
||||
|
||||
Consider code:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('home.jpg')
|
||||
hsv = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
|
||||
hist = cv2.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
img = cv.imread('home.jpg')
|
||||
hsv = cv.cvtColor(img,cv.COLOR_BGR2HSV)
|
||||
hist = cv.calcHist( [hsv], [0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
|
||||
plt.imshow(hist,interpolation = 'nearest')
|
||||
plt.show()
|
||||
|
||||
+28
-29
@@ -33,82 +33,81 @@ Algorithm in Numpy
|
||||
-# First we need to calculate the color histogram of both the object we need to find (let it be
|
||||
'M') and the image where we are going to search (let it be 'I').
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
import cv2 as cvfrom matplotlib import pyplot as plt
|
||||
|
||||
#roi is the object or region of object we need to find
|
||||
roi = cv2.imread('rose_red.png')
|
||||
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
|
||||
roi = cv.imread('rose_red.png')
|
||||
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
|
||||
|
||||
#target is the image we search in
|
||||
target = cv2.imread('rose.png')
|
||||
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
|
||||
target = cv.imread('rose.png')
|
||||
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
|
||||
|
||||
# Find the histograms using calcHist. Can be done with np.histogram2d also
|
||||
M = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
I = cv2.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
M = cv.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
I = cv.calcHist([hsvt],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
@endcode
|
||||
2. Find the ratio \f$R = \frac{M}{I}\f$. Then backproject R, ie use R as palette and create a new image
|
||||
with every pixel as its corresponding probability of being target. ie B(x,y) = R[h(x,y),s(x,y)]
|
||||
where h is hue and s is saturation of the pixel at (x,y). After that apply the condition
|
||||
\f$B(x,y) = min[B(x,y), 1]\f$.
|
||||
@code{.py}
|
||||
h,s,v = cv2.split(hsvt)
|
||||
h,s,v = cv.split(hsvt)
|
||||
B = R[h.ravel(),s.ravel()]
|
||||
B = np.minimum(B,1)
|
||||
B = B.reshape(hsvt.shape[:2])
|
||||
@endcode
|
||||
3. Now apply a convolution with a circular disc, \f$B = D \ast B\f$, where D is the disc kernel.
|
||||
@code{.py}
|
||||
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
|
||||
cv2.filter2D(B,-1,disc,B)
|
||||
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
|
||||
cv.filter2D(B,-1,disc,B)
|
||||
B = np.uint8(B)
|
||||
cv2.normalize(B,B,0,255,cv2.NORM_MINMAX)
|
||||
cv.normalize(B,B,0,255,cv.NORM_MINMAX)
|
||||
@endcode
|
||||
4. Now the location of maximum intensity gives us the location of object. If we are expecting a
|
||||
region in the image, thresholding for a suitable value gives a nice result.
|
||||
@code{.py}
|
||||
ret,thresh = cv2.threshold(B,50,255,0)
|
||||
ret,thresh = cv.threshold(B,50,255,0)
|
||||
@endcode
|
||||
That's it !!
|
||||
|
||||
Backprojection in OpenCV
|
||||
------------------------
|
||||
|
||||
OpenCV provides an inbuilt function **cv2.calcBackProject()**. Its parameters are almost same as the
|
||||
**cv2.calcHist()** function. One of its parameter is histogram which is histogram of the object and
|
||||
OpenCV provides an inbuilt function **cv.calcBackProject()**. Its parameters are almost same as the
|
||||
**cv.calcHist()** function. One of its parameter is histogram which is histogram of the object and
|
||||
we have to find it. Also, the object histogram should be normalized before passing on to the
|
||||
backproject function. It returns the probability image. Then we convolve the image with a disc
|
||||
kernel and apply threshold. Below is my code and output :
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
roi = cv2.imread('rose_red.png')
|
||||
hsv = cv2.cvtColor(roi,cv2.COLOR_BGR2HSV)
|
||||
roi = cv.imread('rose_red.png')
|
||||
hsv = cv.cvtColor(roi,cv.COLOR_BGR2HSV)
|
||||
|
||||
target = cv2.imread('rose.png')
|
||||
hsvt = cv2.cvtColor(target,cv2.COLOR_BGR2HSV)
|
||||
target = cv.imread('rose.png')
|
||||
hsvt = cv.cvtColor(target,cv.COLOR_BGR2HSV)
|
||||
|
||||
# calculating object histogram
|
||||
roihist = cv2.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
roihist = cv.calcHist([hsv],[0, 1], None, [180, 256], [0, 180, 0, 256] )
|
||||
|
||||
# normalize histogram and apply backprojection
|
||||
cv2.normalize(roihist,roihist,0,255,cv2.NORM_MINMAX)
|
||||
dst = cv2.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
|
||||
cv.normalize(roihist,roihist,0,255,cv.NORM_MINMAX)
|
||||
dst = cv.calcBackProject([hsvt],[0,1],roihist,[0,180,0,256],1)
|
||||
|
||||
# Now convolute with circular disc
|
||||
disc = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
|
||||
cv2.filter2D(dst,-1,disc,dst)
|
||||
disc = cv.getStructuringElement(cv.MORPH_ELLIPSE,(5,5))
|
||||
cv.filter2D(dst,-1,disc,dst)
|
||||
|
||||
# threshold and binary AND
|
||||
ret,thresh = cv2.threshold(dst,50,255,0)
|
||||
thresh = cv2.merge((thresh,thresh,thresh))
|
||||
res = cv2.bitwise_and(target,thresh)
|
||||
ret,thresh = cv.threshold(dst,50,255,0)
|
||||
thresh = cv.merge((thresh,thresh,thresh))
|
||||
res = cv.bitwise_and(target,thresh)
|
||||
|
||||
res = np.vstack((target,thresh,res))
|
||||
cv2.imwrite('res.jpg',res)
|
||||
cv.imwrite('res.jpg',res)
|
||||
@endcode
|
||||
Below is one example I worked with. I used the region inside blue rectangle as sample object and I
|
||||
wanted to extract the full ground.
|
||||
|
||||
+16
-16
@@ -7,7 +7,7 @@ Goal
|
||||
Learn to
|
||||
- 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.
|
||||
- You will see these functions : **cv.calcHist()**, **np.histogram()** etc.
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -57,10 +57,10 @@ intensity values.
|
||||
|
||||
### 1. Histogram Calculation in OpenCV
|
||||
|
||||
So now we use **cv2.calcHist()** function to find the histogram. Let's familiarize with the function
|
||||
So now we use **cv.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>
|
||||
<center><em>cv.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]".
|
||||
@@ -78,8 +78,8 @@ and its parameters :
|
||||
So let's start with a sample image. Simply load an image in grayscale mode and find its full
|
||||
histogram.
|
||||
@code{.py}
|
||||
img = cv2.imread('home.jpg',0)
|
||||
hist = cv2.calcHist([img],[0],None,[256],[0,256])
|
||||
img = cv.imread('home.jpg',0)
|
||||
hist = cv.calcHist([img],[0],None,[256],[0,256])
|
||||
@endcode
|
||||
hist is a 256x1 array, each value corresponds to number of pixels in that image with its
|
||||
corresponding pixel value.
|
||||
@@ -118,11 +118,11 @@ Matplotlib comes with a histogram plotting function : matplotlib.pyplot.hist()
|
||||
It directly finds the histogram and plot it. You need not use calcHist() or np.histogram() function
|
||||
to find the histogram. See the code below:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('home.jpg',0)
|
||||
img = cv.imread('home.jpg',0)
|
||||
plt.hist(img.ravel(),256,[0,256]); plt.show()
|
||||
@endcode
|
||||
You will get a plot as below :
|
||||
@@ -132,14 +132,14 @@ You will get a plot as below :
|
||||
Or you can use normal plot of matplotlib, which would be good for BGR plot. For that, you need to
|
||||
find the histogram data first. Try below code:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('home.jpg')
|
||||
img = cv.imread('home.jpg')
|
||||
color = ('b','g','r')
|
||||
for i,col in enumerate(color):
|
||||
histr = cv2.calcHist([img],[i],None,[256],[0,256])
|
||||
histr = cv.calcHist([img],[i],None,[256],[0,256])
|
||||
plt.plot(histr,color = col)
|
||||
plt.xlim([0,256])
|
||||
plt.show()
|
||||
@@ -154,28 +154,28 @@ should be due to the sky)
|
||||
### 2. Using OpenCV
|
||||
|
||||
Well, here you adjust the values of histograms along with its bin values to look like x,y
|
||||
coordinates so that you can draw it using cv2.line() or cv2.polyline() function to generate same
|
||||
coordinates so that you can draw it using cv.line() or cv.polyline() function to generate same
|
||||
image as above. This is already available with OpenCV-Python2 official samples. Check the
|
||||
code at samples/python/hist.py.
|
||||
|
||||
Application of Mask
|
||||
-------------------
|
||||
|
||||
We used cv2.calcHist() to find the histogram of the full image. What if you want to find histograms
|
||||
We used cv.calcHist() to find the histogram of the full image. What if you want to find histograms
|
||||
of some regions of an image? Just create a mask image with white color on the region you want to
|
||||
find histogram and black otherwise. Then pass this as the mask.
|
||||
@code{.py}
|
||||
img = cv2.imread('home.jpg',0)
|
||||
img = cv.imread('home.jpg',0)
|
||||
|
||||
# create a mask
|
||||
mask = np.zeros(img.shape[:2], np.uint8)
|
||||
mask[100:300, 100:400] = 255
|
||||
masked_img = cv2.bitwise_and(img,img,mask = mask)
|
||||
masked_img = cv.bitwise_and(img,img,mask = mask)
|
||||
|
||||
# Calculate histogram with mask and without mask
|
||||
# Check third argument for mask
|
||||
hist_full = cv2.calcHist([img],[0],None,[256],[0,256])
|
||||
hist_mask = cv2.calcHist([img],[0],mask,[256],[0,256])
|
||||
hist_full = cv.calcHist([img],[0],None,[256],[0,256])
|
||||
hist_mask = cv.calcHist([img],[0],mask,[256],[0,256])
|
||||
|
||||
plt.subplot(221), plt.imshow(img, 'gray')
|
||||
plt.subplot(222), plt.imshow(mask,'gray')
|
||||
|
||||
+10
-10
@@ -26,11 +26,11 @@ a very good explanation with worked out examples, so that you would understand a
|
||||
after reading that. Instead, here we will see its Numpy implementation. After that, we will see
|
||||
OpenCV function.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('wiki.jpg',0)
|
||||
img = cv.imread('wiki.jpg',0)
|
||||
|
||||
hist,bins = np.histogram(img.flatten(),256,[0,256])
|
||||
|
||||
@@ -76,15 +76,15 @@ histogram equalized to make them all with same lighting conditions.
|
||||
Histograms Equalization in OpenCV
|
||||
---------------------------------
|
||||
|
||||
OpenCV has a function to do this, **cv2.equalizeHist()**. Its input is just grayscale image and
|
||||
OpenCV has a function to do this, **cv.equalizeHist()**. Its input is just grayscale image and
|
||||
output is our histogram equalized image.
|
||||
|
||||
Below is a simple code snippet showing its usage for same image we used :
|
||||
@code{.py}
|
||||
img = cv2.imread('wiki.jpg',0)
|
||||
equ = cv2.equalizeHist(img)
|
||||
img = cv.imread('wiki.jpg',0)
|
||||
equ = cv.equalizeHist(img)
|
||||
res = np.hstack((img,equ)) #stacking images side-by-side
|
||||
cv2.imwrite('res.png',res)
|
||||
cv.imwrite('res.png',res)
|
||||
@endcode
|
||||

|
||||
|
||||
@@ -122,15 +122,15 @@ applied.
|
||||
Below code snippet shows how to apply CLAHE in OpenCV:
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('tsukuba_l.png',0)
|
||||
img = cv.imread('tsukuba_l.png',0)
|
||||
|
||||
# create a CLAHE object (Arguments are optional).
|
||||
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
||||
clahe = cv.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
|
||||
cl1 = clahe.apply(img)
|
||||
|
||||
cv2.imwrite('clahe_2.jpg',cl1)
|
||||
cv.imwrite('clahe_2.jpg',cl1)
|
||||
@endcode
|
||||
See the result below and compare it with results above, especially the statue region:
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ Goal
|
||||
|
||||
In this chapter,
|
||||
- We will learn to use Hough Transform to find circles in an image.
|
||||
- We will see these functions: **cv2.HoughCircles()**
|
||||
- We will see these functions: **cv.HoughCircles()**
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -17,29 +17,29 @@ equation, we can see we have 3 parameters, so we need a 3D accumulator for hough
|
||||
would be highly ineffective. So OpenCV uses more trickier method, **Hough Gradient Method** which
|
||||
uses the gradient information of edges.
|
||||
|
||||
The function we use here is **cv2.HoughCircles()**. It has plenty of arguments which are well
|
||||
The function we use here is **cv.HoughCircles()**. It has plenty of arguments which are well
|
||||
explained in the documentation. So we directly go to the code.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import numpy as np
|
||||
import cv2 as cv
|
||||
|
||||
img = cv2.imread('opencv-logo-white.png',0)
|
||||
img = cv2.medianBlur(img,5)
|
||||
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
|
||||
img = cv.imread('opencv-logo-white.png',0)
|
||||
img = cv.medianBlur(img,5)
|
||||
cimg = cv.cvtColor(img,cv.COLOR_GRAY2BGR)
|
||||
|
||||
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,20,
|
||||
circles = cv.HoughCircles(img,cv.HOUGH_GRADIENT,1,20,
|
||||
param1=50,param2=30,minRadius=0,maxRadius=0)
|
||||
|
||||
circles = np.uint16(np.around(circles))
|
||||
for i in circles[0,:]:
|
||||
# draw the outer circle
|
||||
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
|
||||
cv.circle(cimg,(i[0],i[1]),i[2],(0,255,0),2)
|
||||
# draw the center of the circle
|
||||
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
|
||||
cv.circle(cimg,(i[0],i[1]),2,(0,0,255),3)
|
||||
|
||||
cv2.imshow('detected circles',cimg)
|
||||
cv2.waitKey(0)
|
||||
cv2.destroyAllWindows()
|
||||
cv.imshow('detected circles',cimg)
|
||||
cv.waitKey(0)
|
||||
cv.destroyAllWindows()
|
||||
@endcode
|
||||
Result is shown below:
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ Goal
|
||||
In this chapter,
|
||||
- We will understand the concept of the Hough Transform.
|
||||
- We will see how to use it to detect lines in an image.
|
||||
- We will see the following functions: **cv2.HoughLines()**, **cv2.HoughLinesP()**
|
||||
- We will see the following functions: **cv.HoughLines()**, **cv.HoughLinesP()**
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -62,7 +62,7 @@ denote they are the parameters of possible lines in the image. (Image courtesy:
|
||||
Hough Transform in OpenCV
|
||||
=========================
|
||||
|
||||
Everything explained above is encapsulated in the OpenCV function, **cv2.HoughLines()**. It simply returns an array of :math:(rho,
|
||||
Everything explained above is encapsulated in the OpenCV function, **cv.HoughLines()**. It simply returns an array of :math:(rho,
|
||||
theta)\` values. \f$\rho\f$ is measured in pixels and \f$\theta\f$ is measured in radians. First parameter,
|
||||
Input image should be a binary image, so apply threshold or use canny edge detection before
|
||||
applying hough transform. Second and third parameters are \f$\rho\f$ and \f$\theta\f$ accuracies
|
||||
@@ -88,7 +88,7 @@ Hough Transform and Probabilistic Hough Transform in Hough space. (Image Courtes
|
||||
|
||||
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. @cite Matas00. The function used is
|
||||
**cv2.HoughLinesP()**. It has two new arguments.
|
||||
**cv.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 a single line.
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ Goal
|
||||
In this chapter,
|
||||
- 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.
|
||||
- We will see different functions like : **cv.erode()**, **cv.dilate()**,
|
||||
**cv.morphologyEx()** etc.
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -35,12 +35,12 @@ detach two connected objects etc.
|
||||
|
||||
Here, as an example, I would use a 5x5 kernel with full of ones. Let's see it how it works:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
img = cv2.imread('j.png',0)
|
||||
img = cv.imread('j.png',0)
|
||||
kernel = np.ones((5,5),np.uint8)
|
||||
erosion = cv2.erode(img,kernel,iterations = 1)
|
||||
erosion = cv.erode(img,kernel,iterations = 1)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -54,7 +54,7 @@ Normally, in cases like noise removal, erosion is followed by dilation. Because,
|
||||
white noises, but it also shrinks our object. So we dilate it. Since noise is gone, they won't come
|
||||
back, but our object area increases. It is also useful in joining broken parts of an object.
|
||||
@code{.py}
|
||||
dilation = cv2.dilate(img,kernel,iterations = 1)
|
||||
dilation = cv.dilate(img,kernel,iterations = 1)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -63,9 +63,9 @@ Result:
|
||||
### 3. Opening
|
||||
|
||||
Opening is just another name of **erosion followed by dilation**. It is useful in removing noise, as
|
||||
we explained above. Here we use the function, **cv2.morphologyEx()**
|
||||
we explained above. Here we use the function, **cv.morphologyEx()**
|
||||
@code{.py}
|
||||
opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel)
|
||||
opening = cv.morphologyEx(img, cv.MORPH_OPEN, kernel)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -76,7 +76,7 @@ Result:
|
||||
Closing is reverse of Opening, **Dilation followed by Erosion**. It is useful in closing small holes
|
||||
inside the foreground objects, or small black points on the object.
|
||||
@code{.py}
|
||||
closing = cv2.morphologyEx(img, cv2.MORPH_CLOSE, kernel)
|
||||
closing = cv.morphologyEx(img, cv.MORPH_CLOSE, kernel)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -88,7 +88,7 @@ It is the difference between dilation and erosion of an image.
|
||||
|
||||
The result will look like the outline of the object.
|
||||
@code{.py}
|
||||
gradient = cv2.morphologyEx(img, cv2.MORPH_GRADIENT, kernel)
|
||||
gradient = cv.morphologyEx(img, cv.MORPH_GRADIENT, kernel)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -99,7 +99,7 @@ Result:
|
||||
It is the difference between input image and Opening of the image. Below example is done for a 9x9
|
||||
kernel.
|
||||
@code{.py}
|
||||
tophat = cv2.morphologyEx(img, cv2.MORPH_TOPHAT, kernel)
|
||||
tophat = cv.morphologyEx(img, cv.MORPH_TOPHAT, kernel)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -109,7 +109,7 @@ Result:
|
||||
|
||||
It is the difference between the closing of the input image and input image.
|
||||
@code{.py}
|
||||
blackhat = cv2.morphologyEx(img, cv2.MORPH_BLACKHAT, kernel)
|
||||
blackhat = cv.morphologyEx(img, cv.MORPH_BLACKHAT, kernel)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -120,11 +120,11 @@ Structuring Element
|
||||
|
||||
We manually created a structuring elements in the previous examples with help of Numpy. It is
|
||||
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
|
||||
purpose, OpenCV has a function, **cv.getStructuringElement()**. You just pass the shape and size of
|
||||
the kernel, you get the desired kernel.
|
||||
@code{.py}
|
||||
# Rectangular Kernel
|
||||
>>> cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
|
||||
>>> cv.getStructuringElement(cv.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))
|
||||
>>> cv.getStructuringElement(cv.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))
|
||||
>>> cv.getStructuringElement(cv.MORPH_CROSS,(5,5))
|
||||
array([[0, 0, 1, 0, 0],
|
||||
[0, 0, 1, 0, 0],
|
||||
[1, 1, 1, 1, 1],
|
||||
|
||||
@@ -7,7 +7,7 @@ Goal
|
||||
In this chapter,
|
||||
- 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()**
|
||||
- We will see these functions: **cv.pyrUp()**, **cv.pyrDown()**
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -28,18 +28,18 @@ contribution from 5 pixels in underlying level with gaussian weights. By doing s
|
||||
image becomes \f$M/2 \times N/2\f$ image. So area reduces to one-fourth of original area. It is called
|
||||
an Octave. The same pattern continues as we go upper in pyramid (ie, resolution decreases).
|
||||
Similarly while expanding, area becomes 4 times in each level. We can find Gaussian pyramids using
|
||||
**cv2.pyrDown()** and **cv2.pyrUp()** functions.
|
||||
**cv.pyrDown()** and **cv.pyrUp()** functions.
|
||||
@code{.py}
|
||||
img = cv2.imread('messi5.jpg')
|
||||
lower_reso = cv2.pyrDown(higher_reso)
|
||||
img = cv.imread('messi5.jpg')
|
||||
lower_reso = cv.pyrDown(higher_reso)
|
||||
@endcode
|
||||
Below is the 4 levels in an image pyramid.
|
||||
|
||||

|
||||
|
||||
Now you can go down the image pyramid with **cv2.pyrUp()** function.
|
||||
Now you can go down the image pyramid with **cv.pyrUp()** function.
|
||||
@code{.py}
|
||||
higher_reso2 = cv2.pyrUp(lower_reso)
|
||||
higher_reso2 = cv.pyrUp(lower_reso)
|
||||
@endcode
|
||||
Remember, higher_reso2 is not equal to higher_reso, because once you decrease the resolution, you
|
||||
loose the information. Below image is 3 level down the pyramid created from smallest image in
|
||||
@@ -79,38 +79,38 @@ blending, Laplacian Pyramids etc. Simply it is done as follows:
|
||||
Below is the full code. (For sake of simplicity, each step is done separately which may take more
|
||||
memory. You can optimize it if you want so).
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np,sys
|
||||
|
||||
A = cv2.imread('apple.jpg')
|
||||
B = cv2.imread('orange.jpg')
|
||||
A = cv.imread('apple.jpg')
|
||||
B = cv.imread('orange.jpg')
|
||||
|
||||
# generate Gaussian pyramid for A
|
||||
G = A.copy()
|
||||
gpA = [G]
|
||||
for i in xrange(6):
|
||||
G = cv2.pyrDown(G)
|
||||
G = cv.pyrDown(G)
|
||||
gpA.append(G)
|
||||
|
||||
# generate Gaussian pyramid for B
|
||||
G = B.copy()
|
||||
gpB = [G]
|
||||
for i in xrange(6):
|
||||
G = cv2.pyrDown(G)
|
||||
G = cv.pyrDown(G)
|
||||
gpB.append(G)
|
||||
|
||||
# generate Laplacian Pyramid for A
|
||||
lpA = [gpA[5]]
|
||||
for i in xrange(5,0,-1):
|
||||
GE = cv2.pyrUp(gpA[i])
|
||||
L = cv2.subtract(gpA[i-1],GE)
|
||||
GE = cv.pyrUp(gpA[i])
|
||||
L = cv.subtract(gpA[i-1],GE)
|
||||
lpA.append(L)
|
||||
|
||||
# generate Laplacian Pyramid for B
|
||||
lpB = [gpB[5]]
|
||||
for i in xrange(5,0,-1):
|
||||
GE = cv2.pyrUp(gpB[i])
|
||||
L = cv2.subtract(gpB[i-1],GE)
|
||||
GE = cv.pyrUp(gpB[i])
|
||||
L = cv.subtract(gpB[i-1],GE)
|
||||
lpB.append(L)
|
||||
|
||||
# Now add left and right halves of images in each level
|
||||
@@ -123,14 +123,14 @@ for la,lb in zip(lpA,lpB):
|
||||
# now reconstruct
|
||||
ls_ = LS[0]
|
||||
for i in xrange(1,6):
|
||||
ls_ = cv2.pyrUp(ls_)
|
||||
ls_ = cv2.add(ls_, LS[i])
|
||||
ls_ = cv.pyrUp(ls_)
|
||||
ls_ = cv.add(ls_, LS[i])
|
||||
|
||||
# image with direct connecting each half
|
||||
real = np.hstack((A[:,:cols/2],B[:,cols/2:]))
|
||||
|
||||
cv2.imwrite('Pyramid_blending2.jpg',ls_)
|
||||
cv2.imwrite('Direct_blending.jpg',real)
|
||||
cv.imwrite('Pyramid_blending2.jpg',ls_)
|
||||
cv.imwrite('Direct_blending.jpg',real)
|
||||
@endcode
|
||||
Additional Resources
|
||||
--------------------
|
||||
|
||||
@@ -6,24 +6,24 @@ Goals
|
||||
|
||||
In this chapter, you will learn
|
||||
- To find objects in an image using Template Matching
|
||||
- You will see these functions : **cv2.matchTemplate()**, **cv2.minMaxLoc()**
|
||||
- You will see these functions : **cv.matchTemplate()**, **cv.minMaxLoc()**
|
||||
|
||||
Theory
|
||||
------
|
||||
|
||||
Template Matching is a method for searching and finding the location of a template image in a larger
|
||||
image. OpenCV comes with a function **cv2.matchTemplate()** for this purpose. It simply slides the
|
||||
image. OpenCV comes with a function **cv.matchTemplate()** for this purpose. It simply slides the
|
||||
template image over the input image (as in 2D convolution) and compares the template and patch of
|
||||
input image under the template image. Several comparison methods are implemented in OpenCV. (You can
|
||||
check docs for more details). It returns a grayscale image, where each pixel denotes how much does
|
||||
the neighbourhood of that pixel match with template.
|
||||
|
||||
If input image is of size (WxH) and template image is of size (wxh), output image will have a size
|
||||
of (W-w+1, H-h+1). Once you got the result, you can use **cv2.minMaxLoc()** function to find where
|
||||
of (W-w+1, H-h+1). Once you got the result, you can use **cv.minMaxLoc()** function to find where
|
||||
is the maximum/minimum value. Take it as the top-left corner of rectangle and take (w,h) as width
|
||||
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.
|
||||
@note If you are using cv.TM_SQDIFF as comparison method, minimum value gives the best match.
|
||||
|
||||
Template Matching in OpenCV
|
||||
---------------------------
|
||||
@@ -34,35 +34,35 @@ Here, as an example, we will search for Messi's face in his photo. So I created
|
||||
|
||||
We will try all the comparison methods so that we can see how their results look like:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
img2 = img.copy()
|
||||
template = cv2.imread('template.jpg',0)
|
||||
template = cv.imread('template.jpg',0)
|
||||
w, h = template.shape[::-1]
|
||||
|
||||
# All the 6 methods for comparison in a list
|
||||
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
|
||||
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
|
||||
methods = ['cv.TM_CCOEFF', 'cv.TM_CCOEFF_NORMED', 'cv.TM_CCORR',
|
||||
'cv.TM_CCORR_NORMED', 'cv.TM_SQDIFF', 'cv.TM_SQDIFF_NORMED']
|
||||
|
||||
for meth in methods:
|
||||
img = img2.copy()
|
||||
method = eval(meth)
|
||||
|
||||
# Apply template Matching
|
||||
res = cv2.matchTemplate(img,template,method)
|
||||
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
|
||||
res = cv.matchTemplate(img,template,method)
|
||||
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(res)
|
||||
|
||||
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
|
||||
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
|
||||
if method in [cv.TM_SQDIFF, cv.TM_SQDIFF_NORMED]:
|
||||
top_left = min_loc
|
||||
else:
|
||||
top_left = max_loc
|
||||
bottom_right = (top_left[0] + w, top_left[1] + h)
|
||||
|
||||
cv2.rectangle(img,top_left, bottom_right, 255, 2)
|
||||
cv.rectangle(img,top_left, bottom_right, 255, 2)
|
||||
|
||||
plt.subplot(121),plt.imshow(res,cmap = 'gray')
|
||||
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
|
||||
@@ -74,56 +74,56 @@ for meth in methods:
|
||||
@endcode
|
||||
See the results below:
|
||||
|
||||
- cv2.TM_CCOEFF
|
||||
- cv.TM_CCOEFF
|
||||
|
||||

|
||||
|
||||
- cv2.TM_CCOEFF_NORMED
|
||||
- cv.TM_CCOEFF_NORMED
|
||||
|
||||

|
||||
|
||||
- cv2.TM_CCORR
|
||||
- cv.TM_CCORR
|
||||
|
||||

|
||||
|
||||
- cv2.TM_CCORR_NORMED
|
||||
- cv.TM_CCORR_NORMED
|
||||
|
||||

|
||||
|
||||
- cv2.TM_SQDIFF
|
||||
- cv.TM_SQDIFF
|
||||
|
||||

|
||||
|
||||
- cv2.TM_SQDIFF_NORMED
|
||||
- cv.TM_SQDIFF_NORMED
|
||||
|
||||

|
||||
|
||||
You can see that the result using **cv2.TM_CCORR** is not good as we expected.
|
||||
You can see that the result using **cv.TM_CCORR** is not good as we expected.
|
||||
|
||||
Template Matching with Multiple Objects
|
||||
---------------------------------------
|
||||
|
||||
In the previous section, we searched image for Messi's face, which occurs only once in the image.
|
||||
Suppose you are searching for an object which has multiple occurances, **cv2.minMaxLoc()** won't
|
||||
Suppose you are searching for an object which has multiple occurances, **cv.minMaxLoc()** won't
|
||||
give you all the locations. In that case, we will use thresholding. So in this example, we will use
|
||||
a screenshot of the famous game **Mario** and we will find the coins in it.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img_rgb = cv2.imread('mario.png')
|
||||
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
|
||||
template = cv2.imread('mario_coin.png',0)
|
||||
img_rgb = cv.imread('mario.png')
|
||||
img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
|
||||
template = cv.imread('mario_coin.png',0)
|
||||
w, h = template.shape[::-1]
|
||||
|
||||
res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
|
||||
res = cv.matchTemplate(img_gray,template,cv.TM_CCOEFF_NORMED)
|
||||
threshold = 0.8
|
||||
loc = np.where( res >= threshold)
|
||||
for pt in zip(*loc[::-1]):
|
||||
cv2.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
|
||||
cv.rectangle(img_rgb, pt, (pt[0] + w, pt[1] + h), (0,0,255), 2)
|
||||
|
||||
cv2.imwrite('res.png',img_rgb)
|
||||
cv.imwrite('res.png',img_rgb)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
|
||||
@@ -6,24 +6,24 @@ Goal
|
||||
|
||||
- In this tutorial, you will learn Simple thresholding, Adaptive thresholding, Otsu's thresholding
|
||||
etc.
|
||||
- You will learn these functions : **cv2.threshold**, **cv2.adaptiveThreshold** etc.
|
||||
- You will learn these functions : **cv.threshold**, **cv.adaptiveThreshold** etc.
|
||||
|
||||
Simple Thresholding
|
||||
-------------------
|
||||
|
||||
Here, the matter is straight forward. If pixel value is greater than a threshold value, it is
|
||||
assigned one value (may be white), else it is assigned another value (may be black). The function
|
||||
used is **cv2.threshold**. First argument is the source image, which **should be a grayscale
|
||||
used is **cv.threshold**. First argument is the source image, which **should be a grayscale
|
||||
image**. Second argument is the threshold value which is used to classify the pixel values. Third
|
||||
argument is the maxVal which represents the value to be given if pixel value is more than (sometimes
|
||||
less than) the threshold value. OpenCV provides different styles of thresholding and it is decided
|
||||
by the fourth parameter of the function. Different types are:
|
||||
|
||||
- cv2.THRESH_BINARY
|
||||
- cv2.THRESH_BINARY_INV
|
||||
- cv2.THRESH_TRUNC
|
||||
- cv2.THRESH_TOZERO
|
||||
- cv2.THRESH_TOZERO_INV
|
||||
- cv.THRESH_BINARY
|
||||
- cv.THRESH_BINARY_INV
|
||||
- cv.THRESH_TRUNC
|
||||
- cv.THRESH_TOZERO
|
||||
- cv.THRESH_TOZERO_INV
|
||||
|
||||
Documentation clearly explain what each type is meant for. Please check out the documentation.
|
||||
|
||||
@@ -32,16 +32,16 @@ our **thresholded image**.
|
||||
|
||||
Code :
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('gradient.png',0)
|
||||
ret,thresh1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
|
||||
ret,thresh2 = cv2.threshold(img,127,255,cv2.THRESH_BINARY_INV)
|
||||
ret,thresh3 = cv2.threshold(img,127,255,cv2.THRESH_TRUNC)
|
||||
ret,thresh4 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO)
|
||||
ret,thresh5 = cv2.threshold(img,127,255,cv2.THRESH_TOZERO_INV)
|
||||
img = cv.imread('gradient.png',0)
|
||||
ret,thresh1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
|
||||
ret,thresh2 = cv.threshold(img,127,255,cv.THRESH_BINARY_INV)
|
||||
ret,thresh3 = cv.threshold(img,127,255,cv.THRESH_TRUNC)
|
||||
ret,thresh4 = cv.threshold(img,127,255,cv.THRESH_TOZERO)
|
||||
ret,thresh5 = cv.threshold(img,127,255,cv.THRESH_TOZERO_INV)
|
||||
|
||||
titles = ['Original Image','BINARY','BINARY_INV','TRUNC','TOZERO','TOZERO_INV']
|
||||
images = [img, thresh1, thresh2, thresh3, thresh4, thresh5]
|
||||
@@ -72,8 +72,8 @@ 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_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood
|
||||
- cv.ADAPTIVE_THRESH_MEAN_C : threshold value is the mean of neighbourhood area.
|
||||
- cv.ADAPTIVE_THRESH_GAUSSIAN_C : threshold value is the weighted sum of neighbourhood
|
||||
values where weights are a gaussian window.
|
||||
|
||||
**Block Size** - It decides the size of neighbourhood area.
|
||||
@@ -83,18 +83,18 @@ It has three ‘special’ input params and only one output argument.
|
||||
Below piece of code compares global thresholding and adaptive thresholding for an image with varying
|
||||
illumination:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('sudoku.png',0)
|
||||
img = cv2.medianBlur(img,5)
|
||||
img = cv.imread('sudoku.png',0)
|
||||
img = cv.medianBlur(img,5)
|
||||
|
||||
ret,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
|
||||
th2 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_MEAN_C,\
|
||||
cv2.THRESH_BINARY,11,2)
|
||||
th3 = cv2.adaptiveThreshold(img,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C,\
|
||||
cv2.THRESH_BINARY,11,2)
|
||||
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
|
||||
th2 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\
|
||||
cv.THRESH_BINARY,11,2)
|
||||
th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
|
||||
cv.THRESH_BINARY,11,2)
|
||||
|
||||
titles = ['Original Image', 'Global Thresholding (v = 127)',
|
||||
'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']
|
||||
@@ -124,7 +124,7 @@ That is what Otsu binarization does. So in simple words, it automatically calcul
|
||||
value from image histogram for a bimodal image. (For images which are not bimodal, binarization
|
||||
won’t be accurate.)
|
||||
|
||||
For this, our cv2.threshold() function is used, but pass an extra flag, cv2.THRESH_OTSU. **For
|
||||
For this, our cv.threshold() function is used, but pass an extra flag, cv.THRESH_OTSU. **For
|
||||
threshold value, simply pass zero**. Then the algorithm finds the optimal threshold value and
|
||||
returns you as the second output, retVal. If Otsu thresholding is not used, retVal is same as the
|
||||
threshold value you used.
|
||||
@@ -134,21 +134,21 @@ for a value of 127. In second case, I applied Otsu’s thresholding directly. In
|
||||
filtered image with a 5x5 gaussian kernel to remove the noise, then applied Otsu thresholding. See
|
||||
how noise filtering improves the result.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('noisy2.png',0)
|
||||
img = cv.imread('noisy2.png',0)
|
||||
|
||||
# global thresholding
|
||||
ret1,th1 = cv2.threshold(img,127,255,cv2.THRESH_BINARY)
|
||||
ret1,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)
|
||||
|
||||
# Otsu's thresholding
|
||||
ret2,th2 = cv2.threshold(img,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
||||
ret2,th2 = cv.threshold(img,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
|
||||
|
||||
# Otsu's thresholding after Gaussian filtering
|
||||
blur = cv2.GaussianBlur(img,(5,5),0)
|
||||
ret3,th3 = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
||||
blur = cv.GaussianBlur(img,(5,5),0)
|
||||
ret3,th3 = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
|
||||
|
||||
# plot all the images and their histograms
|
||||
images = [img, 0, th1,
|
||||
@@ -188,11 +188,11 @@ where
|
||||
It actually finds a value of t which lies in between two peaks such that variances to both classes
|
||||
are minimum. It can be simply implemented in Python as follows:
|
||||
@code{.py}
|
||||
img = cv2.imread('noisy2.png',0)
|
||||
blur = cv2.GaussianBlur(img,(5,5),0)
|
||||
img = cv.imread('noisy2.png',0)
|
||||
blur = cv.GaussianBlur(img,(5,5),0)
|
||||
|
||||
# find normalized_histogram, and its cumulative distribution function
|
||||
hist = cv2.calcHist([blur],[0],None,[256],[0,256])
|
||||
hist = cv.calcHist([blur],[0],None,[256],[0,256])
|
||||
hist_norm = hist.ravel()/hist.max()
|
||||
Q = hist_norm.cumsum()
|
||||
|
||||
@@ -217,7 +217,7 @@ for i in xrange(1,256):
|
||||
thresh = i
|
||||
|
||||
# find otsu's threshold value with OpenCV function
|
||||
ret, otsu = cv2.threshold(blur,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
|
||||
ret, otsu = cv.threshold(blur,0,255,cv.THRESH_BINARY+cv.THRESH_OTSU)
|
||||
print( "{} {}".format(thresh,ret) )
|
||||
@endcode
|
||||
*(Some of the functions may be new here, but we will cover them in coming chapters)*
|
||||
|
||||
+24
-24
@@ -8,7 +8,7 @@ In this section, we will learn
|
||||
- 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
|
||||
- We will see following functions : **cv.dft()**, **cv.idft()** etc
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -50,11 +50,11 @@ you want to bring it to center, you need to shift the result by \f$\frac{N}{2}\f
|
||||
directions. This is simply done by the function, **np.fft.fftshift()**. (It is more easier to
|
||||
analyze). Once you found the frequency transform, you can find the magnitude spectrum.
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
f = np.fft.fft2(img)
|
||||
fshift = np.fft.fftshift(f)
|
||||
magnitude_spectrum = 20*np.log(np.abs(fshift))
|
||||
@@ -112,21 +112,21 @@ Better option is Gaussian Windows.
|
||||
Fourier Transform in OpenCV
|
||||
---------------------------
|
||||
|
||||
OpenCV provides the functions **cv2.dft()** and **cv2.idft()** for this. It returns the same result
|
||||
OpenCV provides the functions **cv.dft()** and **cv.idft()** for this. It returns the same result
|
||||
as previous, but with two channels. First channel will have the real part of the result and second
|
||||
channel will have the imaginary part of the result. The input image should be converted to
|
||||
np.float32 first. We will see how to do it.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('messi5.jpg',0)
|
||||
img = cv.imread('messi5.jpg',0)
|
||||
|
||||
dft = cv2.dft(np.float32(img),flags = cv2.DFT_COMPLEX_OUTPUT)
|
||||
dft = cv.dft(np.float32(img),flags = cv.DFT_COMPLEX_OUTPUT)
|
||||
dft_shift = np.fft.fftshift(dft)
|
||||
|
||||
magnitude_spectrum = 20*np.log(cv2.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
|
||||
magnitude_spectrum = 20*np.log(cv.magnitude(dft_shift[:,:,0],dft_shift[:,:,1]))
|
||||
|
||||
plt.subplot(121),plt.imshow(img, cmap = 'gray')
|
||||
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
|
||||
@@ -135,7 +135,7 @@ 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
|
||||
@note You can also use **cv.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
|
||||
@@ -153,8 +153,8 @@ mask[crow-30:crow+30, ccol-30:ccol+30] = 1
|
||||
# apply mask and inverse DFT
|
||||
fshift = dft_shift*mask
|
||||
f_ishift = np.fft.ifftshift(fshift)
|
||||
img_back = cv2.idft(f_ishift)
|
||||
img_back = cv2.magnitude(img_back[:,:,0],img_back[:,:,1])
|
||||
img_back = cv.idft(f_ishift)
|
||||
img_back = cv.magnitude(img_back[:,:,0],img_back[:,:,1])
|
||||
|
||||
plt.subplot(121),plt.imshow(img, cmap = 'gray')
|
||||
plt.title('Input Image'), plt.xticks([]), plt.yticks([])
|
||||
@@ -166,7 +166,7 @@ See the result:
|
||||
|
||||

|
||||
|
||||
@note As usual, OpenCV functions **cv2.dft()** and **cv2.idft()** are faster than Numpy
|
||||
@note As usual, OpenCV functions **cv.dft()** and **cv.idft()** are faster than Numpy
|
||||
counterparts. But Numpy functions are more user-friendly. For more details about performance issues,
|
||||
see below section.
|
||||
|
||||
@@ -180,23 +180,23 @@ the array to any optimal size (by padding zeros) before finding DFT. For OpenCV,
|
||||
manually pad zeros. But for Numpy, you specify the new size of FFT calculation, and it will
|
||||
automatically pad zeros for you.
|
||||
|
||||
So how do we find this optimal size ? OpenCV provides a function, **cv2.getOptimalDFTSize()** for
|
||||
this. It is applicable to both **cv2.dft()** and **np.fft.fft2()**. Let's check their performance
|
||||
So how do we find this optimal size ? OpenCV provides a function, **cv.getOptimalDFTSize()** for
|
||||
this. It is applicable to both **cv.dft()** and **np.fft.fft2()**. Let's check their performance
|
||||
using IPython magic command %timeit.
|
||||
@code{.py}
|
||||
In [16]: img = cv2.imread('messi5.jpg',0)
|
||||
In [16]: img = cv.imread('messi5.jpg',0)
|
||||
In [17]: rows,cols = img.shape
|
||||
In [18]: print("{} {}".format(rows,cols))
|
||||
342 548
|
||||
|
||||
In [19]: nrows = cv2.getOptimalDFTSize(rows)
|
||||
In [20]: ncols = cv2.getOptimalDFTSize(cols)
|
||||
In [19]: nrows = cv.getOptimalDFTSize(rows)
|
||||
In [20]: ncols = cv.getOptimalDFTSize(cols)
|
||||
In [21]: print("{} {}".format(nrows,ncols))
|
||||
360 576
|
||||
@endcode
|
||||
See, the size (342,548) is modified to (360, 576). Now let's pad it with zeros (for OpenCV) and find
|
||||
their DFT calculation performance. You can do it by creating a new big zero array and copy the data
|
||||
to it, or use **cv2.copyMakeBorder()**.
|
||||
to it, or use **cv.copyMakeBorder()**.
|
||||
@code{.py}
|
||||
nimg = np.zeros((nrows,ncols))
|
||||
nimg[:rows,:cols] = img
|
||||
@@ -205,8 +205,8 @@ OR:
|
||||
@code{.py}
|
||||
right = ncols - cols
|
||||
bottom = nrows - rows
|
||||
bordertype = cv2.BORDER_CONSTANT #just to avoid line breakup in PDF file
|
||||
nimg = cv2.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
|
||||
bordertype = cv.BORDER_CONSTANT #just to avoid line breakup in PDF file
|
||||
nimg = cv.copyMakeBorder(img,0,bottom,0,right,bordertype, value = 0)
|
||||
@endcode
|
||||
Now we calculate the DFT performance comparison of Numpy function:
|
||||
@code{.py}
|
||||
@@ -217,9 +217,9 @@ In [23]: %timeit fft2 = np.fft.fft2(img,[nrows,ncols])
|
||||
@endcode
|
||||
It shows a 4x speedup. Now we will try the same with OpenCV functions.
|
||||
@code{.py}
|
||||
In [24]: %timeit dft1= cv2.dft(np.float32(img),flags=cv2.DFT_COMPLEX_OUTPUT)
|
||||
In [24]: %timeit dft1= cv.dft(np.float32(img),flags=cv.DFT_COMPLEX_OUTPUT)
|
||||
100 loops, best of 3: 13.5 ms per loop
|
||||
In [27]: %timeit dft2= cv2.dft(np.float32(nimg),flags=cv2.DFT_COMPLEX_OUTPUT)
|
||||
In [27]: %timeit dft2= cv.dft(np.float32(nimg),flags=cv.DFT_COMPLEX_OUTPUT)
|
||||
100 loops, best of 3: 3.11 ms per loop
|
||||
@endcode
|
||||
It also shows a 4x speed-up. You can also see that OpenCV functions are around 3x faster than Numpy
|
||||
@@ -232,7 +232,7 @@ A similar question was asked in a forum. The question is, why Laplacian is a hig
|
||||
Sobel is a HPF? etc. And the first answer given to it was in terms of Fourier Transform. Just take
|
||||
the fourier transform of Laplacian for some higher size of FFT. Analyze it:
|
||||
@code{.py}
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
@@ -240,7 +240,7 @@ from matplotlib import pyplot as plt
|
||||
mean_filter = np.ones((3,3))
|
||||
|
||||
# creating a guassian filter
|
||||
x = cv2.getGaussianKernel(5,10)
|
||||
x = cv.getGaussianKernel(5,10)
|
||||
gaussian = x*x.T
|
||||
|
||||
# different edge detecting filters
|
||||
|
||||
@@ -6,7 +6,7 @@ Goal
|
||||
|
||||
In this chapter,
|
||||
- We will learn to use marker-based image segmentation using watershed algorithm
|
||||
- We will see: **cv2.watershed()**
|
||||
- We will see: **cv.watershed()**
|
||||
|
||||
Theory
|
||||
------
|
||||
@@ -45,12 +45,12 @@ We start with finding an approximate estimate of the coins. For that, we can use
|
||||
binarization.
|
||||
@code{.py}
|
||||
import numpy as np
|
||||
import cv2
|
||||
import cv2 as cv
|
||||
from matplotlib import pyplot as plt
|
||||
|
||||
img = cv2.imread('coins.png')
|
||||
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
|
||||
ret, thresh = cv2.threshold(gray,0,255,cv2.THRESH_BINARY_INV+cv2.THRESH_OTSU)
|
||||
img = cv.imread('coins.png')
|
||||
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
|
||||
ret, thresh = cv.threshold(gray,0,255,cv.THRESH_BINARY_INV+cv.THRESH_OTSU)
|
||||
@endcode
|
||||
Result:
|
||||
|
||||
@@ -78,18 +78,18 @@ obtained from subtracting sure_fg area from sure_bg area.
|
||||
@code{.py}
|
||||
# noise removal
|
||||
kernel = np.ones((3,3),np.uint8)
|
||||
opening = cv2.morphologyEx(thresh,cv2.MORPH_OPEN,kernel, iterations = 2)
|
||||
opening = cv.morphologyEx(thresh,cv.MORPH_OPEN,kernel, iterations = 2)
|
||||
|
||||
# sure background area
|
||||
sure_bg = cv2.dilate(opening,kernel,iterations=3)
|
||||
sure_bg = cv.dilate(opening,kernel,iterations=3)
|
||||
|
||||
# Finding sure foreground area
|
||||
dist_transform = cv2.distanceTransform(opening,cv2.DIST_L2,5)
|
||||
ret, sure_fg = cv2.threshold(dist_transform,0.7*dist_transform.max(),255,0)
|
||||
dist_transform = cv.distanceTransform(opening,cv.DIST_L2,5)
|
||||
ret, sure_fg = cv.threshold(dist_transform,0.7*dist_transform.max(),255,0)
|
||||
|
||||
# Finding unknown region
|
||||
sure_fg = np.uint8(sure_fg)
|
||||
unknown = cv2.subtract(sure_bg,sure_fg)
|
||||
unknown = cv.subtract(sure_bg,sure_fg)
|
||||
@endcode
|
||||
See the result. In the thresholded image, we get some regions of coins which we are sure of coins
|
||||
and they are detached now. (In some cases, you may be interested in only foreground segmentation,
|
||||
@@ -103,7 +103,7 @@ Now we know for sure which are region of coins, which are background and all. So
|
||||
(it is an array of same size as that of original image, but with int32 datatype) and label the
|
||||
regions inside it. The regions we know for sure (whether foreground or background) are labelled with
|
||||
any positive integers, but different integers, and the area we don't know for sure are just left as
|
||||
zero. For this we use **cv2.connectedComponents()**. It labels background of the image with 0, then
|
||||
zero. For this we use **cv.connectedComponents()**. It labels background of the image with 0, then
|
||||
other objects are labelled with integers starting from 1.
|
||||
|
||||
But we know that if background is marked with 0, watershed will consider it as unknown area. So we
|
||||
@@ -111,7 +111,7 @@ want to mark it with different integer. Instead, we will mark unknown region, de
|
||||
with 0.
|
||||
@code{.py}
|
||||
# Marker labelling
|
||||
ret, markers = cv2.connectedComponents(sure_fg)
|
||||
ret, markers = cv.connectedComponents(sure_fg)
|
||||
|
||||
# Add one to all labels so that sure background is not 0, but 1
|
||||
markers = markers+1
|
||||
@@ -128,7 +128,7 @@ compared to unknown region.
|
||||
Now our marker is ready. It is time for final step, apply watershed. Then marker image will be
|
||||
modified. The boundary region will be marked with -1.
|
||||
@code{.py}
|
||||
markers = cv2.watershed(img,markers)
|
||||
markers = cv.watershed(img,markers)
|
||||
img[markers == -1] = [255,0,0]
|
||||
@endcode
|
||||
See the result below. For some coins, the region where they touch are segmented properly and for
|
||||
|
||||
Reference in New Issue
Block a user