0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

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

新机器视觉 来源:CSDN技术社区 作者:jolingcome 2021-05-20 15:15 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

英文: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

importnumpyasnp

importcv2

deffind_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

returncv2.minAreaRect(c)

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

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

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

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

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

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

13e2fc3a-b4a9-11eb-bf61-12bb97331649.jpg

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

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

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

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

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

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

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

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

defdistance_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

importnumpyasnp

importcv2

deffind_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

returncv2.minAreaRect(c)

defdistance_to_camera(knownWidth,focalLength,perWidth):

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

return(knownWidth*focalLength)/perWidth

# initialize the known distance from the camera to the object, which

# in this case is 24 inches

KNOWN_DISTANCE=24.0

# initialize the known object width, which in this case, the piece of

# paper is 11 inches wide

KNOWN_WIDTH=11.0

# initialize the list of images that we'll be using

IMAGE_PATHS=["images/2ft.png","images/3ft.png","images/4ft.png"]

# load the furst image that contains an object that is KNOWN TO BE 2 feet

# from our camera, then find the paper marker in the image, and initialize

# the focal length

image=cv2.imread(IMAGE_PATHS[0])

marker=find_marker(image)

focalLength=(marker[1][0]*KNOWN_DISTANCE)/KNOWN_WIDTH

找到图像中目标的距离的第一步是标定和计算焦距。我们需要知道以下参数:

相机到物体的距离

这个物体的宽度(单位英尺或米)。注意:也可以用高度,这个例子中我们使用宽度。

这里不得不提示一下我们所做的并不是实质意义上的摄像机标定。真正的摄像机标定包括摄像机的内参,你可以从这里获得更多相关知识。

在第25 行我们初始化了已知的KNOWN_DISTANCE,从相机到物体的距离为 24 英寸。在第29 行我们初始了物体的宽度KNOWN_WIDTH为 11 英寸(一张横着放的标准 A4 纸)。

然后我们在第32 行定义要用到的图片的路径。

下一步比较重要:是一个简单的标定。

第37 行从硬盘读取第一张图,——我们将用这张图来作为标定图片。

图片加载以后,在第38 行计算图中 A4 纸的轮廓信息,在第39 行使用三角形相似法计算出focalLength。

由于我们已经“标定”了我们的系统并且获得了focalLength,我们可以很容易地计算出相机离接下来图片中目标的距离。

让我们看看这个是这么做的:

41# loop over the images

42forimagePathinIMAGE_PATHS:

# load the image, find the marker in the image, then compute the

# distance to the marker from the camera

image=cv2.imread(imagePath)

46marker=find_marker(image)

47inches=distance_to_camera(KNOWN_WIDTH,focalLength,marker[1][0])

# draw a bounding box around the image and display it

box=np.int0(cv2.cv.BoxPoints(marker))

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)

在第42 行开始遍历所有的图片路径。

然后,在第45 行我们将列表中所有的图片从硬盘读取下来。在第46 行提取目标轮廓,并且在第47 行计算摄像机到物体的距离。

在第50-56 行,我们简单地画出目标的边框并且显示出距离。

结果

来看看我们的脚本运作,打开一个终端,导航到你的代码目录,执行以下命令:

$pythondistance_to_camera.py

如果一切正常你将会看到2ft.png的结果,这张图是用来“标定”我们的系统并且计算初始的focalLength:

从上面的图片我们可以看到我们的焦距被正确地计算出来并且按照代码中的变量KNOWN_DISTANCE和KNOWN_WIDTH,A4 纸的距离是 2 英尺。

现在我们有了焦距,我们可以在接下来的图片中计算出目标的距离:

上上面的例子,我们的相机大概离目标有 3 英尺远。

让我们退后一步:

再次需要注意的是,我在拍这个例子的时候动作很快并且卷尺并没有绷紧。而且,我也没有确保我的相机是百分之百地对准目标底部,因此,这些例子总会有大概 1 英寸的误差。

以上是我要说的,这篇文章描述的三角形相似法仍然可以用,并且能够让你测量出图像上的物体或目标到你相机的距离。

总结

在这篇博客我们学习了如何计算一个图像上的已知物体到相机的距离。

为了完成这个任务我们利用了三角形相似法,并且需要知道两个重要的参数:

1、 目标的实际宽度(或高度),单位可以是英寸或者米。

2、 标定过程 1 中相机到目标的距离。

计算机视觉和图像处理算法可以被用来自动检测图像中物体的像素宽度或高度并且完成相似三角形的计算,得出一个焦距。

然后在接下来的图片中,我们只要提取出目标轮廓就可以利用得到的焦距测量出目标到相机的距离。

编辑:jq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 硬盘
    +关注

    关注

    3

    文章

    1367

    浏览量

    60072
  • 图像处理
    +关注

    关注

    29

    文章

    1347

    浏览量

    59698
  • 相机
    +关注

    关注

    5

    文章

    1606

    浏览量

    56034
  • 自动检测
    +关注

    关注

    0

    文章

    121

    浏览量

    16412
  • 计算机视觉
    +关注

    关注

    9

    文章

    1715

    浏览量

    47723

原文标题:用 Python 和 OpenCV 来测量相机到目标的距离

