OpenCV-python小玩意3 直线的像素距离

0.我要做什么?

用OpenCV启动摄像头后,在预览界面用鼠标点击两点,画一条线。(没错,这是上一个小节的需求描述)
然后,显示出该线段的像素距离。

1.初步方案或待解决的问题

有了上一篇文章的基础,留给本文的就两个问题:
一个是如何显示长度信息,一个如何计算长度。
前者使用cv2.putText()方法,而后者通过欧氏距离来计算。

其他交互方面:

  • 实时显示鼠标位置与预览线。所谓的预览线是鼠标点击一次后,就有了起点,那么鼠标抬起后,有一根绿色线跟着鼠标走。
  • 支持多条线段的测量。

2.函数cv2.putText()介绍

该函数主要作用是在图像上绘制文本,原型如下:

cv2.putText(img, text, org, fontFace, fontScale, color, thickness, lineType, bottomLeftOrigin)

参数属实有点多,下面来看看说明:

参数类型说明示例值
imgMat/ndarray目标图像(直接修改原图)frame
textstr要绘制的文本内容"Cat: 95%"
org(x, y)文本左下角的坐标(原点默认左上角)(50, 100)
fontFaceint字体类型(如 FONT_HERSHEY_SIMPLEXcv2.FONT_HERSHEY_SIMPLEX
fontScalefloat字体缩放因子(1.0 为默认大小)0.8
color(B, G, R)文本颜色(BGR 格式)(0, 0, 255)(红色)
thicknessint笔画粗细(像素)2
lineTypeint线条类型(推荐抗锯齿 LINE_AAcv2.LINE_AA
bottomLeftOriginbool若为 True,坐标原点移至左下角False(默认)

举个代码例子:

import cv2

image = cv2.imread(r'../defect_inspection/images/glove.png')

cv2.putText(image, "Text Test", (20, 80),
            cv2.FONT_HERSHEY_PLAIN, 1.5, (0, 255, 255), 2)

cv2.imshow('Text Test', image)
cv2.waitKey(0)

3.欧氏距离

欧氏距离(Euclidean Distance)是欧几里得空间中两点间直线距离的度量方式,也是最常用的距离计算方法之一。其核心是通过勾股定理计算多维空间中点的绝对距离。
本次我们只看二维的,多维暂时用不到,就不烧脑了。

计算公式

  1. 二维空间(如平面坐标系)
    点 (A(x_1, y_1)) 与 (B(x_2, y_2)) 的欧氏距离:
    d=(x2−x1)2+(y2−y1)2d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2}d=(x2x1)2+(y2y1)2

示例:点 (A(1,2)) 和 (B(4,6)) 的距离为 (4−1)2+(6−2)2=9+16=5\sqrt{(4-1)^2 + (6-2)^2} = \sqrt{9+16} = 5(41)2+(62)2=9+16=5

  1. 三维空间
    点 (A(x_1,y_1,z_1)) 与 (B(x_2,y_2,z_2)) 的距离:
    d=(x2−x1)2+(y2−y1)2+(z2−z1)2 d = \sqrt{(x_2 - x_1)^2 + (y_2 - y_1)^2 + (z_2 - z_1)^2} d=(x2x1)2+(y2y1)2+(z2z1)2
    示例:点 (A(1,2,3)) 和 (B(4,5,6)) 的距离为 9+9+9≈5.196\sqrt{9+9+9} \approx 5.1969+9+95.196

代码例子

pt1 = points[-2]
pt2 = points[-1]
distance = np.sqrt((pt2[0] - pt1[0]) ** 2 + (pt2[1] - pt1[1]) ** 2)

4.代码实现

直线颜色 (B, G, R) 格式
绿色:(0, 255, 0)
蓝色:(255, 0, 0)

import cv2
import numpy as np

points = []  # 存储坐标点
current_pos = (0, 0)  # 当前鼠标位置
line_distances = []  # 存储每条线的长度


def mouse_draw(event, x, y, flags, param):
    global points, current_pos
    current_pos = (x, y)  # 实时更新鼠标位置
    if event == cv2.EVENT_LBUTTONDOWN:
        points.append((x, y))  # 添加当前点到列表
        # 每当有偶数个点时计算线段长度
        if len(points) % 2 == 0:
            pt1 = points[-2]
            pt2 = points[-1]
            distance = np.sqrt((pt2[0] - pt1[0]) ** 2 + (pt2[1] - pt1[1]) ** 2)
            line_distances.append(round(distance, 2))


cv2.namedWindow('image')
cv2.setMouseCallback('image', mouse_draw)
cap = cv2.VideoCapture(1)  # 0是默认摄像头,根据自己的摄像头设置

while True:
    ret, frame = cap.read()
    if not ret:
        break

    # 绘制所有已完成的线段和长度
    for i in range(0, len(points) // 2):
        idx = 2 * i
        pt1 = points[idx]
        pt2 = points[idx + 1]
        cv2.line(frame, pt1, pt2, (255, 0, 0), 2)
        # 在线段中点显示长度
        mid_x = (pt1[0] + pt2[0]) // 2
        mid_y = (pt1[1] + pt2[1]) // 2
        cv2.putText(frame, f"{line_distances[i]}px",
                    (mid_x, mid_y), cv2.FONT_HERSHEY_SIMPLEX,
                    0.7, (0, 255, 255), 2)

    # 实时绘制未完成的线段
    if len(points) % 2 == 1:
        cv2.line(frame, points[-1], current_pos, (0, 255, 0), 2)

    # 显示当前状态
    status = f"Points: {len(points)} | Next: {'Start' if len(points) % 2 == 0 else 'End'}"
    cv2.putText(frame, status, (10, 30),
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

    cv2.imshow('image', frame)

    key = cv2.waitKey(30)
    if key == ord('q'):
        break
    elif key == ord('c'):  # 清除功能
        points = []
        line_distances = []

cap.release()
cv2.destroyAllWindows()

运行效果如下:
两点间距离

至此,我们向真正的测量又迈进了一步!加油!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值