用 Python 和 OpenCV 来测量相机到目标的距离 - Go语言中文社区

用 Python 和 OpenCV 来测量相机到目标的距离


(点击上方蓝字,快速关注我们)


英文:Adrian Rosebrock  编译: 伯乐在线 - G.K. 

http://python.jobbole.com/84378/


几天前,一个叫 Cameron 的 PyImageSearch 读者发来邮件询问摄像头测距的方法。他花了一些时间研究,但是没有找到解决办法。

我很能体会 Cameron 的感受。几年前我做过一个分析棒球离手飞向本垒的运动的小项目。

我通过使用运动分析和基于轨迹的跟踪方法来确定或者估计小球在视频帧中的位置。并且因为棒球的大小是已知的,所以我也能估计出其到本垒的距离。

那是个有趣的项目,虽然系统的精度没有达到我的预期。——棒球运动太快所造成的“运动模糊”让达到高精度变得十分困难。

我的项目完全算是一个个例,但是通常来说,在计算机视觉或者图形处理领域计算从相机到目标的距离实际上是一个非常容易的问题。你可以找到一个像三角形相似这样简单粗暴的方法,或者你也可以用上相机模型的内参这样更复杂一点(但是更精确)的方法。

在这篇博客,我将会告诉大家我和 Cameron 是如果解决这个计算相机到已知物体或目标的距离。

千万要看——你一定不想错过。

OpenCV 和 Python 版本: 这个例子可以在 Python 2.7/Python 3.4+ 和 OpenCV 2.4.X上运行。

用相似三角形计算物体或者目标到相机的距离

我们将使用相似三角形来计算相机到一个已知的物体或者目标的距离。

相似三角形就是这么一回事:假设我们有一个宽度为 W 的目标或者物体。然后我们将这个目标放在距离我们的相机为 D 的位置。我们用相机对物体进行拍照并且测量物体的像素宽度 P 。这样我们就得出了相机焦距的公式:

F = (P x D) / W

举个例子,假设我在离相机距离 D = 24 英寸的地方放一张标准的 8.5 x 11 英寸的 A4 纸(横着放;W = 11)并且拍下一张照片。我测量出照片中 A4 纸的像素宽度为 P = 249 像素。

因此我的焦距 F 是:

F = (248px x 24in) / 11in = 543.45

当我继续将我的相机移动靠近或者离远物体或者目标时,我可以用相似三角形来计算出物体离相机的距离:

D’ = (W x F) / P

为了更具体,我们再举个例子,假设我将相机移到距离目标 3 英尺(或者说 36 英寸)的地方并且拍下上述的 A4 纸。通过自动的图形处理我可以获得图片中 A4 纸的像素距离为 170 像素。将这个代入公式得:

D’ = (11in x 543.45) / 170 = 35 英寸

或者约 36 英寸,合 3 英尺。

注意:当我给这次例子拍照时,我的卷尺有一点松,因此结果造成了大约 1 英寸的误差。还有我也是很快速地拍下了照片并且没有完全对齐卷尺上的脚标,这也会对最终结果的 1 英寸误差产生影响。综上所述,相似三角形的方法还是合理的,你也可以用这个方法很简单地计算出物体或者目标距离你的相机的距离。

现在理解了?

太棒了。接下来让我们用一些代码来看看如何用 Python、OpenCV、图像处理和计算机视觉技术来获得相机到物体或者目标的距离。

用Python和OpenCV来测量相机到目标的距离

继续,我们开始这个项目。打开一个文件,命名为distance_to_camera.py,然后就可以开工了。

# import the necessary packages

import numpy as np

import cv2

 

def find_marker(image):

    # convert the image to grayscale, blur it, and detect edges

    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

    gray = cv2.GaussianBlur(gray, (5, 5), 0)

    edged = cv2.Canny(gray, 35, 125)

 

    # find the contours in the edged image and keep the largest one;

    # we'll assume that this is our piece of paper in the image

    (cnts, _) = cv2.findContours(edged.copy(), cv2.RETR_LIST,        cv2.CHAIN_APPROX_SIMPLE)

    c = max(cnts, key = cv2.contourArea)

 

    # compute the bounding box of the of the paper region and return it

    return cv2.minAreaRect(c)


第一件要做的事情就是导入必要的包。我们将用 NumPy 来进行数值计算和 cv2 来绑定 OpenCV 。

在那之后我们定义 find_marker 函数。这个函数接收一个 image 参数,并且这意味着我们将用它来找出将要计算距离的物体。

在这个例子中我们使用标准的 8.5 x 11 英寸的 A4 纸作为我们的目标。

目前我们的第一个任务是找出图像中的这张纸。

我们先将图像转成灰度图,用高斯模糊除去明显的噪点,并且在第 7-9 行 使用边缘检测。

完成这几步后,我们的图像应该长这样:

如你所见,我们的目标(A4 纸)的边缘已经很清晰了。现在我们只要找出这张纸的轮廓(比如:外形)。

我们用 13 行 的 cv2.findContours 函数找到目标,并且在 14 行 计算出面积最大的轮廓。

我们假设面积最大的轮廓是我们的那张 A4 纸。这个假设在我们的这个例子是成立的,但是实际上在图像中找出目标是和是与应用场景高度相关的。

在我们的例子中,简单的边缘检测和计算最大的轮廓是可行的。我们可以通过使用轮廓近似法使系统更具鲁棒性,排除不包含有4个顶点的轮廓(因为 A4 纸是矩形有四个顶点),然后计算面积最大的四点轮廓。

注意:更多这样的方法见这篇文章,讲述了如何做一个简单粗暴的手机扫描仪。

其他找到图像中目标可选的方法是利用颜色特征(目标的颜色和背景有着明显的不同)。你还可以使用关键点检测,局部不变性描述子,和关键点匹配来寻找目标。但是这些方法以及超出了这篇文章的范畴,并且具有高度定制化的特性。

不管怎样,我们现在获得了目标的轮廓,并且在第 17 行 返回包含 (x, y) 坐标和像素高度和宽度信息的边界框给调用函数。

让我们也快速定义一个用上述的相似三角形法计算距离的函数:

def distance_to_camera(knownWidth, focalLength, perWidth):

# compute and return the distance from the maker to the camera

return (knownWidth * focalLength) / perWidth


这个函数传入目标的 knownWidth ,计算好的 focalLength ,和目标在图像中的像素距离,并且使用上面推导的相似三角形公式来计算到物体的距离


继续读下列代码来看看我们是如何利用这些函数的:


#import the necessary packages

import numpy as np

import cv2

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/iodjSVf8U1J7KYc/article/details/79070936
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

  • 发表于 2020-02-13 15:34:34
  • 阅读 ( 989 )
  • 分类:

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