Angle Finder(角度测量)

目录

一 前言

二 实现步骤

1 需要的第三方库

2 读取图像

3 获取鼠标点

(1)打印鼠标点击的位置(演示,不一定要实现)

(2)创建列表存储坐标并将点击生成的点绘制出来

4 计算三个点组成的角的度数

5 润色(绘制线段构成角度) 

三 整体代码

扫描二维码关注公众号,回复: 15447774 查看本文章

四 结束语

一 前言

       在本次项目中,我们将会使用鼠标构建一个角,并显示这个角的度数;即通过点击鼠标来生成两条线,如果这两条线相交就会形成一个夹角,我们要做的就是测量这个夹角的度数。和之前的项目一样,本项目也是博主在Github中找到的比较有趣的项目,大家如果感兴趣可以尝试着复现一遍,如果对其他项目感兴趣可以关注下面这专栏,有时间我会更新一些比较有趣的项目分享给大家:
GitHub 计算机视觉项目实践

Now, let's start!

二 实现步骤

       先来简单介绍一下本次的任务,我们要通过点击鼠标生成三个点,而这三个点刚好能够组成两条相交的射线,接下我们使用一些简单的数学知识就可以得出这个角的度数了。不难看出,本次的项目并没有太大的难度,主要是使用数学方法计算角度。

1 需要的第三方库

       在本次项目中首先是要对图像中的角度进行测量,所以需要的第一个库是 OpenCV;然后需要计算角度,免不了数学计算,因此还需要 math 库,使用这两个库就可以实现本次项目了。

2 读取图像

       本项目是在图像中测量角度,所以第一步需要做的是读取目标图像。本次实验中我使用的是随便找的一幅图像,只要是使用 CV2 第三方库能够读取就到图像就可以。

读取图像的代码比较简单,如下:

import cv2
import math

path = 'test.jpg'  #图像读取路径
img = cv2.imread(path) #读取图像

如果你想将图像显示出来也可以:

3 获取鼠标点

        读取图像之后我们要操作的是能够让鼠标的点击在图像中起作用(点击左键就可以创建一个点,通过三次点击不同的点得到一个角)。在这里我们创建一个 mousepoint() 函数来完成这个任务。

(1)打印鼠标点击的位置(演示,不一定要实现)

       通过下面的函数就可以实现鼠标点的检测并将点击的坐标,本过程只是显示鼠标的点击位置,在项目中不一定实现

def mousePoints(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN: #检测是否有鼠标左键按下
        print(x, y)

cv2.setMouseCallback('Image', mousePoints) #鼠标的点击返回到图像中

通过点击就可以打印出鼠标的位置 

(2)创建列表存储坐标并将点击生成的点绘制出来

每测量一个角度我们要生成不止一个点,所以我们可以将这些点的坐标存储到一个列表中。

pointsList = [] #创建列表来存储鼠标点击的坐标点(这行代码并不在定义的函数中)

pointsList.append([x, y])#将坐标点存储在列表中(这行代码应该在函数中)

cv2.circle(img, (x, y), 5, (0, 0, 255), cv2.FILLED) #在鼠标的点击处绘制一个实心圆

#上面的代码都是实现功能的方式,并不会全都排列在一起

将存有坐标点的列表打印下来如下: 

4 计算三个点组成的角的度数

       当我们的列表中存储的点的个数达到3的倍数(即图像中的出现完整的角度时,我们该计算这些角的度数并将其绘制在图中)

计算一个角的度数的方式如下(通过三角函数诱导公式就能得到):

创建一个函数来计算角的度数:

#------------------------------
#定义函数计算两点之间的斜率
#------------------------------
def gradient(pt1, pt2):
    return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0])

#----------------------------
#定义函数计算角的度数
#---------------------------
def getAngle(pointsList):
    pt1, pt2, pt3 = pointsList[-3:] #列表中最后的三个坐标点
    m1 = gradient(pt1, pt2) #计算第一个点和第二个点之间的斜率
    m2 = gradient(pt1, pt3) #计算第一个点和第三个点之间的斜率
    angR = math.atan((m2 - m1) / (1 + (m2 * m1))) #计算正切值
    angD = round(math.degrees(angR)) #将弧度转化为角度

    cv2.putText(img, str(angD), (pt1[0] - 40, pt1[1] - 20), cv2.FONT_HERSHEY_COMPLEX,
                1.5, (0, 0, 255), 2)  #绘制文本

5 润色(绘制线段构成角度) 

       其实到第四步我们的目标已经达成了,将前面的代码整合起来就可以实现测量角度了,但我们可以在添加一些来绘制线段构成角度,代码如下:

        # -------------------
        #绘制线段构成一个角度
        # -------------------
        size = len(pointsList)
        if size != 0 and size % 3 != 0:
            cv2.line(img, tuple(pointsList[round((size - 1) / 3) * 3]), (x, y), (0, 0, 255), 2)

通过以上的步骤就能实现本次的角度测量了

由于线段宽度以及一些因素的影响,误差在所难免,感兴趣可以简单尝试一下。 

三 整体代码

整体代码如下:
 

"""
Author:XiaoMa
date:2022/03/30
"""
import cv2
import math

path = 'test.jpg'  #图像读取路径
img = cv2.imread(path) #读取图像
pointsList = [] #创建列表来存储鼠标点击的坐标点

#-------------------------------
#定义函数来检测鼠标动作
#-------------------------------
def mousePoints(event, x, y, flags, params):
    if event == cv2.EVENT_LBUTTONDOWN: #检测是否有鼠标左键按下
        # -------------------
        #绘制线段构成一个角度
        # -------------------
        size = len(pointsList)
        if size != 0 and size % 3 != 0:
            cv2.line(img, tuple(pointsList[round((size - 1) / 3) * 3]), (x, y), (0, 0, 255), 2) #在两点之间绘制直线
        cv2.circle(img, (x, y), 5, (0, 0, 255), cv2.FILLED) #在鼠标的点击处绘制一个实心圆
        pointsList.append([x, y])#将坐标点存储在列表中
        print(pointsList)

#------------------------------
#定义函数计算两点之间的斜率
#------------------------------
def gradient(pt1, pt2):
    return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0])

#----------------------------
#定义函数计算角的度数
#---------------------------
def getAngle(pointsList):
    pt1, pt2, pt3 = pointsList[-3:] #列表中最后的三个坐标点
    m1 = gradient(pt1, pt2) #计算第一个点和第二个点之间的斜率
    m2 = gradient(pt1, pt3) #计算第一个点和第三个点之间的斜率
    angR = math.atan((m2 - m1) / (1 + (m2 * m1))) #计算正切值
    angD = round(math.degrees(angR)) #将弧度转化为角度

    cv2.putText(img, str(angD), (pt1[0] - 40, pt1[1] - 20), cv2.FONT_HERSHEY_COMPLEX,
                1.5, (0, 0, 255), 2)  #绘制文本


while True:

    if len(pointsList) % 3 == 0 and len(pointsList) != 0: #列表长度为3时得到角度
        getAngle(pointsList)

    cv2.imshow('Image', img)
    cv2.setMouseCallback('Image', mousePoints) #鼠标的点击返回到图像中
#-------------------------------
#按下q键清除图像中的点(刷新图像)
#-------------------------------
    if cv2.waitKey(1) & 0xFF == ord('q'):
        pointsList = []
        img = cv2.imread(path)

四 结束语

       本次项目的实现较为简单,大家都可以尝试一下,原理也是使用高中的知识就能搞懂,简单的不达鸟,简单的一塌糊涂啊!!

猜你喜欢

转载自blog.csdn.net/qq_52309640/article/details/122910914