详解:用Python OpenCV库来处理图像并测量物体的长度
1. 项目背景
智能卷尺测量系统通过传感器和算法实现自动测量,具备高精度、便携性和数据存储功能,适用于建筑、制造等领域。该系统的核心算法涉及到图像处理、计算机视觉和机器学习等技术。本文主要介绍Python OpenCV库的处理逻辑。
1. 安装所需的库
pip install opencv-python opencv-python-headless numpy
2. 代码实现
import cv2
import numpy as np
# 加载预训练的深度学习模型(例如:YOLO或SSD)
# 这里我们使用OpenCV自带的MobileNet SSD模型
net = cv2.dnn.readNetFromCaffe(
"deploy.prototxt", # 模型配置文件
"mobilenet_iter_73000.caffemodel" # 预训练模型权重
)
# 加载类别标签
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor"]
# 初始化摄像头
cap = cv2.VideoCapture(0)
while True:
# 读取摄像头帧
ret, frame = cap.read()
if not ret:
break
# 获取帧的尺寸
(h, w) = frame.shape[:2]
# 预处理图像:缩放、归一化、交换通道
blob = cv2.dnn.blobFromImage(frame, 0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
# 遍历检测结果
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
# 过滤掉低置信度的检测结果
if confidence > 0.2:
idx = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
# 绘制边界框和标签
label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100)
cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
y = startY - 15 if startY - 15 > 15 else startY + 15
cv2.putText(frame, label, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 计算物体的宽度和高度(以像素为单位)
object_width = endX - startX
object_height = endY - startY
# 假设我们知道物体的实际尺寸,可以将其转换为实际长度
# 例如,假设物体的实际宽度为10cm
actual_width_cm = 10.0
pixels_per_cm = object_width / actual_width_cm
# 计算物体的实际高度
actual_height_cm = object_height / pixels_per_cm
# 显示测量结果
measurement_label = "Width: {:.2f}cm, Height: {:.2f}cm".format(actual_width_cm, actual_height_cm)
cv2.putText(frame, measurement_label, (startX, y + 20), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 显示结果帧
cv2.imshow("Smart Tape Measure", frame)
# 按下 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
# 释放摄像头并关闭所有窗口
cap.release()
cv2.destroyAllWindows()
3. 代码说明
-
模型加载:我们使用了OpenCV自带的MobileNet SSD模型来检测物体。你需要下载
deploy.prototxt
和mobilenet_iter_73000.caffemodel
文件。 -
图像处理:我们使用
cv2.dnn.blobFromImage
对图像进行预处理,然后将其输入到神经网络中进行推理。 -
物体检测:我们遍历检测结果,并过滤掉低置信度的检测结果。然后,我们绘制边界框和标签。
-
测量:假设我们知道物体的实际尺寸(例如宽度为10cm),我们可以根据像素与实际尺寸的比例来计算物体的实际高度。
-
显示结果:最后,我们在图像上显示测量结果。
4. 注意事项
-
模型文件:你需要下载 MobileNet SSD 模型的配置文件和预训练权重文件
deploy.prototxt
和mobilenet_iter_73000.caffemodel
文件,并将它们放在与脚本相同的目录中。 -
deploy.prototxt
: 下载链接 -
mobilenet_iter_73000.caffemodel
: 下载链接 -
实际尺寸:在实际应用中,你需要知道物体的实际尺寸才能进行准确的测量。你可以通过校准过程来确定像素与实际尺寸的比例。
-
性能优化:在实际应用中,你可能需要对代码进行优化,以提高检测和测量的准确性。
5、创建图形化界面:
智能卷尺系统通常在移动终端(如手机或平板)上使用,我们使用适合移动开发的框架Kivy:一个开源的 Python 库,支持跨平台开发(包括 Android 和 iOS)。代码如下:
1. 安装 Kivy
首先,确保你已经安装了 Kivy。可以通过以下命令安装:
pip install kivy
2. 使用 Kivy 开发移动端智能卷尺系统
以下是一个完整的 Kivy 示例代码,集成了摄像头捕获和物体测量功能。
代码:smart_tape_measure.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.clock import Clock
from kivy.graphics.texture import Texture
from kivy.uix.camera import Camera
import cv2
import numpy as np
# 加载预训练的深度学习模型
net = cv2.dnn.readNetFromCaffe("deploy.prototxt", "mobilenet_iter_73000.caffemodel")
# 加载类别标签
CLASSES = ["background", "aeroplane", "bicycle", "bird", "boat",
"bottle", "bus", "car", "cat", "chair", "cow", "diningtable",
"dog", "horse", "motorbike", "person", "pottedplant",
"sheep", "sofa", "train", "tvmonitor"]
# 初始化全局变量
object_width_cm = 10.0 # 假设物体的实际宽度为10cm
pixels_per_cm = None
class SmartTapeMeasureApp(App):
def build(self):
# 主布局
self.layout = BoxLayout(orientation='vertical')
# 摄像头图像显示
self.image_widget = Image()
self.layout.add_widget(self.image_widget)
# 测量结果标签
self.result_label = Label(text="测量结果将显示在这里", size_hint=(1, 0.1))
self.layout.add_widget(self.result_label)
# 开始按钮
self.start_button = Button(text="开始测量", size_hint=(1, 0.1))
self.start_button.bind(on_press=self.start_measurement)
self.layout.add_widget(self.start_button)
# 初始化摄像头
self.capture = cv2.VideoCapture(0)
Clock.schedule_interval(self.update, 1.0 / 30.0) # 每秒更新30帧
return self.layout
def start_measurement(self, instance):
# 重置测量结果
self.result_label.text = "测量中..."
def update(self, dt):
# 读取摄像头帧
ret, frame = self.capture.read()
if ret:
# 处理图像
processed_frame = self.process_image(frame)
# 显示处理后的图像
self.display_image(processed_frame)
def process_image(self, frame):
global pixels_per_cm
(h, w) = frame.shape[:2]
# 预处理图像
blob = cv2.dnn.blobFromImage(frame, 0.007843, (300, 300), 127.5)
net.setInput(blob)
detections = net.forward()
# 遍历检测结果
for i in np.arange(0, detections.shape[2]):
confidence = detections[0, 0, i, 2]
# 过滤掉低置信度的检测结果
if confidence > 0.2:
idx = int(detections[0, 0, i, 1])
box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
(startX, startY, endX, endY) = box.astype("int")
# 绘制边界框和标签
label = "{}: {:.2f}%".format(CLASSES[idx], confidence * 100)
cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
y = startY - 15 if startY - 15 > 15 else startY + 15
cv2.putText(frame, label, (startX, y), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
# 计算物体的宽度和高度(以像素为单位)
object_width = endX - startX
object_height = endY - startY
# 计算像素与实际尺寸的比例
if pixels_per_cm is None:
pixels_per_cm = object_width / object_width_cm
# 计算物体的实际高度
actual_height_cm = object_height / pixels_per_cm
# 更新测量结果
measurement_label = "Width: {:.2f}cm, Height: {:.2f}cm".format(object_width_cm, actual_height_cm)
self.result_label.text = measurement_label
return frame
def display_image(self, frame):
# 将 OpenCV 图像转换为 Kivy 纹理
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
buf = frame.tostring()
texture = Texture.create(size=(frame.shape[1], frame.shape[0]), colorfmt='rgb')
texture.blit_buffer(buf, colorfmt='rgb', bufferfmt='ubyte')
self.image_widget.texture = texture
def on_stop(self):
# 释放摄像头
self.capture.release()
if __name__ == '__main__':
SmartTapeMeasureApp().run()
3. 代码说明
-
Kivy 界面:
-
使用
BoxLayout
构建了一个简单的界面,包含一个图像显示区域、一个测量结果标签和一个开始按钮。 -
点击“开始测量”按钮后,系统会开始处理摄像头帧并显示测量结果。
-
-
摄像头捕获:
-
使用 OpenCV 捕获摄像头帧,并通过 Kivy 的
Texture
将帧显示在界面上。
-
-
物体检测与测量:
-
使用 MobileNet SSD 模型检测物体,并计算物体的实际尺寸。
-
假设物体的实际宽度为 10cm,根据像素与实际尺寸的比例计算物体的实际高度。
-
-
实时更新:
-
使用 Kivy 的
Clock
定时器每秒更新 30 帧,实现实时测量。
-
4. 运行步骤
-
确保已安装 Kivy 和 OpenCV。
-
将
deploy.prototxt
和mobilenet_iter_73000.caffemodel
文件放在与脚本相同的目录中。 -
运行脚本:
python smart_tape_measure.py
-
点击“开始测量”按钮,系统会实时显示摄像头画面和测量结果。
6. 打包为移动应用
要将 Kivy 应用打包为 Android 或 iOS 应用,可以使用 Buildozer 或 Kivy-iOS。
以下使用 Buildozer 打包为 Android APK
-
安装 Buildozer:
pip install buildozer
-
在项目目录中初始化 Buildozer:
-
buildozer init
-
修改
buildozer.spec
文件,确保包含 OpenCV 和其他依赖项。 -
打包 APK:
buildozer -v android debug
-
生成的 APK 文件位于
bin
目录中,可以安装到 Android 设备上运行。