OpenCV利用鼠标操作测量角度


前言

本文介绍一种在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.运行结果

​​​​​​​

 

总结

        纯小白,第一次写文章,希望大家都会有一点收获!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值