How can I mirror a polygon using Python? - python

I have a set of images over which polygons are drawn. I have the points of those polygons and I draw these using Shapely and check whether certain points from an eye tracker fall into the polygons.
Now, some of those images are mirrored but I do not have the coordinates of the polygons drawn in them. How can I flip the polygons horizontally? Is there a way to do this with Shapely?

if you want to reflect a polygon with respect to a vertical axis, i.e., to flip them horizontally, one option would be to use the scale transformation (using negative unit scaling factor) provided by shapely.affinity or to use a custom transformation:
from shapely.affinity import scale
from shapely.ops import transform
from shapely.geometry import Polygon
def reflection(x0):
return lambda x, y: (2*x0 - x, y)
P = Polygon([[0, 0], [1, 1], [1, 2], [0, 1]])
print(P)
#POLYGON ((0 0, 1 1, 1 2, 0 1, 0 0))
Q1 = scale(P, xfact = -1, origin = (1, 0))
Q2 = transform(reflection(1), P)
print(Q1)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))
print(Q2)
#POLYGON ((2 0, 1 1, 1 2, 2 1, 2 0))

by multiplying [[1,0], [0,-1]], You can get the vertically flipped shape. (I tested this on jupyter notebook)
pts = np.array([[153, 347],
[161, 323],
[179, 305],
[195, 315],
[184, 331],
[177, 357]])
display(Polygon(pts))
display(Polygon(pts.dot([[1,0],[0,-1]])))
And If you multiply [[-1,0],[0,1]], you will get horizontally flipped shape.
Refer linear transformation to understand why this works.

Related

How to draw 2.5d polygon on 3d GLViewWidget

I want to add polygons to the GLViewWidget of the PyQtGraph library. I have an array of dots, i.e:
vertexes = [[1, 0, 0],
[1, 1, 1],
.........
]
So, it is not a 3d polygon, it is a flat polygon with z coordinates (2.5d).
I thought about triangulation, but I got 3d polygons:
vertices = np.array(points)
d = spatial.Delaunay(vertices)
md = gl.MeshData(vertexes=points, faces=d.simplices)
m1 = gl.GLMeshItem(meshdata=md,
smooth=False,
shader='myShader')
But it looks really strange:
How can I draw 2.5d polygons on GLViewWidget?
I drew lines, and that looks good, but I want to fill it:
vertices = np.array(points)
for i in range(0, len(vertices) - 1):
glLine = gl.GLLinePlotItem(pos=[np.array([vertices[i][0], vertices[i][1], vertices[i][2]]),
np.array([vertices[i+1][0], vertices[i+1][1], vertices[i+1][2]])])
self.glvw.addItem(glLine)

GL_LINES isn't drawn properly around GL_QUADS (possible z-fight?)

