opencv-python单目相机测距
时间: 2025-02-01 15:08:52 浏览: 68
### 使用 OpenCV-Python 实现单目相机测距
#### 1. 像素坐标系与相机坐标系
为了理解单目相机测距的工作原理,首先要了解两个重要的坐标系:像素坐标系和相机坐标系。像素坐标系用于描述图像中的位置,而相机坐标系则表示三维空间中相对于相机的位置。
- **像素坐标系**:二维平面上的点由(x, y)表示。
- **相机坐标系**:三维空间中的点由(Xc, Yc, Zc)表示[^3]。
#### 2. 转换到世界坐标系
通过已知的目标尺寸以及其在图像上的投影大小,可以推算出目标距离。这涉及到将相机坐标系下的数据转换成世界坐标系的数据。此过程依赖于内外参矩阵来完成变换操作。
#### 3. 获取相机参数
要实现精确的距离测量,需要获取相机内部参数(焦距f、主点cx/cy)。可以通过标定板配合OpenCV函数`cv.calibrateCamera()`获得这些参数。对于外部参数,则是在拍摄时固定不变的情况下求解得到旋转和平移向量R|t[]。
```python
import cv2 as cv
import numpy as np
# 加载棋盘格角点检测结果
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.
criteria = (cv.TERM_CRITERIA_EPS + cv.TERM_CRITERIA_MAX_ITER, 30, 0.001)
for fname in images:
img = cv.imread(fname)
gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret, corners = cv.findChessboardCorners(gray, patternSize=(9,6), None)
if ret == True:
objp = np.zeros((6*9,3), np.float32)
objp[:,:2] = np.mgrid[0:9,0:6].T.reshape(-1,2)*square_size
objpoints.append(objp)
imgpoints.append(corners)
ret, mtx, dist, rvecs, tvecs = cv.calibrateCamera(objpoints, imgpoints, gray.shape[::-1],None,None)
```
#### 4. 计算实际距离
假设有一个已知宽度的对象,在不同距离处拍摄的照片里它所占有的像素数会变化。利用这一点就可以构建比例关系从而估算未知物体离镜头有多远:
\[ \text{distance} = (\text{known_width}/\text{pixel_width}) * f_x \]
其中 `fx` 是相机内参里的水平方向焦距;`known_width` 表示被摄体的实际物理宽度;`pixel_width` 则是从图像上读取出来的该对象占据了多少个像素列宽。
```python
def find_marker(image):
# 将输入图像转化为灰度图并进行高斯模糊处理减少噪声影响
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
blurred = cv.GaussianBlur(gray, (5, 5), 0)
# 边缘检测寻找轮廓
edged = cv.Canny(blurred, 35, 125)
cnts = cv.findContours(edged.copy(), cv.RETR_LIST, cv.CHAIN_APPROX_SIMPLE)[-2]
c = max(cnts , key=cv.contourArea)
return cv.minAreaRect(c)
def distance_to_camera(knownWidth, focalLength, perWidth):
return (knownWidth * focalLength) / perWidth
KNOWN_DISTANCE = 24.0
KNOWN_WIDTH = 11.0
IMAGE_PATHS = ["images/{}.png".format(i) for i in range(1, 6)]
marker = find_marker(cv.imread(IMAGE_PATHS[0]))
focalLength = (marker[1][0] * KNOWN_DISTANCE) / KNOWN_WIDTH
for imagePath in IMAGE_PATHS:
image = cv.imread(imagePath)
marker = find_marker(image)
inches = distance_to_camera(KNOWN_WIDTH, focalLength, marker[1][0])
box = cv.cv.BoxPoints(marker) if imutils.is_cv2() else cv.boxPoints(marker)
box = np.int0(box)
cv.drawContours(image, [box], -1, (0, 255, 0), 2)
cv.putText(image, "%.2fft" % (inches / 12),
(image.shape[1] - 200, image.shape[0] - 20),
cv.FONT_HERSHEY_SIMPLEX,
2.0, (0, 255, 0), 3)
cv.imshow("image", image)
cv.waitKey(0)
```
阅读全文
相关推荐
















