用MATLAB计算摄像机矩阵
我目前正试图计算给定一组世界点(X)及其对应的图像点(X)的相机矩阵p。但是,在测试结果时,P(3 x 4摄影机矩阵)乘以世界点并不能给出正确的对应图像点。但是,只有PX=x的第一列。另一列不会返回近似的图像点 代码: 第一列的输出效果良好:用MATLAB计算摄像机矩阵,matlab,matrix,camera,computer-vision,projection,Matlab,Matrix,Camera,Computer Vision,Projection,我目前正试图计算给定一组世界点(X)及其对应的图像点(X)的相机矩阵p。但是,在测试结果时,P(3 x 4摄影机矩阵)乘以世界点并不能给出正确的对应图像点。但是,只有PX=x的第一列。另一列不会返回近似的图像点 代码: 第一列的输出效果良好: >> p*XX{1} ans = 0.0461 0.0922 0.0154 >> ans/0.0154 ans = 2.9921 5.9841 0.9974 >>
>> p*XX{1}
ans =
0.0461
0.0922
0.0154
>> ans/0.0154
ans =
2.9921
5.9841
0.9974
>> xx{1}
ans =
3
6
1
第二列的输出无效:
>> p*XX{2}
ans =
0.5202
0.0867
0.1734
>> ans/0.1734
ans =
2.9999
0.5000
1.0000
>> xx{2}
ans =
6
1
2
顺便说一下,有人告诉我,在计算相机矩阵之前,我需要规范化世界点和图像点。我还没有完成这一步,也不知道怎么做。如果这是导致问题的原因,请说明可以采取的措施。先谢谢你 这是因为您没有正确地索引到矩阵中。您正在使用线性索引来访问矩阵的每一列。在这种情况下,您的
for
循环需要独立地访问每一列。因此,for
循环的每次迭代必须访问3D点的4个元素组和2D点的3个元素组
因此,您只需对for
循环执行以下操作:
for i = 0:(nX-1)
XX{i+1} = transpose(X(4*i + 1 : 4*(i + 1)));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(3*i + 1 : 3*(i + 1)));
end
A = [zeros(N, 4) -X.' bsxfun(@times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(@times, -x(1,:).', X.')];
在此之后,代码应该可以正常工作。为了验证,我们可以循环通过每个3D点,并在使用单元时确定其2D等效值:
out = zeros(size(xx)); % Declare output matrix
for ii = 1 : numel(XX) % For each 3D point...
out(:,ii) = p * XX{ii}; % Transform the point
out(:,ii) = out(:,ii) / out(end,ii); % Normalize
end
因此,我们得到:
>> out
out =
3.0000 2.0000 1.0000
6.0000 5.0000 4.0000
1.0000 1.0000 1.0000
与您的x
进行比较:
>> x
x =
3 2 1
6 5 4
1 1 1
建议-使用矢量化
如果我能提出一些建议,请不要在这里使用单元格数组。可以创建方程矩阵,以便使用矢量化进行求解。具体而言,您可以直接创建矩阵A
,而无需为循环创建任何:
for i = 0:(nX-1)
XX{i+1} = transpose(X(4*i + 1 : 4*(i + 1)));
end
for i = 0:(nx-1)
xx{i+1} = transpose(x(3*i + 1 : 3*(i + 1)));
end
A = [zeros(N, 4) -X.' bsxfun(@times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(@times, -x(1,:).', X.')];
如果您拥有MATLAB R2016b及更高版本,您可以通过内部广播实现这一点:
A = [zeros(N, 4) -X.' x(2,:).' .* X.';
X.' zeros(N, 4) -x(1,:).' .* X.']
请注意,由于矢量化,与原始矩阵A
相比,您将看到行被洗牌。因为我们正在求解矩阵A
的空空间,所以洗牌行没有效果。因此,您的代码可以简化为:
X = [1 2 3; 4 5 6; 7 8 9; 1 1 1];
x = [3 2 1; 6 5 4; 1 1 1];
A = [zeros(N, 4) -X.' bsxfun(@times, x(2,:).', X.');
X.' zeros(N, 4) bsxfun(@times, -x(1,:).', X.')];
% Use this for MATLAB R2016b and up
% A = [zeros(N, 4) -X.' x(2,:).' .* X.';
% X.' zeros(N, 4) -x(1,:).' .* X.']
[u, s, v] = svd(A);
p = v(:, end);
p = reshape(p, 4, 3).';
要最终计算输出矩阵,只需使用简单的矩阵乘法。使用单元格这一事实要求您必须使用for
循环,而使用矩阵乘法则要快得多:
out = p * X;
然后,您可以获取结果的最后一行,并将其他每一行除以此行
out = bsxfun(@rdivide, out, out(end,:));
同样,使用MATLAB R2016b及更高版本,您可以这样做:
out = out ./ out(end,:);
求求你!可能是x(i+1:3+i)
中的索引错误。在命令窗口中单独运行此部件。这就是你想要的吗?我回答你的问题了吗?@rayryeng是的,现在它工作得很好!谢谢你详尽的回答。非常感谢@夏文森一点问题都没有。如果你愿意,我可以谈谈为什么你需要规范化点。不过,我觉得这应该是另一个问题。在此特定实例中,2D和3D点之间的值的大小大致相同,因此不需要标准化。