how could I find the area of the intersection of line and contour - python

the blue pen is the contour
and the red pen is the straight line
how could I find the two areas of the intersection of line and contour
Now, I can get the contour area by
area = cv2.contourArea(np.array( [ [i] for i in blue_points ] ))

A simple but perhaps not the most efficient way would be to use cv.drawContours and cv.line to create two images: one with the contour of the blob and one with the contour of the line. Then cv.bitwise_and them together, and any point that is still positive will be points of intersection.

Shapely library makes it quick.
Assuming you have points of contour and line:
from shapely.geometry import Polygon, LineString
poly = Polygon([(5,5), (10,10), (10,0)])
a = LineString([(0, 0), (8, 8)])
print(a.intersects(poly))
There are options to speed up the code. Not checked.

Related

Approximate 4 circles inside ellipse to get the radii

I need the approximate radii of the following ellipse.
The bottom/top and left/right radii should be the same nevertheless need to be checked. Which means 4 radii should be the result of my code. I did the following in paint, the green circle should give me the top radius and red the left (the right and bottom one aren't drawn here).
The idea I'm working on is to crop the image (left/right/top/bottom side) and approximate circles to the cropped images. With the cv2.findContours-feature some white pixels get recognized as highlighted here.
Is there a way to approximate my drawn red circle from above with these given coordinates? The problems I've seen on the internet are all with a given center point or angle which I don't have. Is there a cv2 function that draws circles with only some given coordinates or something similar?
Use this function : cv2.fitEllipse(points) and pass contour points -Ziri
Yes this did the trick. I got the radii after your function with:
(x, y), radius = cv2.minEnclosingCircle(i)

Open CV Contours - Splitting concave polygon into multiple convex ones

I have the below image in a numpy array
I want to
separate the blocks into individual contours or any coordinate representation.
I then want to transform any concave polygons into multiple convex polygons.
Like this
So far I've managed to isolate each block into contours with opencv... but is there an easy way to split the L shape objects into two or more square blocks. The new contours of each shape can overlap if needed.
It may also be the case that I have an Image like this which does not have such straight lines.
I have used cv2.approxPolyDP to draw the shape, but again they are concave and I need them splitting.
Any help appreciated.
One way I can think of is, for each contour, find it convex hull first.See this link
Now find the defect points between contour and its convex hull. See this link
Now using the data of defects distance, find the point with maximum distance. This point will be the points where the 2 objects are joined in L shape. Now from this point, draw a perpendicular line to the contour tangent at that point, and again find contours. The resultant contours will be the 2 contours for the L shape.
Note: In this approach, it is possible that some part of one object comes in other while dividing them at the boundary.
Ok so thanks Rahul for your answer.
I ended up finding a package that helped me trangulate the polygons which solved my issue.
download with :
pip install sect
Then :
from sect.triangulation import constrained_delaunay_triangles
Take the contours generated by openCV - this generates them as below.
Then "smooth" the colours so there are less of them. I've used this
epsilon = 0.005 * cv2.arcLength(contour, True)
approx = cv2.approxPolyDP(contour, epsilon, True)
then run it through sect
constrained_delaunay_triangles([tuple(x) for x in approx.squeeze()])
The output splits the polygons into triangles removing ALL concave polygons totally.

Python: Return position and size of arbitrary/teeth shapes in image using OpenCV

I'm very new to the image processing and object detection. I'd like to extract/identify the position and dimensions of teeth in the following image:
Here's what I've tried so far using OpenCV:
import cv2
import numpy as np
planets = cv2.imread('model.png', 0)
canny = cv2.Canny(planets, 70, 150)
circles = cv2.HoughCircles(canny,cv2.HOUGH_GRADIENT,1,40, param1=10,param2=16,minRadius=10,maxRadius=80)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(planets,(i[0],i[1]),i[2],(255,0,0),2)
# draw the center of the circle
cv2.circle(planets,(i[0],i[1]),2,(255,0,0),3)
cv2.imshow("HoughCirlces", planets)
cv2.waitKey()
cv2.destroyAllWindows()
This is what I get after applying canny filter:
This is the final result:
I don't know where to go from here. I'd like to get all of the teeth identified. How can I do that?
I'd really appreciate any help..
Note that the teeth-structure is more-or-less a parabola (upside-down). If you could somehow guess the parabolic shape that defines the centroids of those blobs (teeth), then your problem could be simplified to a reasonable extent. I have shown a red line that passes through the centers of the teeth.
I would suggest you to approach it as follows:
Binarize your image (background=0, else 1). You could use sklearn.preprocessing.binarize.
Calculate the centroid of all the non-zero pixels. This is the central blue circle in the image. Call this structure_centroid. See this: How to center the nonzero values within 2D numpy array?.
Make polar slices of the entire image, centered at the location of the structure_centroid. I have shown a cartoon image of such polar slices (triangular semi-transparent). Cover complete 360 degrees. See this: polarTransform library.
Determine the position of the centroid of the non-zero pixels for each of these polar slices. See these:
find the distance between a point and a curve python.
Find the minimum distance from a point to a curve.
The array containing these centroids gives you the locus (path) of the average location of the teeth. Call this centroid_path.
Run an elimination/selection algorithm on the circles you were able to detect, that are closest to the centroid_path. Use a threshold distance to drop the outliers.
This should give you a good approximation of the teeth with the circles.
I hope this helps.

opencv - Polyline and rectangle intersection

I would like to get if a polyline and rectangle intersect on opencv+Python:
A = cv2.rectangle(frame,(384,0),(510,128),(0,255,0),3)
pts = np.array([[1300,900],[1750,700],[1000,200],[600,200]], np.int32)
pts = pts.reshape((-1,1,2))
B = cv2.polylines(frame,[pts],True,(244,66,66),7)
How can I find if A intersect with B?
Thank you
Opencv and Numpy don't have direct geometry intersection functions.
You can write your own (see Numpy and line intersections) or a common technique is to draw the rectangle filled with a color and then check if the points along the line on the same image are that color.

How to draw a line from two points and then let the line complete drawing until reaching a contour point with opencv, python?

I am using opencv and python for programming and I am trying to draw a line between two points that I know their coordinates, and then let the line complete until it reaches the end of the contour as shown in the image bellow. The contour in my case is actually of an image face, but I have provided a circle here for explanation. So what I am trying to achieve is to get the edge of the head at that point intersecting with the line and contour. Is there a way to draw a line from two points and then let the line complete drawing until reaching the contour?
I can think of one easy method off the top of my head that doesn't involve incrementally updating the image: on one blank image, draw a long line extending from point one in the direction of point two, and then AND the resulting image with the an image of the single contour drawn (filled). This will stop the line at the end of the contour. Then you can either use that mask to draw the line, or get the minimum/maximum x, y coords if you want the coordinates of the line.
To walk through an example, first we'll find the contour and draw it on a blank image:
contours = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)[1]
contour_img = np.zeros_like(img)
cv2.fillPoly(contour_img, contours, 255)
Then, if we have the points p1 and p2, find the direction they're heading in and find a point far off in that distance and draw that line on a new blank image (here I used a distance of 1000 pixels from p1):
p1 = (250, 250)
p2 = (235, 210)
theta = np.arctan2(p1[1]-p2[1], p1[0]-p2[0])
endpt_x = int(p1[0] - 1000*np.cos(theta))
endpt_y = int(p1[1] - 1000*np.sin(theta))
line_img = np.zeros_like(img)
cv2.line(line_img, (p1[0], p1[1]), (endpt_x, endpt_y), 255, 2)
Then simply cv2.bitwise_and() the two images together
contour_line_img = cv2.bitwise_and(line_img, contour_img)
Here is an image showing the points, the line extending past the contour, and the line breaking off at the contour.
Edit: Note that this will only work if your contours are convex. If there is any concavity and the line goes through that concave part, it will continue to draw on the other side of it. For e.g. in Silencer's answer, if both points were inside one of the ear and pointed towards the other ear, you'd want the contour to stop once it hit an edge, but mine will continue to draw on the other ear. I think an iterative method like Silencer's is the best for the general case, but I like the simplicity of this method if you know you have convex contours or if your points will be in a place to not have this issue.
Edit2: Someone else on Stack answered their own question about the Line Iterator class in Python by creating one: openCV 3.0 python LineIterator

Categories