I have three basic functions that draw a surface, the first one is drawing the surface;
def deflected_3d_surface(self, array):
glBegin(GL_QUADS)
for d in range(int(array.shape[0] / 2 - 1)):
glColor4f(1, 1, 1, 1)
glVertex3fv(array[2 * d + 2, :])
glVertex3fv(array[2 * d, :])
glVertex3fv(array[2 * d + 1, :])
glVertex3fv(array[2 * d + 3, :])
glEnd()
the second one drawing the outer edges of that surface;
def deflected_3d_edges(self, array2):
glBegin(GL_LINES)
for i in range(array2.shape[0] - 1):
glColor3fv((0, 0, 0))
glVertex3fv(array2[i, :])
glVertex3fv(array2[i + 1, :])
glEnd()
the third one is drawing lines on that surface; (note that the line vertices and the surface vertices are not the same)
def deflected_3d_inner_edges(self, x_array, y_array, z_array):
glBegin(GL_LINES)
for i in range(x_array.shape[0]):
glColor3fv((0, 0, 0))
glVertex3fv([x_array[i, 0], y_array[i, 0], z_array[i, 0]])
glVertex3fv([x_array[i, 1], y_array[i, 1], z_array[i, 1]])
if x_array.shape[1] != 2:
glVertex3fv([x_array[i, 1], y_array[i, 1], z_array[i, 1]])
glVertex3fv([x_array[i, 2], y_array[i, 2], z_array[i, 2]])
glEnd()
When I call these functions with the following order;
`glWidget.deflected_3d_edges(self, self.tf1_edges_array)
glWidget.deflected_3d_edges(self, self.tf2_edges_array)
glWidget.deflected_3d_edges(self, self.bf1_edges_array)
glWidget.deflected_3d_edges(self, self.bf2_edges_array)
glWidget.deflected_3d_inner_edges(self, self.xbcr_, self.ybcr_,
self.zbcr_)
glWidget.deflected_3d_inner_edges(self, self.xwcr_, self.ywcr_,
self.zwcr_)
glWidget.deflected_3d_inner_edges(self, self.xtcr_, self.ytcr_,
self.ztcr_)`
Any ideas how I can fix the black lines appearing on the white surface?
When a fragment (think of it as a pixel) is going to be set in the frame buffer FB (previous step to the window) OpenGL compares its Z-coordinate with the current one for the same X,Y NDC coordinates (those of the FB).
By default, if the incomming Z is less than the current one (it's nearer to the camera), then it wins and it replaces the old color in the FB. This way, a fragment behind another one is discarded.
When to fragments have a similar Z-coordinate, it's not clear who gets ahead. Sometimes, due to numerical float imprecisions, the nearest fragment "loses" and wrongly gets discarded. This is called "z-fighting".
If you want to see something, despite it's at the front or the back of other primitive, you can change the glDepthFunc to GL_ALWAYS.
So:
Draw your surface
Set glDepthFunc(GL_ALWAYS)
Draw your always-seen objects
Restore glDepthFunc to normal 'GL_LESS`

Why PIL draw polygon does not accept numpy array?

This code works as expected:
import numpy as np
from PIL import Image, ImageDraw
A = (
( 2, 2),
( 2, 302),
( 302, 302),
( 302, 2)
)
img = Image.new('L', (310, 310), 0)
ImageDraw.Draw(img).polygon(A, outline=1, fill=1)
mask = np.array(img)
print(mask)
However, if the A matrix is provided as numpy array:
A = np.array(
[[ 2, 2],
[ 2, 302],
[302, 302],
[302, 2]], dtype="int32"
)
it produces completely wrong result. I also try to flatten the A array, it does not help.
Do I miss something? Can I stuff the numpy array somehow directly into PIL?
If call-interaface says use a list-of-tuples or a list of interleaved values,
best use a list-of-tuples or a sequence / list of interleaved values:
PIL.ImageDraw.ImageDraw.polygon( xy, fill = None, outline = None )
Draws a polygon.
The polygon outline consists of straight lines between the given coordinates, plus a straight line between the last and the first coordinate.
xy – Sequence of either 2-tuples like [(x, y), (x, y), ...]ornumeric values like [x, y, x, y, ...].
Can I stuff ..
Using
>>> xy
array([[ 2, 3],
[10, 3],
[10, 0],
[ 2, 0]])
>>> xy.flatten().tolist()
[ 2, 3, 10, 3, 10, 0, 2, 0 ]
>>>
shall work and meet the PIL-documented-Call-Interface for ImageDraw.polygon()

List all faces for all edges

A very simple question:
how to compute efficiently in Python (or Cython) the following quantity.
Given the list of polygons in 3D (polygon
There is a list of polygons given in the following form:
vertex = np.array([[0, 0, 0], [0, 0, 1], [0, 1, 0],[1, 0, 0],[0.5, 0.5, 0.5]], order = 'F').T
polygons = np.array([3, 0, 1, 2, 4, 1, 2, 3 ,4])
i.e. polygon is a 1D array, which contains entries of the form [N,i1,i2,i3,i4,...],
N is the number of vertices in a polygons and then the id numbers of the vertices in the vertex array (in the example above there is one triangle with 3 vertices [0,1,2] and one polygon with 4 vertices [1,2,3,4]
I need to compute the information: a list of all edges and for each edge the information
which faces contain this edge.
And I need to do it fast: the number of vertices can be large.
Update
The polygon is closed, i.e. a polygon [4, 0, 1, 5, 7] means that there are 4 vertices and edges are 0-1, 1-5, 5-7, 7-0
The face is a synonim to polygon in fact.
Dunno if this is the fastest option, most probably not, but it works. I think the slowest part is edges.index((v, polygon[i + 1])) where we have to find if this edge is already in list. Vertex array is not really needed since edge is a pair of vertex indexes. I used face_index as a reference to polygon index since you didn't write what face is.
vertex = [[0,0,0], [0,0,1], [0,1,0],[1,0,0],[0.5,0.5,0.5]]
polygons = [3,0,1,2,4,1,2,3,4]
_polygons = polygons
edges = []
faces = []
face_index = 0
while _polygons:
polygon = _polygons[1:_polygons[0] + 1]
polygon.append(polygon[0])
_polygons = _polygons[_polygons[0] + 1:]
for i, v in enumerate(polygon[0:-1]):
if not (v, polygon[i + 1]) in edges:
edges.append((v, polygon[i + 1]))
faces.append([face_index, ])
else:
faces[edges.index((v, polygon[i + 1]))].append(face_index)
face_index += 1
edges = map(lambda edge, face: (edge, face), edges, faces)
print edges
<<< [((0, 1), [0]), ((1, 2), [0, 1]), ((2, 0), [0]), ((2, 3), [1]), ((3, 4), [1]), ((4, 1), [1])]
You can make it faster by removing line polygon.append(polygon[0]) and append first vertice of polygon to vertices list in polygon manually, which shouldn't be a problem.
I mean change polygons = [3,0,1,2,4,1,2,3,4] into polygons = [3,0,1,2,0,4,1,2,3,4,1].
PS Try to use PEP8. It is a code typing style. It says that you should put a space after every comma in iterables so it's eaasier to read.

Rotate small portion of an array by 90 degrees

I want to rotate an array but not as a whole, only small portion of it.
I have 512X512 array (basically it is a Gaussian circle at the center (150,150) with 200 radius). Now I want to rotate only small portion (center around (150,150) with radius 100) of the array by 90 degree. Initially I used numpy rot90 module but it rotate each array element which is not I want.
If you can describe the elements that you would like rotated using advanced indexing, then you should be able to perform the rotation using something like the following (assuming your array is called arr):
arr[rs:re,cs:ce] = np.rot90(np.copy(arr[rs:re,cs:ce]))
Here rs, re, cs, and ce would signify the row-start and row-end of a slice, and the column-start and column-end of a slice, respectively.
Here is an example of why the np.copy call is necessary (at least in numpy 1.3.0):
>>> import numpy as np
>>> m = np.array([[i]*4 for i in range(4)])
>>> m
array([[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3]])
>>> m[1:3,1:3] = np.rot90(m[1:3,1:3]) # rotate middle 2x2
>>> m
array([[0, 0, 0, 0],
[1, 1, 2, 1], # got 1, 2 expected 1, 2
[2, 1, 1, 2], # 1, 1 1, 2
[3, 3, 3, 3]])
Here is some fuller code that does as F.J. has already explained.
And here is the code:
import numpy as np
import scipy
def circle(im, centre_x, centre_y, radius):
grid_x, grid_y = np.mgrid[0:im.shape[0],0:im.shape[1]]
return (grid_x-centre_x)**2 + (grid_y-centre_y)**2 < radius**2
centre_x, centre_y, radius = 150, 200, 100
x_slice = slice(centre_x - radius, centre_x + radius)
y_slice = slice(centre_y - radius, centre_y + radius)
im = scipy.misc.imread('1_tree.jpg')
rotated_square = np.rot90(im[x_slice,y_slice].copy())
im[circle(im, centre_x, centre_y,radius)] = rotated_square[circle(rotated_square,
radius, radius, radius)]
scipy.misc.imsave('sdffs.png',im)

Categories

Resources