单目相机测距

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

单目相机测距

  • 一、理论
    • 1.像素坐标系
    • 1.相机坐标系
    • 1.转换到大地坐标系
  • 二、代码实现
    • 1.使用matlab找到相机参数
    • 2.使用opencv进行测距
  • 总结

一、理论

先说缺点:单目相机测距需要庞大的样本量(需要事先知道物体的大致高度)。
理论依据:小孔成像,相似三角形。
是:像素坐标系==>相机坐标系==>大地坐标系,三个坐标系之间的转换。

1.像素坐标系

通过图像,找到图像的感兴区域所在的真实位置:
单目相机测距_第1张图片
p为感兴区域,(u,v)为p在像素坐标系下的像素点,(u0,v0)为摄像机光轴和图像的交点,(x,y)为p在图像坐标系下的位置。

1.相机坐标系

单目相机测距_第2张图片

O2为相机所在位置,(X2,Y2)是相机坐标系,f为焦距(相机到图像的距离)。

1.转换到大地坐标系

单目相机测距_第3张图片
H是相机离地面的高度,α为相机的俯仰角,(X2,Y2)为大地坐标系,是P在大地的真实位置。

二、代码实现

1.使用matlab找到相机参数

使用matlab里面的图像处理和视觉的工具包:
在这里插入图片描述
导入标定板图片(Add Images):(从网上下载,最好导入15张以上)
单目相机测距_第4张图片
通过Camera Calibrator获取相机的参数(Calibrate):
单目相机测距_第5张图片

通过以上步骤,matlab的工作区里会有我们所需要的相机参数:
单目相机测距_第6张图片
得到内参矩阵(IntrinsicMatrix):
在这里插入图片描述
4378.63641114583 0 0
5.21127842219180 4376.52506346791 0
2862.91763839858 2221.66776871603 1

和畸变系数k1,k2(RadialDistortion)、p1,p2(TangentialDistortion):
k1, k2 = 0.119834359859580, -0.518385077316403
P1, p2 = -8.93400883990887e-05, -0.00140607066202787

内参矩阵和畸变矩阵用来矫正图片。

通过内参矩阵可以得到焦距fx和fy:(测距用)
4378.63641114583 4376.52506346791

2.使用opencv进行测距

1.对标定板进行矫正:

import numpy as np

def show(name):
    cv2.imshow('img', name)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

#内参数矩阵
k = np.array([[4378.63641114583 , 5.21127842219180	, 2862.91763839858	],
                         [0, 4376.52506346791,  2221.66776871603],
                         [0,0,1]])
#畸变系数矩阵,k1 k2 p1 p2 k3
d = np.array([0.119834359859580,  -0.518385077316403,  -8.93400883990887e-05, -0.00140607066202787, 0])
img = cv2.imread(r'./img.jpg')
h,w = img.shape[:2]

mapx, mapy = cv2.initUndistortRectifyMap(k,d,None,k,(w,h),5)

dst = cv2.remap(img, mapx,mapy,cv2.INTER_LINEAR)

h,w = dst.shape[:2]
h_1,w_1 = h/10,w/10
dst = cv2.resize(dst,(int(w_1),int(h_1)))
show(dst)

得到图片:
单目相机测距_第7张图片

2.对目标进行测距(预先知道物体在图像中的感兴区域和物体的大致高度):
代码如下(示例):

import cv2

def show(name):
    cv2.imshow('img', name)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
cap = cv2.imread(r'./cap.jpg')
h,w = cap.shape[:2]
h_1,w_1 = h/10, w/10
cap = cv2.resize(cap,(int(w_1),int(h_1)))
# cap_cutout = cap[95:310,260:400]
cap = cv2.rectangle(cap,(260,95),(400,310),(0,255,0),5)
fx = 4378.63641114583
fy = 4376.52506346791
y = 310-95
x = 400-260
distance = (fy*0.1)/(y*10)  #只求了y坐标的值。
distance = round(distance*100,2)
distance = str(distance)+'cm'
cap = cv2.putText(cap, distance,(260,85),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
print(distance)
show(cap)

得到的结果为:
单目相机测距_第8张图片


总结

单目相机测距需要大量的数据库作为测距的支撑,在项目中也需要通过yolo获取想要测量物体在图像中的感兴区域,通过对水杯的测距得到误差在0.36cm左右。

你可能感兴趣的:(python,matlab,opencv)