文章出处:【微信号:vision263com,微信公众号:新机器视觉】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    【幸狐Omni3576边缘计算套件试用体验】YOLO26 板端部署

    【幸狐Omni3576边缘计算套件试用体验】YOLO26 板端部署 本文介绍了幸狐 Omni3576 开发板结合 OpenCV 和 Ultralytics 库实现 YOLO26 板端部署,并实现目标
    发表于 04-19 22:02

    机器人主控核心板米尔RK3576 + ROS2,NPU加速实现目标跟随与机械臂抓取

    操作”——识别特定物体、主动跟随、近距离抓取。本文将在此基础上,集成深度摄像头,实现机器人核心功能: 使用米尔RK3576 NPU加速MixFormerV2进行目标跟踪,替代传统OpenCV算法
    发表于 04-10 21:23

    法兰距离相机镜头系统的关键参数

    在视觉领域,法兰距是一个重要的概念。它通常指的是相机镜头安装法兰的参考平面成像传感器的距离,这一参数在机器视觉领域充当重要角色,法兰距离的精准性作为一个核心参数,它的精准性直接影响
    的头像 发表于 01-28 17:29 1412次阅读
    法兰<b class='flag-5'>距离</b>:<b class='flag-5'>相机</b>镜头系统的关键参数

    没有专利的opencv-python 版本

    nonfree 模块的 contrib 版」 如果需要 contrib 模块的扩展功能(如特征匹配、目标跟踪),但要规避专利,可安装 opencv-contrib-python-headless(无头版,无
    发表于 12-13 12:37

    毫米波雷达如何用距离与角度分辨率感知世界

    左右的角度分辨率。正是这两把无形的标尺,定义了雷达区分复杂环境中紧密相邻目标的能力极限。一、距离分辨率想象两辆车在同一车道上一前一后行驶。雷达能否将它们识别为两个
    的头像 发表于 12-08 11:13 1068次阅读
    毫米波雷达如<b class='flag-5'>何用</b><b class='flag-5'>距离</b>与角度分辨率感知世界

    工业镜头测量中的“工作距离”是什么?

    工业镜头作为机器视觉系统中的核心组件,在自动化生产、质量检测和精密测量等领域发挥着关键作用。其中,“工作距离”(WorkingDistance,简称WD)是一个至关重要的参数,它直接影响系统
    的头像 发表于 12-06 16:46 1140次阅读
    工业镜头<b class='flag-5'>测量</b>中的“工作<b class='flag-5'>距离</b>”是什么?

    那些年我用OpenCV+Qt趟过哪些坑?写给视觉应用开发者的避坑指南

    前阵子,团队里新来的小伙子跑来找我,眉头紧锁。他手里的项目我清楚:一个基于摄像头的简单计数工具。Demo阶段用Python+OpenCV,几行代码跑得飞快,准确率也好看。可一旦要打包成给产线工人用
    发表于 12-02 09:43

    【开发实例】基于GM-3568JHF开发板安装OpenCV并使用视频目标跟踪 ( CamShift)

    在计算机视觉领域,视频目标跟踪是一个非常重要的任务。视频目标跟踪广泛应用于监控、自动驾驶、人机交互等多个领域。OpenCV提供了多种目标跟踪算法,其中MeanShift和CamShif
    的头像 发表于 09-02 08:04 944次阅读
    【开发实例】基于GM-3568JHF开发板安装<b class='flag-5'>OpenCV</b>并使用视频<b class='flag-5'>目标</b>跟踪 ( CamShift)

    图像尺寸测量仪硬件解析 - 相机篇:双模式测量系统

    在工业制造向 “高精度、高自动化” 升级的今天,相机作为测量仪的 “眼睛”,其性能将直接影响产品的质量控制与生产效率。而普密斯通过对相机硬件的持续创新,正在为更多行业提供 “精准、高效” 的
    的头像 发表于 09-01 11:38 1002次阅读
    图像尺寸<b class='flag-5'>测量</b>仪硬件解析 - <b class='flag-5'>相机</b>篇:双模式<b class='flag-5'>测量</b>系统

    【GM-3568JHF开发板免费体验】OpenCV开发环境安装和计数程序开发

    、 Android 等系统上运行,并通过Python接口简化操作。 sudo apt install libopencv-dev python3-opencv 四、OpenCV图像识别测试 使用
    发表于 08-09 13:30

    【GM-3568JHF开发板免费体验】OpenCV 视频目标跟踪 ( CamShift)

    目标区域的质心。 3)移动窗口:将窗口中心移动到质心位置。 4)调整窗口大小和方向:根据目标的尺寸和方向调整窗口。 5)迭代:重复步骤 2 4,直到窗口中心不再变化或达到最大迭代次数。 O
    发表于 08-09 13:19

    如何板端编译OpenCV并搭建应用--基于瑞芯微米尔RK3576开发板

    运行opencv代码,完成一些视觉内容,充分发挥该板的性能。要先编译opencv需要一些预先的准备工作首先更新软件包并安装必要的依赖:sudo apt update sudo apt upgrade
    发表于 08-08 17:14

    基于凌智视觉识别模块的基于单目视觉的目标测量装置

    1.视觉测量整体方案本视觉测量系统采用单目视觉技术实现目标距离
    的头像 发表于 07-31 15:35 1123次阅读
    基于凌智视觉识别模块的基于单目视觉的<b class='flag-5'>目标</b>物<b class='flag-5'>测量</b>装置

    【Milk-V Duo S 开发板免费体验】SDK编译、人脸检测、OpenCV测试

    OpenCV-mobile OpenCV-mobile 是一个精简版的 OpenCV 库,通过调整编译参数,删减部分 OpenCV 源码,
    发表于 07-11 13:48

    电流互感器远距离测量解决方案

    电流互感器 是非常成熟的工频电流测量元件,它的使用历史可以是追溯19世纪末,它在工频电流的测量方面有着无可比拟的测量优势。电流互感器的二次侧测量
    的头像 发表于 06-10 08:53 921次阅读
    电流互感器远<b class='flag-5'>距离</b><b class='flag-5'>测量</b>解决方案