我的论文方向目前是使用单目摄像头实现机器人对人的跟随,首先单目摄像头与kinect等深度摄像头最大的区别是无法有效获取深度信息,那就首先从这方面入手,尝试通过图像获取摄像头与人的距离。

在网上看了几天关于摄像头标定和摄像头焦距等原理的文章,然后通过这篇文章真正启发了我:用python和opencv来测量目标到相机的距离  主要的测距的原理是利用相似三角形计算物体到相机的距离。

在这里我的环境为: Ubuntu14.04 + Opencv2.4.9

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

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

相似三角形就是这么一回事:假设我们有一个宽度为 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 英尺。

从以上的解释中,我们可以看到,要想得到距离,我们就要知道摄像头的焦距和目标物体的尺寸大小,这两个已知条件根据公式:  

D’ = (W x F) / P 

得出目标到摄像机的距离D,其中P是指像素距离,W是A4纸的宽度,F是摄像机焦距。

  在原文中,是通过预先拍照,根据第一张照片算出摄像头的焦距,在根据已知的焦距算出接下来的照片中白纸到摄像机的距离,这样不太直观,而且需要预先拍照,我将源程序改为实时测距,简单来说就是将原来的读入照片变为读摄像头,这样的效果看起来比较直观.源程序如下:

#!usr/bin/python
# -*- coding: utf-8 -*-
#定义编码,中文注释#import the necessary packages
import numpy as np
import cv2# 找到目标函数
def find_marker(image):# convert the image to grayscale, blur it, and detect edgesgray = 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# cv2.minAreaRect() c代表点集,返回rect[0]是最小外接矩形中心点坐标,# rect[1][0]是width,rect[1][1]是height,rect[2]是角度return cv2.minAreaRect(c)# 距离计算函数
def distance_to_camera(knownWidth, focalLength, perWidth):  # compute and return the distance from the maker to the camerareturn (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
# A4纸的长和宽(单位:inches)
KNOWN_WIDTH = 11.69
KNOWN_HEIGHT = 8.27# initialize the list of images that we'll be using
IMAGE_PATHS = ["Picture1.jpg", "Picture2.jpg", "Picture3.jpg"]# 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  #通过摄像头标定获取的像素焦距
#focalLength = 811.82
print('focalLength = ',focalLength)#打开摄像头
camera = cv2.VideoCapture(0)while camera.isOpened():# get a frame(grabbed, frame) = camera.read()marker = find_marker(frame)if marker == 0:print(marker)continueinches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])# draw a bounding box around the image and display itbox = np.int0(cv2.cv.BoxPoints(marker))cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)# inches 转换为 cmcv2.putText(frame, "%.2fcm" % (inches *30.48/ 12),(frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,2.0, (0, 255, 0), 3)# show a framecv2.imshow("capture", frame)if cv2.waitKey(1) & 0xFF == ord('q'):break
camera.release()
cv2.destroyAllWindows() 

程序效果图如下:

在这张图里我摄像头距离桌面大概100cm,可以看到图中距离为96cm,可以看到精度还可以。

需要注意的是, 如果使用的是opencv3的版本,

1. 需要将find_marker函数中

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

改为:

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

因为 In Opencv 3 API version the  cv2.findCoutours()  returns 3  object

  • image
  • contours
  • hierarchy

2. 需要将:

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

改为:

box = cv2.boxPoints(marker)
box = np.int0(box)

以上两个地方是安装不同版本opencv需要修改的地方。

存在的问题:

1. 程序在运行时在未检测到A4纸时有时候会报错:

Traceback (most recent call last):
  File "video_paper_distance.py", line 86, in <module>
    marker = find_marker(frame)
  File "video_paper_distance.py", line 18, in find_marker
    c = max(cnts, key = cv2.contourArea)

ValueError: max() arg is an empty sequence

目前关于这个错误,我还没有解决,猜测主要是由于没有检测到目标造成max()函数为空的原因,不过没有深究。

2. 程序是通过第一张图已知目标到相机的距离来计算摄像头焦距,然后再通过焦距计算接下来目标到摄像头的距离,在这里焦距是一个关键的参数,所以我准备尝试通过对摄像头的标定直接获取相机的像素焦距,我是通过ros的一个包实现了对相机的标定,不过通过相机标定得出的像素焦距计算出来的距离并没有通过第一张图片计算出的焦距计算出来的距离准确,这个具体原因也没有搞明白,可能是我标定的结果不够准确?

3. 在通过摄像头测距时, 得出的距离也是准确且随着摄像头距离桌面远近而线性变化的,但距离偶尔会出现突变,目前也没找到是什么原因造成的.

ros相机标定主要参考的是这篇博客,博主是白巧克力亦唯心,ROS大神:

