How do I find the smallest surrounding rectangle of a set of 2D points in Shapely? - python

How do I find the msmallest surrounding rectangle (which is possibly rotated) of a set of 2D points in Shapely?

To create the smallest surrounding rectangle in Shapely, first construct a MultiPoint from a sequence of points then use the minimum_rotated_rectangle property (which is in the BaseGeometry class).
from shapely.geometry import MultiPoint, Polygon
points = [(0, 0), (2, 2), (10, 4), (5, 5), (8, 8)]
# create a minimum rotated rectangle containing all the points
polygon = MultiPoint(points).minimum_rotated_rectangle
print(polygon)
Output:
POLYGON ((2.9999999999999996 -2.9999999999999996, 10.999999999999998 4.999999999999998, ...
The example set of points are displayed below in red and the bounding box is in blue.
If want to create an envelope around the points which is the smallest rectangle (with sides parallel to the coordinate axes) containing all the points then can call the envelope property on the object.
polygon = MultiPoint(points).envelope

Related

Map corresponding points between Delaunay triangles

I'm trying to morph two images of faces using an inverse warp. I have the Delaunay triangles for both images as well as all transformation matrices for all pairs of corresponding triangles.
I have applied the matrix to every pixel inside the triangles, but the image I am getting is all messed up and some pixels aren't being filled in as well.
I suspect the vertices lists are not in order which means the triangles are not corresponding. Or it could just be me messing up the row, cols order.
Here's my code:
from scipy.spatial import Delaunay
from skimage.draw import polygon
import numpy as np
def drawDelaunay(img, landmarks, color):
tri = Delaunay(landmarks)
vertices = []
for t in landmarks[tri.simplices]:
# t = [int(i) for i in t]
pt1 = [t[0][0], t[0][1]]
pt2 = [t[1][0], t[1][1]]
pt3 = [t[2][0], t[2][1]]
cv2.line(img, pt1, pt2, color, 1, cv2.LINE_AA, 0)
cv2.line(img, pt2, pt3, color, 1, cv2.LINE_AA, 0)
cv2.line(img, pt3, pt1, color, 1, cv2.LINE_AA, 0)
vertices.append([pt1, pt2, pt3])
return img, vertices
def getAffineMat(triangle1, triangle2):
x = np.transpose(np.matrix([*triangle1]))
y = np.transpose(np.matrix([*triangle2]))
# Add ones to bottom of x and y
x = np.vstack((x, [1,1,1]))
y = np.vstack((y, [1,1,1]))
xInv = np.linalg.pinv(x)
return np.dot(y, xInv)
srcImg = face2
srcRows, srcCols, srcDepth = face2.shape
destImg = np.zeros(face1.shape, dtype=np.uint8)
for triangle1, triangle2 in zip(vertices1, vertices2):
transMat = getAffineMat(triangle1, triangle2)
r, c = list(map(list, zip(*triangle2)))
rr, cc = polygon(r, c)
for row, col in zip(rr, cc):
transformed = np.dot(transMat, [col, row, 1])
srcX, srcY, *_ = np.array(transformed.T)
# Check if pixel is within image boundaries
if isWithinBounds(srcCols, srcRows, col, row):
# Interpolate the color of the pixel from the four nearest pixels
color = bilinearInterpolation(srcImg, srcX, srcY)
# Set the color of the current pixel in the destination image
destImg[row, col] = color
I wish to implement this without getAffineTransform or warpAffine. Any help would be much appreciated!
Sources:
Transfer coordinates from one triangle to another triangle
https://devendrapratapyadav.github.io/FaceMorphing/
But you don't have corresponding triangles! This looks like 2 separates Delaunay triangulation. Maybe made on matching points, but still no matching triangles. You can't do two Delaunay triangulation, one in each image, and expect them to match. You need 1 delaunay triangulation, and then use the same edges on both sides (so, for at least one side, triangulation will not be exactly Delaunay).
Look for example at the top-right corner of your images.
On one side you have you have 4 outgoing edges (counting those we can't see because they are confused with te image border, but they have to be there), on the other you have 6 outgoing edges.
The number of edges connected to two matching vertices is supposed to be a constant (otherwise, how could you warp anything?).
So, clearly, I think (but you did not provide any code, for that, since you postulate that triangulation is correct, when I am pretty sure it is triangulation that is not. So I can only surmise), you got a two sets of matching points, then performed 2 Delaunay's triangulation on those 2 sets of points, expecting to be able to match triangles, even tho they are not at all the same triangles.
Edit: how to transform
(in reply to your question in comment)
It's the same triangulations. You have a list of points p₁, p₂, p₃, ..., pₙ in the first images. A matching list of points q₁, q₂, q₃, ..., qₙ in the second image. You perform a triangulation in the 1st image. Whose output should be a list of triplets of indices, such as (1,3,4), (1, 2, 3), ... meaning that optimal triangulation in 1st image is the one made of triangle (p₁,p₃, p₄), (p₁, p₂, p₃), ...
And in the second image, you use triangulation (q₁,q₃,q₄), (q₁, q₂, q₃), ...
Even if it is not the optimal triangulation of q₁,q₂,...,qₙ (the one that maximize smallest angle). It should not be that far, if q₁,q₂,...,qₙ are not that different from p₁,p₂,...,pₙ (which they are not supposed to be, if you tried to match consistently both images).
So, transformation matrices are the one transforming coordinates in each matching triangles (there are one transformation for each pair of matching triangles).
To decide which point (x',y') of second image matches point (x,y) of first image, you need
to identify in which triangle (i,j,k) (that is (pᵢ,pⱼ,pₖ)) (x,y) is,
Find barycentric coordinates of (x,y) inside this triangle: (x,y)=αpᵢ+βpⱼ+γpₖ
Assume that (x',y') have the same barycentric coordinates inside the matching triangle, that is (x',y')=αqᵢ+βqⱼ+γqₖ
Transformation matrix (for triangle (i,j,k)) is the one going from (x,y) to (x',y')

How to count number of points inside a circle

I got this plot and I want to divide this plot into many different circles and need how many points in each circle.
I am trying to plot radius of the circle with how many number of points inside the circle.
Intuition:- Finding the distance between two points. (i.e sqrt((x2-x1)**2+(y2-y1)**2)) [Euclidean Formula]
If Distance>Radius than point is outside the circle
If Distance=Radius than point is on the circle
If Distance<Radius than point is inside the circle
Code:-
import math
# Lets say the circle points are x=2 y=3
x,y=2,3
# Radius of a Circle radius=4
radius=4
# Given points to check -:
lis=[(-1,1),(4,3),(5,4),(9,10),(1,2),(2,7)]
res=[]
for x1,y1 in lis: # x1,y1 points to check is it inside or not
if math.sqrt((x1-x)**2+(y1-y)**2)<radius: #Note use "<=radius" if you want point which is on the circle also
res.append((x1,y1))
print(res) #The points which are inside in the circle
Output:-
[(-1, 1), (4, 3), (5, 4), (1, 2)]

How to warp an image using a mesh in Python?

I want to warp an image using a mesh, the mesh is an array of shape WxHx2. I have two channels: one for x and the other for y, they tell us how much distortion in that zone we will have.
If I create a grid with that distortion it is something like this:
Now I want to interpolate an image using this grid. If the distortion is beyond the image size it will be cut.
I have tried with ImageOps.deform and Image.Image.transform but I can't get it to work.
With ImageOps we need to create a deformer object like:
class SingleDeformer:
def getmesh(self, img):
#Map a target rectangle onto a source quad
return [(
# target rectangle
(20, 10, 30, 20),
# corresponding source quadrilateral
(0, 0, 0, 10, 10, 20, 10, 0)
)]
The target needs two points (x1,y1) and (x2,y2) and in this case I would need the target to be four points (x,y) as the source quadrilateral which requires to be:
Top left
Bottom left
Bottom right
Top right
I can have the four source as quadrilateral but the target is not a a square, maybe I'm missing something, any help is appreciated.

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

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.

Plotting heatmaps in python

I am using heatmap.py to plot a heatmap on python. I read on the doc (same page in the details section) that 'points' is "an iteratable list of tuples, where the contents are the
| x,y coordinates to plot. e.g., [(1, 1), (2, 2), (3, 3)]"
Therefore, we can specify the points (x,y) to color, but how is it possible to specify the intensity of each point (x,y)?
You do not directly specify the intensity, it is inferred from the number of points you place at any given coordinates. From the documentation:
The dot is placed into the output image for each input point at the translated output image coordinate. […] Dots are blended into the output image with an additive process: as points are placed on top of each other, they become darker. After all input points have been blended into the output image, the ouput image is colored based on the darkness of each pixel.
It seems you can make an area of the heat map more intense by adding more points the lie in that area.

Categories