前言
本文介绍一种在OpenCV中定义鼠标事件来进行对两条直线之间夹角的计算以及输出。
一、本文内容
利用OpenCV设置鼠标操作来进行测量角度,基本思路是通过定义鼠标事件得到三角形的三个点的坐标位置,通过我们熟知的余弦定理来进行对夹角的求解,大概程序分为以下部分:
1.加载图片
2.定义鼠标事件,鼠标按下左键后会在当前鼠标位置画下实心圆点。
3.绘制交线,我们通过鼠标点击3次后,会在屏幕中留下三个实心点,第一个圆点代表两条直线的交点,剩下两点分别代表两条线上任意一线,这样通过OpenCV自带绘制直线函数,将其画出。
4.求取角度,可以将这三个点看做是三角形的三个顶点,分别利用两点之间距离公式求出三角形的各个边长,再利用余弦定理进行角度的求解。
5.将求出的角度利用OpenCV.putText()函数在合适的位置在图片中打印出来。
本案例也在程序中加入循环条件,可以进行多次测量一张图片上的角度值。
二、使用步骤
1.代码及注释
代码及注释如下:
# 开发时间:2022/3/21 10:44
import cv2 as cv
import math
def mouse_event(event,x,y,flags,params): ##鼠标事件(看过一个视频,定义鼠标事件必须要协商这几个参数变量(我可以不用,但是必须有!!)(event事件名称,x坐标,y坐标,flags(我也没用过),params(这个也还不太清楚))))
global i ##将i设成全局变量,(line(37)注释只是交代了i存在的意义,并给i附初始值i=0,并没有进行对i变量全局化的操作)
if event==cv.EVENT_LBUTTONDOWN: ##如果鼠标左键按下:
cv.circle(img,(x,y),5,(0,0,255),-1) ##在当前坐标位置画一个实心圆,当做点0
pointslist.append((x,y)) ##并且把这个点添加进我们之前准备好的点坐标列表pointlist[]中
i+=1 ##i+1
#print(pointslist,i) ##输出当前坐标列表里面的坐标和列表里面点的个数i (这个是我测试程序时候用到的,可写可不写)
if event==cv.EVENT_MOUSEMOVE: ##(看过的那个视频还告诉我,鼠标事件还必须定义鼠标的移动事件)
pass ##(我没用到,就pass 带过了)
if event==cv.EVENT_LBUTTONUP: ##(看过的那个视频又告诉我,鼠标事件还必须定义鼠标的抬起事件)
pass ##(我还用到,又pass 带过了)
###我们依次点完三个点后(因为i=3了现在),程序就会跳转至line(37)行了!!
def printAngle():
global angle ##定义全局变量angle,为了下步输出用
c2=((pointslist[1][1]-pointslist[0][1])**2+(pointslist[1][0]-pointslist[0][0])**2) ##利用两点之间距离公式计算各边边长的平方
b2=((pointslist[2][1]-pointslist[0][1])**2+(pointslist[2][0]-pointslist[0][0])**2)
a2=((pointslist[2][1]-pointslist[1][1])**2+(pointslist[2][0]-pointslist[1][0])**2)
cosangle=(b2+c2-a2)/(2*math.sqrt(b2)*math.sqrt(c2)) ##余弦定理求夹角
angle=float(math.acos(cosangle)) ##将计算出的夹角强制转化为小数型,注意:此时得到的是弧度
angle=math.degrees(angle) ##这个函数是将弧度制转换为角度
angle = round(angle) ##取整数角度的部分
print(angle,"°") ##输出角度值
###输出角度值之后,程序继续执行至——→line(32)(printAngle()功能可以直接写在getAngle()功能里面,不用单独写出来,但是这样我比较习惯,看个人的思路了!!)
def getAngle():
cv.line(img, pointslist[0], pointslist[1], (0, 0, 255), 2, 8) ##画第一条直线,(由第一个点位到第二个点位)
cv.line(img, pointslist[0], pointslist[2], (0, 0, 255), 2, 8) ##画第一条直线,(由第一个点位到第二个点位)
printAngle() ##这里再去调用printAngle()(line(17)),去计算角度
cv.putText(img,str(angle)+"°",(pointslist[0][0]+30,pointslist[0][1]+30),cv.FONT_HERSHEY_DUPLEX,2,(0,0,255),2) ##在img图像中合适的地方输出角度值
###程序开始
img=cv.imread("E:/cvpicture/angle.jpg") ##加载图片
cv.namedWindow("img",0)
pointslist = [] ##初始化定义一个可以存放点坐标的列表
i=0 ##为了检测鼠标所画点的个数,需要有一个全局变量i来进行计数
while True:
cv.imshow("img", img) ##显示图片
cv.setMouseCallback("img",mouse_event) ##创建鼠标事件——→程序跳转到mouse_event()事件处(line4)
c=cv.waitKey(1) ##时刻等待鼠标操作
if i==3: ##若鼠左键已点击3次,说明这时已经存储完成我们所需要的3个点坐标
getAngle() ##当按下三次鼠标左键之后,(i=3),程序跳转至getAngle()功能——→line(28)
pointslist=[] ##待getAngle()功能结束后,我们已经完成了角度的标注,可以开始进行下一个角度的测量了,因此需要将已有点坐标列表进行清空
i =0 ##同理,也需要重新计算点的个数i
cv.imshow("img",img) ##以及继续加载图片
cv.destroyAllWindows() ##释放窗口
2.运行结果
总结
纯小白,第一次写文章,希望大家都会有一点收获!!