ROS 教程之 vision: 摄像头标定camera calibration

这里主要记录的是,通过摄像机标定,得到的3*3的内参数矩阵,其中M[1][1]和M[2][2]分别为我们要求的相机的x,y轴的像素焦距。

二 使用相机计算人到相机的距离

  在第一部分中我们已经计算出了A4纸距离相机的距离,在具体应用中,我需要计算的是人距离相机的距离,来实现机器人对目标人距离的判断,应用与对目标人的跟随。在这里主要的思路是先通过opencv中的HOG方法检测到人,再根据人的预估身高和摄像头焦距计算人到摄像机的距离。在这里选择身高的原因在于人的身高在不同方向上变化较小,而且我们的摄像头高度是固定的,所以选择身高。

1.首先要使用opencv进行行人检测:

#!usr/bin/python
# -*- coding: utf-8 -*-# import the necessary packages
from __future__ import print_function
from imutils.object_detection import non_max_suppression
from imutils import paths
import numpy as np
import argparse
import imutils
import cv2cap = cv2.VideoCapture(0)# initialize the HOG descriptor/person detector
hog = cv2.HOGDescriptor()
# 使用opencv默认的SVM分类器
hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector())while(1):# get a frameret, frame = cap.read()frame = imutils.resize(frame, width=min(400, frame.shape[1]))# detect people in the image(rects, weights) = hog.detectMultiScale(frame, winStride=(4, 4),padding=(8, 8), scale=1.05)rects = np.array([[x, y, x + w, y + h] for (x, y, w, h) in rects])# 非极大抑制 消除多余的框 找到最佳人体pick = non_max_suppression(rects, probs=None, overlapThresh=0.65)# 画出边框for (xA, yA, xB, yB) in pick:cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2)# show a framecv2.imshow("capture", frame)if cv2.waitKey(1) & 0xFF == ord('q'):break
cap.release()
cv2.destroyAllWindows() 

2.将行人检测与测距代码结合:

while camera.isOpened():# get a frame(grabbed, frame) = camera.read()# 如果不能抓取到一帧,说明我们到了视频的结尾if not grabbed:breakframe = imutils.resize(frame, width=min(400, frame.shape[1]))#marker = find_marker(frame)marker = find_person(frame)#inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])for (xA, yA, xB, yB) in marker:cv2.rectangle(frame, (xA, yA), (xB, yB), (0, 255, 0), 2)ya_max = yAyb_max = yBpix_person_height = yb_max - ya_maxif pix_person_height == 0:#pix_person_height = 1continueprint (pix_person_height)#print (pix_person_height)inches = distance_to_camera(KNOW_PERSON_HEIGHT, focalLength, pix_person_height)print("%.2fcm" % (inches *30.48/ 12))# draw a bounding box around the image and display it#box = np.int0(cv2.cv.BoxPoints(marker))#cv2.drawContours(frame, [box], -1, (0, 255, 0), 2)cv2.putText(frame, "%.2fcm" % (inches *30.48/ 12),(frame.shape[1] - 200, frame.shape[0] - 20), cv2.FONT_HERSHEY_SIMPLEX,2.0, (0, 255, 0), 3)# show a framecv2.imshow("capture", frame)if cv2.waitKey(1) & 0xFF == ord('q'):break

3.存在的问题:

  目前使用HOG检测行人的效果不是很好,会把类似人体形状的物体都框出来,比如实验室的三脚架等物体,受背景干扰较大。程序中存在一个bug就是在没有检测到人时,pix_person_height会为0,这样分母为0时无法计算,在接下来我也要通过3个方面改进,首先要想办法进一步改进人体检测,使用YOLO的方法目前是比较好的,但在CPU下速度较慢。然后要改进的是精度,这里需要主要的是选择摄像头要选择固定焦距的摄像头,自动变焦摄像头焦距会变化,测量的距离也会变。最后就是尽可能完善程序,减少bug。

4 . 将要进行的工作

通过程序可以看到使用单目摄像头检测人到摄像头的距离,其中一个影响较大的因素是对人体的准确检测,如果想要使测量的距离准确(完全准确是不可能的,但要达到可以用于机器人跟随人的功能的程度),那就要尽可能的准确的检测出人,通过我的测试,在准确知道目标人的身高前提下,在离摄像头固定距离上对人拍照,然后手动对人进行画框,标定出目标人的在画面中的高度,通过计算,得到的距离比较准确,其精度完全是可以接受的,所以接下来的工作主要是如何通过程序来准确的框出目标人来获取其在图像中的高度。

程序的源码已经上面已经贴出,也可以到下载页面下载。

