Monocamera_opencv传统测距

摄像头单目测距原理与实现

一.测距原理

空间的深度或距离等数据的摄像头

单纯的单目视觉测距,必须已知一个确定的长度

f为摄像头的焦距 c为镜头光心 物体发出的光经过相机的光心,然后成像于图像传感器或者也可以说是像平面上,如果设物体所在平面与相机平面的距离为d,物体实际高度为H,在传感器上的高度为h,H一定要是已知的,我们才能求得距离d.

假设我们有一个宽度为W的目标或物体.然后我们将这个目标放在距离我们的相机D的位置.我们用相机对物体进行拍照且测量物体的像素宽度P.这样就能得到相机焦距的公式: F = (P x D)/W

假设现在我们有一张A4纸(8.27in x 11.69in), in代表英寸,1in = 25.4mm。纸张宽度W=11.69in,相机距离纸张的距离D = 32in,此时拍下的照片中A4纸的像素宽度为P=192px(我的相机实际测量得到的值)。 此时我们可以算出焦距F=(192x30)/11.69。

当我们将摄像头远离或者靠近A4纸时,就可以用相似三角形得到相机距离物体的距离。 此时的距离: D’ = (W’ x F ) / P’。

二.测距步骤

  1. 使用摄像机采集道路前方的图像
  2. 在道路区域对物体进行检测,通过矩形框将物体形状框出来
  3. 结合矩形框信息,找到该矩形框底边的两个像平面坐标,分别记为(u1,v1)和(u2,v2)
  4. 使用几何关系推导法,由像平面坐标点(u1,v1)和(u2,v2)推导出道路平面坐标(x1,y1)/(x2,y2); 投影到地面上,z轴为0
  5. 通过欧氏距离公式计算出d

三.难点步骤

1.图像畸变矫正模型的理解;

(标定参数,内参矩阵,畸变矩阵,外参矩阵(平移、旋转向量矩阵))

2.像素坐标与世界坐标公式的推导及验证;

3.测距方法,对于检测物体在摄像头前方、左侧、右侧的判别思路;

4.弄清反畸变;对于畸变矫正后的图像中的检测框中的点进行反畸变处理。

四.相机镜头畸变矫正--> 得到相机的内外参数/畸变参数矩阵

  1. 外参数矩阵。世界坐标经过旋转和平移,然后落到另一个现实世界点(摄像机坐标)上。

  2. 内参数矩阵。告诉你上述那个点在1的基础上,是如何继续经过摄像机的镜头、并通过针孔成像和电子转化而成为像素点的。

  3. 畸变矩阵。告诉你为什么上面那个像素点并没有落在理论计算该落在的位置上,还产生了一定的偏移和变形.

五.代码实现

# /usr/bin/python3

# -*- coding:utf-8 -*-

import numpy as np
import cv2

KNOWN_DISTANCE = 40
KNOW_WIDTH = 11.69
KNOW_HEIGHT = 8.27

IMAGE_PATHS = ['Picture1.jpg', 'Picture2.jpg', 'Picture3.jpg']

def find_maker(image):

    gray_img = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    gray_img = cv2.GaussianBlur(gray_img, (5, 5), 0)
    edged_img = cv2.Canny(gray_img, 35, 125)
    cv2.namedWindow("Noise reduction effect map", 0)
    cv2.resizeWindow('Noise reduction effect map', 640, 480)
    cv2.imshow('Noise reduction effect map', edged_img)


    countours, hierarchy = cv2.findContours(edged_img.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

    print((len(countours)))
    c = max(countours, key=cv2.contourArea)
    rect = cv2.minAreaRect(c)
    return rect

def distance_to_camera(knownWidth, focalLength, perWidth):
    return (knownWidth * focalLength)/perWidth

def calculate_focalDistance(img_path):
    first_image = cv2.imread(img_path)
    cv2.namedWindow("first image", 0)
    cv2.resizeWindow('first image', 640, 480)
    cv2.imshow('first image', first_image)
    marker = find_maker(first_image)
    focalLength = (marker[1][0] * KNOWN_DISTANCE)/KNOW_WIDTH
    print(marker[1][0])
    print('焦距(focalLength)=', focalLength)
    return focalLength

def calculate_Distance(image_path,focalLength_value):
    image = cv2.imread(image_path)
    cv2.namedWindow("original", 0)
    cv2.resizeWindow('original', 640, 480)
    cv2.imshow('original', image)
    marker = find_maker(image)
    distance_inches = distance_to_camera(KNOW_WIDTH, focalLength_value, marker[1][0])
    box = cv2.boxPoints(marker)
    print('Box = ', box)
    box = np.int0(box)
    print('Box = ', box)
    cv2.drawContours(image, [box], -1, (0, 255, 0), 2)
    cv2.putText(image,'%.2fcm'%(distance_inches * 2.54),(image.shape[1] - 300, image.shape[0] - 20),cv2.FONT_HERSHEY_SIMPLEX, 2.0, (0,255,0), 3)
    cv2.namedWindow("mono-camera", 0);
    cv2.resizeWindow('mono-camera', 640, 480)
    cv2.imshow('mono-camera', image)



if __name__ == '__main__':
    img_path = 'Picture1.jpg'
    #width = 640
    #height = 480
    focalLength = calculate_focalDistance(img_path)
    for image_path in IMAGE_PATHS:
        calculate_Distance(image_path, focalLength)
        cv2.waitKey(0)
    cv2.destroyAllWindows()
updatedupdated2021-03-232021-03-23