我正在开发一个应用程序,我需要纠正从移动相机平台拍摄的图像。平台测量滚动角,俯仰角和偏航角,我希望通过这种信息的某种变换使图像看起来像是从正上方拍摄的。
换句话说,我想要一个完美的方形平躺在地上,从远处拍摄一些相机方向,进行转换,这样广场就完全对称了。
我一直试图通过OpenCV(C ++)和Matlab来做到这一点,但我似乎缺少一些关于如何做到的基本原则。
在Matlab中,我尝试了以下内容:
%% Transform perspective
img = imread('my_favourite_image.jpg');
R = R_z(yaw_angle)*R_y(pitch_angle)*R_x(roll_angle);
tform = projective2d(R);
outputImage = imwarp(img,tform);
figure(1), imshow(outputImage);
其中R_z / y / x是标准旋转矩阵(用度数实现)。
对于某些偏航旋转,一切正常:
R = R_z(10)*R_y(0)*R_x(0);
结果如下:
如果我尝试围绕X轴或Y轴旋转相同数量的图像,我会得到如下结果:
R = R_z(10)*R_y(0)*R_x(10);
然而,如果我旋转10度,除以一些巨大的数字,它开始看起来不错。但话说回来,这是一个没有研究价值的结果:
R = R_z(10)*R_y(0)*R_x(10/1000);
有人可以帮助我理解为什么围绕X轴或Y轴旋转会使转变变得疯狂吗?有没有办法解决这个问题而不用一些随机数和其他魔术技巧?这可能是某些可以使用某种欧拉参数解决的东西吗?任何帮助将受到高度赞赏!
更新:完整设置和测量
为了完整性,添加了完整的测试代码和初始图像,以及欧拉角平台:
代码:
%% Transform perspective
function [] = main()
img = imread('some_image.jpg');
R = R_z(0)*R_y(0)*R_x(10);
tform = projective2d(R);
outputImage = imwarp(img,tform);
figure(1), imshow(outputImage);
end
%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
R = [cosd(psi) -sind(psi) 0;
sind(psi) cosd(psi) 0;
0 0 1];
end
%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
R = [cosd(theta) 0 sind(theta);
0 1 0 ;
-sind(theta) 0 cosd(theta) ];
end
%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
R = [1 0 0;
0 cosd(phi) -sind(phi);
0 sind(phi) cosd(phi)];
end
初始图片:
BODY坐标系中的相机平台测量:
Roll: -10
Pitch: -30
Yaw: 166 (angular deviation from north)
根据我的理解,偏航角与变换没有直接关系。但是,我可能错了。
其他信息:
我想指定使用设置的环境不包含可以可靠地用作参考的线(海洋照片)(地平线通常不在图片中)。此外,初始图像中的方块仅用作衡量转换是否正确的度量,并且不会出现在真实场景中。
答案 0 :(得分:7)
所以,这就是我最终要做的事情:我认为除非您实际处理3D图像,否则纠正照片的视角是2D操作。考虑到这一点,我用零和1替换了变换矩阵的z轴值,并对图像应用了2D仿射变换。
使用测量的Roll = -10和Pitch = -30旋转初始图像(参见初始帖子),方法如下:
R_rotation = R_y(-60)*R_x(10);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ]
这意味着将相机平台旋转到虚拟相机方向,其中相机放置在场景上方,指向正下方。请注意上面矩阵中用于滚动和俯仰的值。
此外,如果旋转图像使其与平台标题对齐,则可能会添加围绕z轴的旋转,从而产生:
R_rotation = R_y(-60)*R_x(10)*R_z(some_heading);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ]
请注意,这不会改变实际图像 - 它只会旋转它。
因此,围绕Y轴和X轴旋转的初始图像如下所示:
如上所示,执行此转换的完整代码是:
% Load image
img = imread('initial_image.jpg');
% Full rotation matrix. Z-axis included, but not used.
R_rot = R_y(-60)*R_x(10)*R_z(0);
% Strip the values related to the Z-axis from R_rot
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ];
% Generate transformation matrix, and warp (matlab syntax)
tform = affine2d(R_2d);
outputImage = imwarp(img,tform);
% Display image
figure(1), imshow(outputImage);
%*** Rotation Matrix Functions ***%
%% Matrix for Yaw-rotation about the Z-axis
function [R] = R_z(psi)
R = [cosd(psi) -sind(psi) 0;
sind(psi) cosd(psi) 0;
0 0 1];
end
%% Matrix for Pitch-rotation about the Y-axis
function [R] = R_y(theta)
R = [cosd(theta) 0 sind(theta);
0 1 0 ;
-sind(theta) 0 cosd(theta) ];
end
%% Matrix for Roll-rotation about the X-axis
function [R] = R_x(phi)
R = [1 0 0;
0 cosd(phi) -sind(phi);
0 sind(phi) cosd(phi)];
end
感谢您的支持,希望这有助于某人!
答案 1 :(得分:3)
我认为你可以通过这种方式获得转型:
1)让你有四个3d点A(-1,-1,0),B(1,-1,0),C(1,1,0)和D(-1,1,0) )。你可以采取任何4个非共线点。它们与图像无关。
2)你有变换矩阵,所以你可以通过用变换矩阵乘以点坐标来设置你的相机。并且你将获得相对于摄像机位置/方向的3d坐标。
3)您需要将您的点投影到屏幕平面。最简单的方法是使用ortographic投影(简单地忽略深度坐标)。在这个阶段,您已经获得了转换点的2D投影。
4)一旦你有2组2D点坐标(步骤1中没有第3个坐标的集合和第3步中的集合),你就可以用标准的方式计算单应矩阵。
5)对图像应用逆同态变换。
答案 2 :(得分:2)
你需要估计单应性。对于现成的Matlab解决方案,请参阅http://www.robots.ox.ac.uk/~vgg/hzbook/code/中的函数vgg_H_from_x_lin.m
。
理论深入研究计算机视觉教科书,例如http://szeliski.org/Book/或http://programmingcomputervision.com/downloads/ProgrammingComputerVision_CCdraft.pdf
第3章中可自由使用的教科书答案 3 :(得分:2)
由于我对相机参数的误解,我的答案可能不正确,但我想知道Yaw / Pitch / Roll是否相对于物体的位置。我使用了general rotations的公式,我的代码在下面(旋转函数R_x
,R_y
和R_z
是从你的复制的,我没有在这里粘贴它们)
close all
file='http://i.stack.imgur.com/m5e01.jpg'; % original image
I=imread(file);
R_rot = R_x(-10)*R_y(-30)*R_z(166);
R_rot = inv(R_rot);
R_2d = [ R_rot(1,1) R_rot(1,2) 0;
R_rot(2,1) R_rot(2,2) 0;
0 0 1 ];
T = maketform('affine',R_2d);
transformedI = imtransform(I,T);
figure, imshow(I), figure, imshow(transformedI)
结果:
这表明您仍然需要一些旋转操作才能在脑海中获得“正确”的对齐(但可能没有必要在相机的脑海中找到正确的位置)。
所以我将R_rot = inv(R_rot);
更改为R_rot = inv(R_rot)*R_x(-5)*R_y(25)*R_z(180);
,现在它给了我:
看起来更像你想要的。 感谢。