How can I reduce complexity of contour by cv2 python? - python

I have some contour image and I want to obtain more simple contour. For example if there is some litle curves such wool of animal or beard of man than I would like to change it woth simple line. For instance on this image from first picture I want to get second. I use cv2 in it.

OpenCV gives you very basic control with the ContourApproximationModes enum that you pass to the findContours() function:
CHAIN_APPROX_NONE
stores absolutely all the contour points. That is, any 2 subsequent points (x1,y1) and (x2,y2) of the contour will be either horizontal, vertical or diagonal neighbors, that is, max(abs(x1-x2),abs(y2-y1))==1.
CHAIN_APPROX_SIMPLE
compresses horizontal, vertical, and diagonal segments and leaves only their end points.
For example, an up-right rectangular contour is encoded with 4 points.
CHAIN_APPROX_TC89_L1
applies one of the flavors of the Teh-Chin chain approximation algorithm [241]
CHAIN_APPROX_TC89_KCOS
applies one of the flavors of the Teh-Chin chain approximation algorithm [241]

Related

How can I detect circles in python with a set of (x, y) points

I have a list of (x,y) points that constitue several circles with different centers, they all have the same diameter (which is known).
I need to detect the number of circles in total (not necessary to define their parameters). Is there a simple way to do that in python? (preferably without openCV)
If all circles have the same size and they do not intersect, you can just scan the picture line-by-line, pixel-by-pixel.
When you meet a pixel of circle color, apply flood-fill algorithm from this point and mark all connected pixels of the same color with the same integer value (1 for the first circle and so on).
After all the last value is number of objects.
Aslo you can use connected-component labelling algorithm

How do I fit rectangles to an image in python and obtain their coordinates

I'm looking for a way to split a number of images into proper rectangles. These rectangles are ideally shaped such that each of them take on the largest possible size without containing a lot of white.
So let's say that we have the following image
I would like to get an output such as this:
Note the overlapping rectangles, the hole and the non axis aligned rectangle, all of these are likely scenario's I have to deal with.
I'm aiming to get the coordinates describing the corner pieces of the rectangles so something like
[[(73,13),(269,13),(269,47)(73,47)],
[(73,13),(73,210),(109,210),(109,13)]
...]
In order to do this I have already looked at the cv2.findContours but I couldn't get it to work with overlapping rectangles (though I could use the hierarchy model to deal with holes as that causes the contours to be merged into one.
Note that although not shown holes can be nested.
A algorithm that works roughly as follow should be able to give you the result you seek.
Get all the corner points in the image.
Randomly select 3 points to create a rectangle
Count the ratio of yellow pixels within the rectangle, accept if the ratio satisfy a threshold.
Repeat 2 to 4 until :
a) every single combination of point is complete or
b) all yellow pixel are accounted for or
c) after n number of iteration
The difficult part of this algorithm lies in step 2, creating rectangle from 3 points.
If all the rectangles were right angle, you can simply find the minimum x and y to correspond for topLeft corner and maximum x and y to correspond for bottomRight corner of your new rectangle.
But since you have off axis rectangle, you will need to check if the two vector created from the 3 points have a 90 degree angle between them before generating the rectangle.

Detecting shape of a contour and color inside

