<p>因为你有点(作为一个numpy数组)并且你想要角度(<em>符号</em>角度),这里有一个完整的解决方案</p>
<ul>
<li>计算<em>向量</em></li>
<li>使用<em>交叉乘积</em>:<img src="https://i.stack.imgur.com/mXqyw.png" alt="cross product"/></li>
</ul>
<p>这将使用整个数组操作</p>
<p><em>注意</em>Yves Daoust在评论中的非常有效的评论。此演示无法正确处理锐角,但可以通过额外的向量检查和角度校正来处理锐角</p>
<pre class="lang-py prettyprint-override"><code>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))]))
</code></pre>
<pre><code>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]]
</code></pre>
<p>一些图纸:</p>
<pre class="lang-py prettyprint-override"><code>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")
</code></pre>
<p><a href="https://i.stack.imgur.com/cbR1V.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/cbR1V.png" alt="drawing"/></a></p>