通过在打开的图片中使用鼠标选取角的三个点,然后计算其角度并且标记在图片中
# 读取图片,返回numpy.ndarray对象
img = cv2.imread("image_path")
# 图片显示, 显示与操作的窗口
cv2.imshow("win_name", img)
# 鼠标事件监听
cv2.setMouseCallback("win_name", calback_function)
# 绘制直线
cv2.line(img, point1, point2, color, thickness=None)
# 绘制点
cv2.circle(img, center, radius, color, thickness=None, lineType=None, shift=None)
from cv2 import cv2
import math
win_name = "measuring angle"
img_path = "angle.jpg"
img = cv2.imread(img_path)
img_cp = img.copy() # 拷贝一份数据
points = [] # 存储选择的点
def mouse_point(event, x, y, *args):
"""
鼠标左键点击事件回调函数
:param event:
:param x:
:param y: y 是图片上到下的方向的坐标轴,不是常规的坐标,
相当于对常规坐标沿X周做了翻转,但是对于角度来说,做翻转不会影响角度大小,所以坐标不需要转换。
:param args: flags, params
:return:
"""
thickness = 2
color = (0, 0, 255)
# print("args", args)
if event == cv2.EVENT_LBUTTONDOWN:
cv2.circle(img, (x, y), 2, (0, 0, 255),
thickness=thickness) # circle(img, center, radius, color, thickness=None, lineType=None, shift=None)
points.append((x, y))
print(x, y)
# 计算角度
if points and len(points) % 3 == 0: # 每三个点组成一个角度
o_point = points[-2] # 角顶点
a = get_angle_by_cos(*points[-3:])
angle = round(math.degrees(a), 2)
print(f"弧度:{a}, 角度:{angle}")
# 绘制角的边
cv2.line(img, o_point, points[-1], color,
thickness=thickness) # def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
# def line(img, pt1, pt2, color, thickness=None, lineType=None, shift=None)
cv2.line(img, o_point, points[-3], color, thickness=thickness)
mark_point = o_point[0] + 20, o_point[1] - 10
# 绘制角度值到图片中
cv2.putText(img, str(angle), mark_point, cv2.FONT_HERSHEY_COMPLEX, 0.6, color)
def get_angle_by_cos(p0, p1, p2):
"""
使用向量的点乘公式计算角度值
:param p0:
:param p1: 角的顶点
:param p2:
:return: 弧度
"""
# print(p0, p1, p2)
l1 = p0[0] - p1[0], p0[1] - p1[1]
l2 = p2[0] - p1[0], p2[1] - p1[1]
# print(l1, l2)
m = math.sqrt(l1[0] ** 2 + l1[1] ** 2) * math.sqrt(l2[0] ** 2 + l2[1] ** 2)
if m == 0:
return 0
cos = (l1[0] * l2[0] + l1[1] * l2[1]) / m
# print(cos)
return math.acos(cos)
def window():
# 函数对全局变量赋值,需要使用 global关键字
global img
global points
while True:
cv2.imshow(win_name, img)
cv2.setMouseCallback(win_name, mouse_point)
if (cv2.waitKey(1) & 0xFF) == ord("q"): # cv2.waitKey(1) & 0xFF 是为了截取低8位,不用也可以
# 键盘输入 q时 保存当前图片以及刷新图片为初始图片
# if cv2.waitKey(1) == ord("q"):
points = []
cv2.imwrite("measuring.jpg", img)
# img = cv2.imread(img_path) # 重新载入图片
img = img_cp.copy() # 重新载入图片
if __name__ == "__main__":
window()