I am new to opencv using python and trying to get the shape of a contour in an image.
Considering only regular shapes like square, rectangle, circle and triangle is there any way to get the contour shape using only numpy and cv2 libraries?
Also i want to find the colour inside a contour. How can I do it?
For finding area of a contour there is an inbuilt function: cv2.contourArea(cnt).
Are there inbuilt functions for "contour shape" and "color inside contour" also?
Please help!
Note : The images I am considering contains multiple regular shapes.
This method might be longer, but right now it is on the top of my head. For finding contour shape, use findcontours function, it will give vector of points as output(boundary points of contours). Now find the center of contour, using moments.
for finding contour use this function-
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]])
image is the canny output image.
calculate center from moments, refer to this link
http://docs.opencv.org/trunk/dd/d49/tutorial_py_contour_features.html
calculate distance of each point stored in contours from the center
Now classify shaped by comparing distance of points from center
1)circle - all contours points will be roughly at equal distance from center.
2)square, rectangle- find farthest 4 points from center, These points will be vertices and will have approximately same distance. Now differentiate square from rectangle using edge length
3) traingles - this can be tricky, for different types of triangle, so you can just use else condition here, since you have only 4 shapes
For finding colour, use the vertices for square, rectangle and triangle to create a mask.
Since you have single color only, you make a small patch around center and get the avg value of RGB pixels there.
Assume you have center at (100,100) and its a circle with radius 20 pixel. create patch of size say 10 X 10, with center at (100,100) and find average value to R,G and B values in this patch.
for red R ~ 255 G ~0 and B~0
for green R ~ 0 G ~255 and B~0
for blue R ~0 G ~0 and B~255
Note: opencv stores value as BGR, not RGB
For finding the shape of a particular contour we can draw a bounded rectangle around the contour.
Now we can compare the area of contour with the area of bounded rectangle.
If area of contour is equal to half the area of bounded rectangle the shape is a triangle.
If the area of contour is less that area of bounded rectangle but is greater than half the area of bounded rectangle then its a circle.
Note: This method is limited to regular triangle and circle. this doesnt apply to polygons like hexagon,heptagon etc.

opencv in python: Is there a easy way to compute the curvature of a contour?

I know that you can easily compute the center of mass, and area of a contour using the moment of the contours. Is there a quick way to compute the curvature of a contour with opencv in python?
Thanks
In OpenCV,
a contour is a Numpy array of (x,y) coordinates of boundary points of
the object.
A method for computing the curvature is described for example in:
Driscoll MK, McCann C, Kopace R, Homan T, Fourkas JT, et al. (2012) "Cell Shape Dynamics: From Waves to Migration." PLoS Comput Biol 8(3): e1002392.
doi:10.1371/journal.pcbi.1002392
They have a contour composed by 400 points (they call them boundary points) and:
At each boundary point, we calculate the boundary curvature by fitting
a circle to that boundary point and the two points that are 10
boundary points away from it. The magnitude of the boundary curvature
is then defined as the reciprocal of the radius of that circle.
See also this video from the above paper.
I am not familiar with Python and so I cannot suggest you a function for circle interpolation; anyway in order to fit a circle to three points you can follow the formulae from (25) to (34) from Weisstein, Eric W. "Circle." From MathWorld--A Wolfram Web Resource.
Taken from https://math.stackexchange.com/a/1215914/10799
You can use the convexityDefects function described here. for python usage see this tutorial.

Is there a way to remove points from a contour outside a given circle in Python OpenCV?

Let's say I have a contour which is meant to represent the shape of the hand. The issue is, the contour also contains other parts of the arm (i.e. wrist, forearm, upper arm, etc.) To find the position of the hand's center, I'm looking at the combinations (size 3) of the defect points of the convex hull, finding the center of circle which is tangent to these 3 points, and averaging the most reasonable ones together to gain a rough understanding of where the hand's center is.
With this averaged center, I'd like to be able to remove points on my given contour which don't fall inside some radius that's likely to determine the width of the hand - in other words, cutoff points that don't fall inside this circle. I could simply iterate through each contour point and remove these points, but that would be horribly inefficient because of Python loops' speed. Is there a faster or more efficient way of doing this, perhaps using some inbuilt OpenCV functions or otherwise?
Thanks!
Interesting follow-up to your other question.
You can remove the unwanted points by boolean indexing:
import numpy as np
hand_contour = np.random.rand(60,2) # you can use np.squeeze on the data from opencv to get rid of that annoying singleton axis (60,1,2)->(60,2)
# You have found the center of the palm and a possible radius
center = np.array([.3, .1])
radius = .3
mask = (hand_contour[:,0] - center[0])**2 + (hand_contour[:,1] - center[1])**2 < radius**2
within_palm = hand_contour[mask,:] # Only selects those values within that circle.
You could also mask the unwanted values, with a masked_array, but if you're not interested in keeping the original data, the above method is the way to go.

Categories

Resources