仅使用外参矩阵实现透视变换的技术问题咨询
我有若干由同一鱼眼镜头传感器拍摄的录像,每段录像中传感器仅会沿单一或多个方向(左、右、上、下、右上、左下)旋转,且我拥有每帧的XYZ角度差值。
我希望通过透视变换对齐同一段录像中的任意两帧。
为进行测试,我选取了一段传感器主要向左旋转的录像中的两张图像,已获取对应的旋转矩阵R = [r1; r2; r3]和平移向量t = [0;0;0]。
我用到了单应性矩阵公式:
$$H = K \cdot [r1; r2; t]$$
以下是我的C++ OpenCV实现代码:
Mat K = (Mat_<double>(3, 3) << fx, 0, cx, 0, fy, cy, 0, 0, 1); Mat t = (cv::Mat_<double>(3, 1) << 0, 0, 0); // Create M by horizontally stacking r1, r2, and t Mat M; cv::hconcat(std::vector<cv::Mat>{R.col(0), R.col(1), t}, M); Mat H = K * M; // load frames Mat frame1 = imread("frame1.tif", IMREAD_UNCHANGED); Mat frame2 = imread("frame2.tif", IMREAD_UNCHANGED); // Warp Mat warped = Mat::zeros(frame1.rows, frame1.cols, frame1.type()); cv::warpPerspective(frame1, warped, H, Size(warped.cols, warped.rows), INTER_LINEAR, BORDER_CONSTANT);
但变换后的图像像素值均为1818,我怀疑相机内参矩阵K存在错误,现提出以下问题:
0. 我使用的单应性矩阵H的公式是否正确?
- 若没有相机的内参参数,如何获取矩阵K?
- 鱼眼镜头是否会影响我的实现方案?我使用的是未去畸变的原始图像?
0. 单应性矩阵公式的正确性
你用的公式不完全正确。这个公式仅适用于纯平面场景的情况,而你的场景是相机绕自身旋转(无平移,t=0),此时正确的单应性公式应该是:
$$H = K \cdot R \cdot K^{-1}$$
因为当相机纯旋转时,空间中任意点的投影变换是通过相机内参、旋转矩阵和内参逆矩阵的组合实现的,而不是截取R的前两列加t。你之前的公式是针对相机看向平面且有平移的场景,完全不匹配当前纯旋转的场景,这也是变换后图像异常的核心原因之一。
1. 获取相机内参矩阵K的方法
如果没有厂商提供的内参参数,可以通过OpenCV的相机标定工具来获取:
- 准备打印好的棋盘格标定板(比如8x6、9x6的角点规格)
- 从不同角度、距离拍摄至少10-20张标定板图像
- 使用
cv::calibrateCamera()函数计算内参K(包含fx, fy, cx, cy)和畸变系数 - 如果你用的是鱼眼镜头,需要用
cv::fisheye::calibrate()专门的鱼眼标定函数,因为鱼眼的畸变模型和普通针孔相机不同
另外,如果你只是做测试,也可以先假设一个近似的K:比如fx和fy设为图像宽度的0.8-1.2倍,cx和cy设为图像宽高的中心位置(比如图像宽W,高H,则cx=W/2,cy=H/2),但这种近似值仅能用于初步验证,正式场景必须用标定得到的准确值。
2. 鱼眼镜头对实现方案的影响
会有严重影响,因为你当前的实现是基于针孔相机模型的透视变换,而鱼眼镜头的成像模型是完全不同的:
- 鱼眼镜头使用的是球面投影模型,而非针孔相机的透视投影模型,
cv::warpPerspective()是针对透视投影的变换,无法处理鱼眼图像的畸变和旋转映射 - 未去畸变的原始鱼眼图像,直接用针孔模型的单应性变换会导致严重的映射错误,甚至出现全黑/异常像素值的情况
正确的处理流程应该是:
- 先对鱼眼图像进行去畸变,转换成针孔相机模型的图像(用
cv::fisheye::undistortImage()) - 再针对去畸变后的图像,使用纯旋转场景的单应性公式
H = K * R * K^{-1}进行透视变换对齐 - 如果你需要保留鱼眼格式的对齐结果,可以在变换后再将图像重新畸变回鱼眼格式
或者直接使用鱼眼相机的旋转映射方法:通过旋转矩阵计算鱼眼图像中每个像素对应的原始像素位置,直接进行重映射,而不是用透视变换。
内容的提问来源于stack exchange,提问作者Orel H