单目摄像机测距(python+opencv)相关推荐

  1. opencv 通过网络连接工业相机_单目摄像机测距(python+opencv)

    点击上方"新机器视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 我的论文方向目前是使用单目摄像头实现机器人对人的跟随,首先单目摄像 ...

  2. 单目摄像机测距(python+opencv)(转载)

    我的论文方向目前是使用单目摄像头实现机器人对人的跟随,首先单目摄像头与kinect等深度摄像头最大的区别是无法有效获取深度信息,那就首先从这方面入手,尝试通过图像获取摄像头与人的距离. 在网上看了几天 ...

  3. 基于OpenCV的单目摄像机测距

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自|新机器视觉 我的论文方向目前是使用单目摄像头实现机器人对人 ...

  4. 单目车辆测距源码,python源码,可以自己改成c语言

    单目车辆测距源码,python源码,可以自己改成c语言 单目车辆测距源码,python源码,可以自己改成c语言 辅助驾驶之车辆测距程序 测距原理:参考百度陈光的基于单目摄像头的物体检测-2D图像上的3 ...

  5. 机器视觉学习笔记(4)——单目摄像机标定参数说明

    机器视觉学习笔记(4)--单目摄像机标定参数说明 标签: 机器视觉 1.针孔摄像机模型 在介绍摄像机标定参数之前,需要先简单说一下针孔摄像机的原理.投影平面到小孔的距离为焦距f,物体到小孔的距离为Z, ...

  6. 史上最全 | 单目相机测距测速方法大盘点!

    点击下方卡片,关注"自动驾驶之心"公众号 ADAS巨卷干货,即可获取 点击进入→自动驾驶之心技术交流群 后台回复[ECCV2022]获取ECCV2022所有自动驾驶方向论文! 论文 ...

  7. 前车碰撞预警——FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码

    前车碰撞预警--FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码. 单目测距,多目标跟踪. 车辆检测,智能adas,FCW,价格只包括源码及设计文档讲解. 我使用的版本说明: gpu版本: an ...

  8. 基于深度学习和单目摄像头测距的前车碰撞预警源码

    前车碰撞预警--FCW,基于深度学习和单目摄像头测距的前车碰撞预警源码 单目测距,多目标跟踪. 车辆检测,智能adas,FCW,编号只包括源码及设计文档讲解. 我使用的版本说明: gpu版本: ano ...

  9. 畸变的单目摄像机标定

    畸变的单目摄像机标定 Deep Single Image Camera Calibration with Radial Distortion 摘要 单图像标定是从一幅图像中预测摄像机参数的问题.在处理 ...

最新文章

  1. linux dev controlC0,关于Linux的alsa音频问题解决
  2. 独家 | Python时间序列分析:一项基于案例的全面指南
  3. 关于使用sudo命令后找不到JAVA_HOME的问题
  4. c++exe程序在别人电脑上双击无法打开_电脑换新系统的应用可以这样快速迁移
  5. IP地址、子网掩码、网关的概念—Vecloud微云
  6. Vue 脚手架生成的项目结构分析||Vue 脚手架的自定义配置
  7. linux同步硬件和系统时钟,liunx系统下时钟不同步会出现问题 怎么同步Linux 的系统时钟和硬件时钟?...
  8. 《锋利的jQuery》学习---基础篇01(持续更新)
  9. GitHub 标星 32.7 k!一行命令下载全网视频,这个项目牛逼了!
  10. Acwing 252. 树 点分治
  11. Java基础:数组的声明,循环,赋值,拷贝。
  12. Java中static变量作用和用法详解
  13. 解决Hadoop运行时的WARN util. NativeCodeLoader: Unable to load native-hadoop library for your platform
  14. Python模拟登录的几种方法
  15. 判断字符串是否是有效的手机号码
  16. 模拟按钮控件BN_CLICKED消息事件
  17. STM32 之十二 FLASH 使用详解 及 LL 库 FLASH 驱动实现
  18. 创建加密访问网站,端口443
  19. python列表数字比大小教案_幼儿园大班数学教案数字比大小
  20. 西部旅游杂志西部旅游杂志社西部旅游编辑部2022年第19期目录

热门文章

  1. Arm和Unity联合推出:适用于移动应用程序的3D美术优化-[3]纹理
  2. 摩根大通和摩根斯坦利的关系(转载自人米网)
  3. 接口日志管理心得分享
  4. 华为云WeLink有多安全?
  5. 创意电子学-第02课:电子学基础(电阻、电压、电流、欧姆定律)
  6. 我为开放原子全球开源峰会助力
  7. 高并发系统设计——分布式锁解决方案
  8. 用html怎么制作风车,如何用css3实现风车效果
  9. CMOS 图像传感器简介
  10. 保监会暂停审批区域保险代理车险