OpenCV未知相机参数时如何校正畸变图像生成鸟瞰视图
问题背景
我尝试将如下足球场图像转换为鸟瞰视图:
最初我仅使用Python环境下OpenCV的warpPerspective方法实现转换,得到的结果如下:
从结果可以看出原始图像存在畸变。我调研了图像去畸变的相关方法,根据现有资料,图像去畸变通常需要先完成相机标定,但我目前面临的问题是:没有拍摄这段足球场画面所用相机的任何参数信息,且仅拥有这一个拍摄角度的素材,难以开展常规相机标定工作。
现需要实现:在未知相机参数的前提下完成图像去畸变,得到准确的足球场鸟瞰视图,以下是可落地的实现方案,以及当前已编写的测试代码:
import cv2 as cv import numpy as np img = cv.imread("/Users/laulpee/Desktop/python/Screen Shot 2022-05-20 at 2.44.15 AM.png") print(img.shape) # 场地尺寸 60' x 90' h = 900 w = 1200 # 原始图像上选取的4个参考点 pt1 = np.float32([[2125,382],[1441,502],[3236,773],[3252,530]]) # 目标鸟瞰图上对应的4个坐标点 pt2 = np.float32([[0,0],[0,h],[w,h],[w,0]]) matrix = cv.getPerspectiveTransform(pt1, pt2) output = cv.warpPerspective(img,matrix,(w,h)) for i in range(0,4): cv.circle(img,(int(pt1[i][0]),int(pt1[i][1])),5,(0,0,255),cv.FILLED) window1 = cv.namedWindow("w1") cv.imshow(window1,img) cv.waitKey(0) cv.destroyWindow(window1) window2 = cv.namedWindow("w2") cv.imshow(window2,output) cv.waitKey(0) cv.destroyWindow(window2)
实现方案
仅用4个点做单应性变换失败的核心原因是:单应性变换只能校正平面的透视投影变形,无法修正镜头本身的径向/切向畸变。不需要做常规的标定板相机标定,足球场本身有大量标准几何约束,完全可以基于单张图完成自校正,按以下步骤操作即可:
- 提取场地直线约束:先在原图上手动标记10~15组分布在画面各区域的场地线段,覆盖画面边角、中心、上下左右所有位置,这些线段对应真实世界里的边线、底线、禁区线、中线,都是绝对笔直的,是校正畸变的核心参考。
- 无标定去畸变:普通运动相机、监控摄像头的畸变以径向畸变为主,切向畸变可以直接忽略,只需要优化k1、k2两个径向畸变系数即可。实现逻辑很简单:以「所有标记线段去畸变后,线段上点到拟合直线的距离总和最小」为优化目标,用scipy的
optimize模块迭代调整k1、k2参数,收敛后就能得到适配这张图的畸变系数,再用cv2.undistort生成去畸变后的原图。这个方法不需要任何相机先验参数,只要直线标记的分布足够均匀,校正精度完全满足鸟瞰图转换需求。 - 高精度透视变换:去畸变完成后,不要沿用之前的4个参考点,重新在去畸变图上标记6~10个已知真实坐标的特征点(比如场地四角、禁区四角、中圈和中线的交点),调用
cv2.findHomography计算变换矩阵,这个接口支持多对点做最小二乘拟合,比仅支持4对点的getPerspectiveTransform鲁棒性高很多,能抵消手动选点的误差。 - 局部优化(可选):如果变换后局部区域仍有轻微对齐偏差,可以把场地划分为中场、左禁区、右禁区3个区块,每个区块单独选点计算局部单应性矩阵做分段变换,就能消除残余的对齐误差。
避坑提示:不要尝试把畸变参数和单应性矩阵放在一起拟合,参数自由度太高很容易收敛到错误结果,先做去畸变、再算透视变换的分步流程稳定性最高。
内容的提问来源于stack exchange,提问作者Paul
相关产品推荐
相关产品推荐

