OpenCV构建交互式图像距离测量工具

在计算机视觉和图形学应用中,准确测量图像上的点之间距离是一项常见且重要的任务。本篇技术博客将详细介绍如何利用Python编程语言和OpenCV库构建一个交互式的图像距离测量工具。我们将通过编写一个名为ImageProcessor的类,让用户能够在图像上点击选取点,并实时显示两点间的实际距离(以毫米为单位)。下面让我们一起深入探讨代码实现及其核心功能。

一、代码结构概览

首先,我们来看看整个程序的主要组成部分:

python 复制代码
import cv2
import numpy as np


class ImageProcessor:
    def __init__(self, image_path, pixel_to_mm=0.3):
        self.image_path = image_path
        self.pixel_to_mm = pixel_to_mm
        self.image = None
        self.points = []
        self.distances = []
        self.load_image()

    def load_image(self):
        try:
            self.image = cv2.imread(self.image_path)
        except FileNotFoundError:
            print("Image file not found.")
            exit()

    def calculate_distance(self, point1, point2):
        pixel_distance = np.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2)
        actual_distance = pixel_distance * self.pixel_to_mm
        return pixel_distance, actual_distance

    def draw_on_image(self):
        img_copy = self.image.copy()
        for i in range(len(self.points)):
            cv2.circle(img_copy, self.points[i], 3, (0, 0, 255), -1)  # Display Point
            if i % 2 == 1:
                cv2.line(img_copy, self.points[i - 1], self.points[i], (255, 0, 0), 2)  # Draw line between points

                pixel_distance, actual_distance = self.calculate_distance(self.points[i - 1], self.points[i])
                self.distances.append(actual_distance)
                text = "AD: {:.2f} mm".format(actual_distance)
                cv2.putText(img_copy, text, (
                (self.points[i - 1][0] + self.points[i][0]) // 2, (self.points[i - 1][1] + self.points[i][1]) // 2),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

        return img_copy

    def mouse_event(self, event, x, y, flags, param):
        if event == cv2.EVENT_LBUTTONDOWN:
            self.points.append((x, y))

    def process(self):
        cv2.namedWindow('Image')
        cv2.setMouseCallback('Image', self.mouse_event)

        while True:
            img_copy = self.draw_on_image()

            cv2.imshow('Image', img_copy)
            key = cv2.waitKey(1) & 0xFF
            if key == 27:  # Press 'Esc' to exit
                break

        cv2.destroyAllWindows()


if __name__ == "__main__":
    processor = ImageProcessor('mask/img.png', pixel_to_mm=0.3)
    processor.process()

该程序主要由以下几部分组成:

  1. 标题引入必要的库:cv2(OpenCV库)用于图像处理和显示,numpy(NumPy库)用于数值计算。

  2. 定义ImageProcessor类:封装图像加载、点选、距离计算、结果显示等逻辑。

  3. 主程序入口:创建ImageProcessor实例,传入图像路径和像素与毫米的比例,默认为0.3,然后调用process方法启动交互过程。

    接下来,我们将逐一解析ImageProcessor类中的关键方法。

二、ImageProcessor类详解

  1. __init__方法
python 复制代码
def __init__(self, image_path, pixel_to_mm=0.3):
    self.image_path = image_path
    self.pixel_to_mm = pixel_to_mm
    self.image = None
    self.points = []
    self.distances = []
    self.load_image()

__init__方法是类的构造器,负责初始化对象属性。这里定义了以下几个属性:

image_path: 存储待处理图像的路径。

pixel_to_mm: 像素与毫米之间的比例,默认值为0.3,表示每个像素代表0.3毫米。

image: 用于存放加载的图像数据。

points: 存储用户点击的点坐标,按点击顺序排列。

distances: 存储已计算的实际距离值。

最后,load_image方法被调用,用于加载指定路径下的图像

  1. load_image方法
python 复制代码
def load_image(self):
   try:
       self.image = cv2.imread(self.image_path)
   except FileNotFoundError:
       print("Image file not found.")
       exit()

load_image方法负责从指定路径加载图像。它使用cv2.imread函数尝试读取图像,如果文件不存在,则捕获FileNotFoundError异常,打印错误消息并退出程序,确保程序在遇到无效文件时能优雅终止。

  1. calculate_distance方法
python 复制代码
def calculate_distance(self, point1, point2):
    pixel_distance = np.sqrt((point2[0] - point1[0]) ** 2 + (point2[1] - point1[1]) ** 2)
    actual_distance = pixel_distance * self.pixel_to_mm
    return pixel_distance, actual_distance

calculate_distance方法接收两个点坐标作为参数,计算它们之间的像素距离(欧氏距离)并转换为实际距离(毫米)。结果以元组形式返回,包含像素距离和实际距离。

  1. draw_on_image方法
python 复制代码
def draw_on_image(self):
    img_copy = self.image.copy()
    for i in range(len(self.points)):
        cv2.circle(img_copy, self.points[i], 3, (0, 0, 255), -1)  # Display Point
        if i % 2 == 1:
            cv2.line(img_copy, self.points[i - 1], self.points[i], (255, 0, 0), 2)  # Draw line between points

            pixel_distance, actual_distance = self.calculate_distance(self.points[i - 1], self.points[i])
            self.distances.append(actual_distance)
            text = "AD: {:.2f} mm".format(actual_distance)
            cv2.putText(img_copy, text, (
            (self.points[i - 1][0] + self.points[i][0]) // 2, (self.points[i - 1][1] + self.points[i][1]) // 2),
                        cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 0, 0), 2)

    return img_copy

draw_on_image方法负责在图像副本上绘制用户选择的点、连线及距离文字。具体步骤如下:

  • 创建图像副本,防止直接修改原始图像。
  • 遍历points列表,绘制每个点为红色圆圈。
  • 当索引i为奇数时,表示当前点与前一个点构成一对,于是:
    绘制连接这两个点的线。
    调用calculate_distance计算它们之间的实际距离,并将结果添加到distances列表。
    在两点之间合适的位置绘制包含实际距离的文字。
    最后返回处理过的图像副本。
  1. mouse_event
python 复制代码
def mouse_event(self, event, x, y, flags, param):
    if event == cv2.EVENT_LBUTTONDOWN:
        self.points.append((x, y))

mouse_event方法作为鼠标回调函数,响应用户的鼠标操作。当用户按下左键(cv2.EVENT_LBUTTONDOWN)时,将当前鼠标位置((x, y))添加到points列表中。

相关推荐
hummhumm20 分钟前
第 25 章 - Golang 项目结构
java·开发语言·前端·后端·python·elasticsearch·golang
deephub21 分钟前
优化注意力层提升 Transformer 模型效率:通过改进注意力机制降低机器学习成本
人工智能·深度学习·transformer·大语言模型·注意力机制
杜小满24 分钟前
周志华深度森林deep forest(deep-forest)最新可安装教程,仅需在pycharm中完成,超简单安装教程
python·随机森林·pycharm·集成学习
搏博33 分钟前
神经网络问题之二:梯度爆炸(Gradient Explosion)
人工智能·深度学习·神经网络
KGback39 分钟前
【论文解析】HAQ: Hardware-Aware Automated Quantization With Mixed Precision
人工智能
电子手信1 小时前
知识中台在多语言客户中的应用
大数据·人工智能·自然语言处理·数据挖掘·知识图谱
不高明的骗子1 小时前
【深度学习之一】2024最新pytorch+cuda+cudnn下载安装搭建开发环境
人工智能·pytorch·深度学习·cuda
Chef_Chen1 小时前
从0开始学习机器学习--Day33--机器学习阶段总结
人工智能·学习·机器学习
搏博1 小时前
神经网络问题之:梯度不稳定
人工智能·深度学习·神经网络
databook1 小时前
『玩转Streamlit』--布局与容器组件
python·机器学习·数据分析