Reputation:
I have the following array of arrays:
[[[623 284]]
[[526 256]]
[[532 189]]
[[504 166]]
[[323 175]]
[[276 219]]
[[119 221]]
[[ 1 272]]
[[ 0 473]]
[[615 479]]]
These are my points (coordinates) of polygon. What I need to do, is to iterate through this array, taking each point for calculating every inner angle in polygon. I have this function for calculating angle between 3 points: getAngle((px1, py1), (px2, py2), (px3, py3))
.
Basically I want to put this function in some loop which will take points repectively, like:
getAngle((623, 284), (526, 256), (532, 189)),
getAngle((526, 256), (532, 189), (504, 166)),
getAngle((532, 189), (504, 166), (323, 175)),
and so on until the end... Which loop it suppose to be and how to implement it?
Upvotes: 0
Views: 1431
Reputation:
What about a simple
for i in range(len(A) - 2):
getAngle(A[0][i], A[0][i+1], A[0][i+2])
Erratum:
for i in range(len(A) - 2):
getAngle(A[i][0], A[i+1][0], A[i+2][0])
Upvotes: 1
Reputation: 15354
Since you have points (as a numpy array) and you want angles (signed angles), here's a complete solution.
This uses whole-array operations.
Note the very valid remark by Yves Daoust in the comments. Acute angles aren't handled properly by this demonstration but they can be with an additional check of the vectors and correction to the angle.
import numpy as np
points = np.array([
[[623, 284]],
[[526, 256]],
[[532, 189]],
[[504, 166]],
[[323, 175]],
[[276, 219]],
[[119, 221]],
[[ 1, 272]],
[[ 0, 473]],
[[615, 479]]])
# funny shape because OpenCV. it's a Nx1 vector of 2-channel elements
# fix that up, remove the silly dimension
points.shape = (-1, 2)
# the vectors are differences of coordinates
# a points into the point, b out of the point
a = points - np.roll(points, 1, axis=0)
b = np.roll(a, -1, axis=0) # same but shifted
# we'll need to know the length of those vectors
alengths = np.linalg.norm(a, axis=1)
blengths = np.linalg.norm(b, axis=1)
# we need only the length of the cross product,
# and we work in 2D space anyway (not 3D),
# so the cross product can't result in a vector, just its z-component
crossproducts = np.cross(a, b) / alengths / blengths
angles = np.arcsin(crossproducts)
angles_degrees = angles / np.pi * 180
print("angles in degrees:")
print(angles_degrees)
# this is just for printing/displaying, not useful in code
print("point and angle:")
print(np.hstack([points, angles_degrees.reshape((-1, 1))]))
angles in degrees:
[-76.24798 79.01601 -55.71665 -42.24728 -40.2652 42.38197 -22.64432 -66.34078 -89.72609 -88.20969]
point and angle:
[[623. 284. -76.24798]
[526. 256. 79.01601]
[532. 189. -55.71665]
[504. 166. -42.24728]
[323. 175. -40.2652 ]
[276. 219. 42.38197]
[119. 221. -22.64432]
[ 1. 272. -66.34078]
[ 0. 473. -89.72609]
[615. 479. -88.20969]]
some drawing:
import cv2 as cv
canvas = np.zeros((600, 700, 3)) # floats, range 0..1
cv.polylines(canvas, [points], isClosed=True, color=(1,1,1))
for i,angle in enumerate(angles_degrees):
cv.circle(canvas, center=tuple(points[i]), radius=5, color=(0,0,1), thickness=cv.FILLED)
cv.putText(
canvas,
f"{angle:+.1f}",
org=tuple(points[i]),
fontFace=cv.FONT_HERSHEY_SIMPLEX,
fontScale=0.75,
color=(0,1,1),
thickness=2)
cv.imshow("canvas", canvas)
cv.waitKey(-1)
cv.destroyWindow("canvas")
Upvotes: 2
Reputation: 24049
try this:
lst = [[[623,284]] , [[526, 256]] , [[532, 189]]]
tuple(map((lambda x : tuple(x[0])), lst))
output:
((623, 284), (526, 256), (532, 189))
EDIT as your comment:
lst = [[[623,284]], [[526, 256]], [[532, 189]], [[504, 166]], [[323, 175]], [[276, 219]], [[119, 221]], [[ 1, 272]], [[ 0, 473]] , [[615, 479]]]
for l in range(0,len(lst)-2):
f , s , t = (tuple(map((lambda x : tuple(x[0])), lst[l:l+3])))
getAngle(f , s, t)
Upvotes: -2
Reputation: 13626
more_itertools
is a good library for stuff like this:
import more_itertools
points = [[623,284], [526, 256], [532, 189], [504, 166], [323, 175], [276, 219], [119, 221], [ 1, 272], [ 0, 473]]
for triplet in more_itertools.windowed(points, n=3, step=3):
getAngle(*triplet)
Upvotes: 0