----追光逐电 光赢未来----
概述
在计算机视觉领域,图像中的集合计算是一项基本且重要的任务。它广泛应用于图像识别、目标跟踪、场景分析等领域。本文将会通过一个有意思的小代码,介绍OpenCV库与用户进行交互,计算图像中的角度,并将其显示在原有图像上。本篇会详细解析相关代码及其原理请放心观看。以下是本文用到的示例图片
一、原理介绍
图像角度计算通常涉及到两个关键步骤:一是确定图像中的三个点,二是计算由这三个点形成的两条线之间的夹角。
确定三个点:在图像中,我们可以通过鼠标点击或其他方式选取三个点。这三个点将用于定义两条线。
计算夹角:通过计算两条线之间的斜率,我们可以得到它们之间的夹角。具体方法如下:
例如,设三个点分别为A(x1, y1)、B(x2, y2)A(x1,y1)、B(x2,y2)和C(x3, y3)C(x3,y3),则线段AB和AC的斜率分别为:
m1 = (y2 - y1) / (x2 - x1) m2 = (y3 - y1) / (x3 - x1)m1=(y2−y1)/(x2−x1)m2=(y3−y1)/(x3−x1)
根据斜率,我们可以计算两条线之间的夹角θ(弧度):
θ=atan((m2-m1)/(1+m1*m2))θ=atan((m2−m1)/(1+m1∗m2))
最后,将弧度转换为度。
二、代码讲解
1、导入相关库
import cv2
import math
2、加载图片
path = 'test.png'
img = cv2.imread(path)
pointsList = []
path = 'test.png': 定义一个变量path,它包含图像文件的路径。
img = cv2.imread(path): 使用cv2.imread函数读取图像文件,并将其存储在名为img的变量中。该函数的参数是图像的路径。
pointsList = []: 初始化一个空列表pointsList,用于存储鼠标点击的坐标。
3、定义一个函数mousePoints
它将在鼠标事件发生时被调用。参数包括事件类型、鼠标的x和y坐标、标志和参数。
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])
if event == cv2.EVENT_LBUTTONDOWN:: 检查是否发生了鼠标左键点击事件。
size = len(pointsList): 获取pointsList列表的长度。
if size != 0 and size % 3 != 0:: 检查列表长度不为0且不是3的倍数。
cv2.line(img, tuple(pointsList[round((size - 1) / 3) * 3]), (x, y), (0, 0, 255), 2): 在图像上画一条线,从pointsList中最近的第三个点开始,到当前鼠标点击的点结束。参数包括图像、起点坐标、终点坐标、线的颜色(红色)和线的宽度。
cv2.circle(img, (x, y), 5, (0, 0, 255), cv2.FILLED): 在图像上画一个圆,圆心在鼠标点击的位置,半径为5,颜色为红色,填充类型为cv2.FILLED。
pointsList.append([x, y]): 将鼠标点击的坐标添加到pointsList列表中。
4、定义一个函数gradient
用于计算两点之间的斜率。
def gradient(pt1, pt2):
return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0])
return (pt2[1] - pt1[1]) / (pt2[0] - pt1[0]): 返回两点之间的斜率,即y坐标之差除以x坐标之差。
5、定义一个函数getAngle
计算由列表pointsList中最后三个点定义的两条线之间的角度,并在图像上显示这个角度的数值。
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)
pt1, pt2, pt3 = pointsList[-3:]: 从pointsList中取出最后三个点。
m1 = gradient(pt1, pt2): 计算点pt1和pt2之间的斜率。
m2 = gradient(pt1, pt3): 计算点pt1和pt3之间的斜率。
angR = math.atan((m2 - m1) / (1 + (m2 * m1))): 计算两条线之间的角度(弧度)。
angD = round(math.degrees(angR)): 将角度从弧度转换为度,并使用round函数对结果进行四舍五入,以便于显示。
cv2.putText(...):使用cv2.putText函数在图像img上绘制文本,显示计算出的角度angD。文本的位置是在pt1点的左侧和上方稍微偏移的位置。使用的字体是cv2.FONT_HERSHEY_COMPLEX,字体大小是1.5,文本颜色是红色(0, 0, 255),线条宽度是2。
6、主循环
最后是一个主循环,其工作流程如下:
程序进入一个无限循环,持续显示图像并等待用户交互。
用户通过鼠标点击在图像上添加点,这些点被存储在pointsList列表中。
当pointsList列表中有三个或更多点,并且点的数量是3的倍数时,程序计算最后三个点定义的两条线之间的角度,并在图像上显示这个角度。
用户可以随时按下’q’键来清除所有点并重新加载图像,从而重置整个程序。
while True:
if len(pointsList) % 3 == 0 and len(pointsList) != 0:
getAngle(pointsList)
cv2.imshow('Image', img)
cv2.setMouseCallback('Image', mousePoints)
if cv2.waitKey(1) & 0xFF == ord('q'):
pointsList = []
img = cv2.imread(path)
效果演示
运行程序后,会弹出图像框,如下所示:
选取三个点,即会显示出两直线之间的夹角,可以看到,与给定参考角度一致(取决于选点的时候是否对准,可能会有一两度的偏差)
按键盘上的Q键即可取消所有标注点,重新绘制图像
总结
使用OpenCV库进行角度计算的过程,首先通过鼠标回调函数收集图像上的点,然后利用数学公式计算由这些点构成的两条线之间的斜率,进而求出它们之间的角度。这一过程不仅展示了OpenCV在图像交互和数据处理方面的强大功能,也体现了计算机视觉技术在几何分析中的应用价值。
申明:感谢原创作者的辛勤付出。本号转载的文章均会在文中注明,若遇到版权问题请联系我们处理。
----与智者为伍 为创新赋能----
联系邮箱:uestcwxd@126.com
QQ:493826566