使用Python,OpenCV检测摄像机到标记对象的距离
这篇博客将介绍如何确定图像中已知物体到相机的距离, 确定从相机到标记物体的距离是计算机视觉/图像处理领域中一个非常好的研究课题。有俩种实现方式:
- 使用非常简单明了的技术——三角形相似性;
- 使用相机模型的固有参数,虽然复杂但更准确;
本文将介绍第一种方法。
1. 效果图
测距效果图1
边缘检测图
测距效果图2
效果图3:
2. 三角形相似性是什么?
三角形相似性是假设我们有一个标记或对象,宽度称为W 。然后,我们将此标记放置在距相机一定距离D处。我们使用相机拍摄物体的图片,然后以像素P为单位测量其宽度。这使我们能够得出摄像机的可感知焦距F:
F =(P x D)/ W
当继续将相机移近或远离物体/标记时,可以应用三角形相似度来确定物体到相机的距离:
D’=(宽x F)/ P
3. 三角形相似性检测距离原理
原理是参照物
利用三角形相似度,需要在应用算法之前了解两个重要参数:
- 用作标记的对象在某种距离度量(例如英寸或米)中的宽度(或高度)。
- 相机摄像头到标记对象的距离(以英寸或米为单位)。
- 使用计算机视觉和图像处理算法来自动确定对象的感知宽度/高度(以像素为单位),并完成三角形相似度并为我们提供焦距。
- 在后续图像中,找到其余的标记/对象并利用计算出的焦距来确定距相机到对象的距离。
4. 使用Python,OpenCV检测标记对象
- 转换灰度图
- 高斯模糊消除高频噪音
- 寻找边缘
- 检测轮廓,根据原始图像的特征保留相应的标记
在图像中找到标记的其他替代方法是利用颜色,假使标记的颜色与图像中其余场景的颜色不同。您还可以应用诸如关键点检测,局部不变描述符和关键点匹配之类的方法来查找标记。
5. 源码
# 使用Pthon,OpenCV检测标记对象到摄像头的距离
# USAGE
# python distance_to_camera.py
# 导入必要的包
from imutils import paths
import numpy as np
import imutils
import cv2
# 函数接受单个参数,image:源输入图像
# 查找我们要计算距离的对象
def find_marker(image):
# 转换为灰度图,高斯模糊,检测边缘
# 高斯模糊以消除高频噪声
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
gray = cv2.GaussianBlur(gray, (5, 5), 0)
edged = cv2.Canny(gray, 35, 125)
# 从边缘图像中检测轮廓,并保留最大的轮廓
# 假设最大轮廓是我们的纸
cnts = cv2.findContours(edged.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
c = max(cnts, key = cv2.contourArea)
# 返回纸区域的最小面积轮廓
return cv2.minAreaRect(c)
# 使用三角形相似度计算距离
# knownWidth 已知宽度
# focalLength 标记宽度
# perWidth 感知宽度
def distance_to_camera(knownWidth, focalLength, perWidth):
# 计算并返回到摄像机的距离
return (knownWidth * focalLength) / perWidth
# 找到与图像中的对象或标记的距离的第一步是校准和计算焦距。为此,我们需要知道:
# 初始化已知物体到摄像头的距离
KNOWN_DISTANCE = 24.0
# 初始化已知物体的宽度
KNOWN_WIDTH = 11.0
# 进行简单的校准
# 加载图像,寻找到纸的轮廓,计算感知焦距
image = cv2.imread("images/2ft.png")
marker = find_marker(image)
focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH
# 有了感知焦距,可以很容易地计算出相机到后续图像中标记的距离。
# 遍历图像
for imagePath in sorted(paths.list_images("images")):
# 加载图像,寻找图像中的标记,计算标记到摄像头的距离
image = cv2.imread(imagePath)
marker = find_marker(image)
inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
# 绘制边界框并展示在图像上,同时显示距离
box = cv2.cv.BoxPoints(marker) if imutils.is_cv2() else cv2.boxPoints(marker)
box = np.int0(box)
cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
cv2.putText(image, "%.2fft" % (inches / 12),
(image.shape[1] - 200, image.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,
2.0, (0, 255, 0), 3)
cv2.imshow("image", image)
cv2.waitKey(0)