matlab - 我imrotate()图像,画了两条线,向后旋转这些线,并在原始图像中绘制它们,但是在MATLAB中没有得到预期的结果?

标签 matlab rotation translation image-rotation

我想做的是:
假设我有一个图像,我使用I旋转-45°(我得到imrotate)然后我画两条线I_RAB(平行线)最后,我将这两条线向后旋转(45°)并在原始图像中绘制它们。
我是怎么做到的##
我使用MATLAB函数旋转CD

I_R = imrotate(I,-45);

从Matlab的帮助中,我得到:B=imrotate(A,angle)将图像A绕其中心点逆时针方向旋转角度度。
但似乎I添加到图像的翻译我有
阅读内置的matlab函数的代码,似乎它使用了
函数来检查旋转的图像是否
符合身材这是我要找的翻译!!
这四个点组成两条平行线。
A = [x_A; u];
B = [x_B; u];

C = [x_A; d];
D = [x_B; d];

现在,我旋转这两行,使用函数I,只需调用以下两行:
[Af,Bf] = rotateTwoPoints(A,B,-45,O,true);
[Cf,Df] = rotateTwoPoints(C,D,-45,O,true);

其中imrotate()是旋转的原点。
我试过了,我是说这是情节的起源没有成功!
所以我用imrotate选择图像的质心这是错误的,因为质心不是一个中心。
现在,我使用图像的中心getOutputBound或使用A,B,C,D
但是当我在图像中画出这样的结果线时:
plot([Af(1) Bf(1)],[Af(2) Bf(2)],'k');
plot([Cf(1) Df(1)],[Cf(2) Df(2)],'k'); 

我得到的结果不正确!
问题:在iU R中,AB&CD包含我所称的BlueZone(参见图3)但是旋转的背线不能覆盖它!
图像的结果
这是旋转的图像和绘制的两条线(中间的两条红线对应于rotateTwoPoints()O):
然后在原始图像I中绘制旋转的线(黑体点对应于我旋转的中心):
图像已更新
问题:正如你所看到的,蓝色区域在两条线内但是,当向后旋转时,它变为外部,如下图所示(红色箭头指向蓝色区域):
更新添加了一个代码段
由于问题尚未解决,我选择了导致问题的代码,并将其添加为以下代码片段(文件中存储了一个变量,您可以下载here):
function Question()

% load image in I, the image is available online in the below link  
load I ;

% rotate I with -45° using imrotate
I_R = imrotate(I,-45);

% some data
x_A = 3 ;
x_B = 79;

u = 24;
d = 44;

% some meaningful Points : A,B,C and D that form two lines AB and CD
% parallels
A = [x_A; u];
B = [x_B; u];

C = [x_A; d];
D = [x_B; d];

% figure 1 contain two subplots 
figure(1);
% draw rotated image I_R
subplot(1,2,1), axis image, imagesc(I_R), hold on;
% draw two lines AB and CD in red in rotated image 
plot([A(1) B(1)],[A(2) B(2)],'r');
plot([C(1) D(1)],[C(2) D(2)],'r');
title('I_R the rotated image with the two lines AB and CD');

% draw original image I
subplot(1,2,2), axis image, imagesc(I)  , hold on;

% compute the middle of image I
axises=axis;
center = [mean(axises(1:2)),mean(axises(3:4))]';
% draw the center in red and as a point
plot(center(1),center(2),'ro');

% rotate the two lines, the result is the two lines AfBf and CfDf
[Af,Bf] = rotateTwoPoints(A,B,-45,center,true);
[Cf,Df] = rotateTwoPoints(C,D,-45,center,true);

% draw the rotated back lines in original image I
figure(1);
subplot(1,2,2);
plot([Af(1) Bf(1)],[Af(2) Bf(2)],'k');
plot([Cf(1) Df(1)],[Cf(2) Df(2)],'k');
title('the original image I with the two lines AfBf and CfDf');

function [Af,Bf] = rotateTwoPoints (A,B,t,Origin,isPlot)

% Definition of the rotation matrix (rotation around origin)
R=[ ...
    cosd(t) -sind(t)
    sind(t) cosd(t)
    ];

% translation 
At = A - Origin;
Bt = B - Origin;

% rotation of the points A and B
Ar = R*At;
Br = R*Bt;

% translation 
Af = Ar + Origin;
Bf = Br + Origin;

if isPlot == true

    figure(100)

    % Plot of the original line
    plot(A(1),A(2),'k*', B(1),B(2),'b*');
    line([A(1) B(1)],[A(2) B(2)], 'Color','r');

    grid on
    hold on

    % Plot the Origin around which the rotation will be
    plot(Origin(1),Origin(2),'k*','LineWidth',3);

    % Plot of the rotated line
    plot(Af(1),Af(2),'g*', Bf(1),Bf(2),'r*');
    line([Af(1) Bf(1)],[Af(2) Bf(2)], 'Color','b');
    legend('A','B','line AB','Origin','Af','Bf','line AfBf',['angle: ',num2str(t)],'Location','northeastoutside');
    daspect([1 1 1])

end

PS:我正在使用MATLAB r2012 b

最佳答案

正如您所说,旋转计算正确,如第一个图所示问题就在于结果的最终显示当你这样做的时候

plot([Af(1) Bf(1)],[Af(2) Bf(2)],'k');
plot([Cf(1) Df(1)],[Cf(2) Bf(2)],'k'); 

第二行有一个输入错误(第二个参数的第二个元素)-您将Bf(2)绘制为第二行的结尾,而不是Df(2)当我用Df(2)替换它时,它按预期绘制了平行线。
更新:
在注释中,我建议重构这段代码,以便对所有内容使用转换矩阵,以便可以对图像和覆盖应用相同的转换集这里是一个一般的大纲,你可以如何设置。
有两点需要注意。
Matlab对图像的约定是y=0是顶部imshow和related,然后将y=0放在顶部,y向下增加这是与plot相反的约定,因此当覆盖绘图和图像时,其中一个必须反转这对变换矩阵的使用有影响,主要的一个是旋转角度必须反转。
在matlab中,图像可以被看作是一个规则像素网格的z数据但是这些像素坐标没有存储,只是在显示图像时推断出来的因此,当您翻译图像,然后再次imshow时,转换并不明显,因为它重新推断了一组新的像素坐标,这些坐标恰好与未翻译图像的坐标相同为了解决这个问题,我们必须修正对图像的空间引用。
除此之外,二维变换使用3空间矩阵执行,因此我们需要在3空间中定义点(但随后将它们截断以在二维图中显示)。
所以让我们把这一切放在一起。
% get an image
I = imread('cameraman.tif');
% get spatial referencing information
Rcb = imref2d(size(I));

% define some test points in 3space
pta = [10; 10; 0];
ptb = [ 50;  10; 0];
% construct a test line in 2space from our test points
testline = [pta(1:2) ptb(1:2)];

% overlay line on plot
figure(90); clf
imshow(I,Rcb); truesize; hold on;
plot(testline(1, :), testline(2, :), 'y', 'linewidth', 4)

% define our transforms
% rotation angle (deg)
t = 45;

% a transform suitable for images
Rimage=[ ...
    cosd(t) -sind(t) 0
    sind(t) cosd(t) 0
    0 0 1
    ];
% the same transform suitable for points
Rpoints=[ ...
    cosd(-t) -sind(-t) 0
    sind(-t) cosd(-t) 0
    0 0 1
    ];

% make tform object suitable for imwarp
tform = affine2d(Rimage);

% transform image and spatial referencing with tform
[Ir, Rr] = imwarp(I, tform);

% transform points directly using matrix multplication
ptar = Rpoints*pta;
ptbr = Rpoints*ptb;

% construct the rotated line for plotting
newline = [ptar(1:2) ptbr(1:2)];

% the results
figure(91); clf
imshow(Ir, Rr); truesize; 
hold on;
plot(testline(1, :), testline(2, :), 'y', 'linewidth', 4)
plot(newline(1, :), newline(2, :), 'g', 'linewidth', 4)

在第二幅图中,我用绿色绘制了变形线,用黄色绘制了原始线,以作比较。
注意事项:
imwarp函数不直接使用旋转矩阵,您必须先从它构造一个tform对象,然后再提供它你当然可以一行完成这一切。
有两个矩阵有点不雅在这里我们只需要担心一个旋转就可以了,但是使用变换矩阵的关键是你可以通过矩阵的乘法把一系列变换连在一起如果你必须这样做两次,它会破坏一段原本优雅的代码,而这永远也做不到,所以可能最干净的方法是在整个过程的开始翻转你的图像,然后在必要时在最后翻转它们(例如,用于导出)。
点数据的簿记有点乏味有很多方法可以做到这一点,这取决于您选择采用的关于在列向量的哪个位置保持哪个坐标的约定我从来没有找到一个集能很好地处理3space转换和plot,以及根据应用程序的不同,什么最适合进行更改如果不是下一个维护者的话,Helper函数可以为您省去一些麻烦,如果您能够证明时间的合理性,那么将它全部打包到一个类中是最简单的。
更新2:
为了尽量减少3空间坐标的使用,我只需使用2空间向量将所有点描述为正常,然后仅在需要执行变换时添加虚拟z坐标。
所以你可能
testpoint = [1; 5]; % x and y xoordinates only
trpoint = Rpoints*[testpoint; 1];
trpoint = trpoint(1:2);

你可以把它放在包装器里,但是你不需要回避这样一个事实:你需要在imwarp部分使用3x3矩阵,这意味着你也需要在3space中指定你的坐标。
或者,可以截断坐标变换的旋转矩阵:
trpoint = Rpoints(1:2, 1:2)*testpoint;

但不管怎样,你得做些索引记账。
更新3:
OP不能访问imref2d,所以这里有一个实现相同结果的方法重要的是这条
imshow(Ir, Rr);

其中Rrimwarp函数输出的spstial引用对象如果没有,可以使用imshow'XData'参数手动为'YData'提供空间引用您需要先计算范围,然后决定一个约定imref2d使用(0,0)作为左上角的约定,当图像旋转时,原始图像的这个角保持为坐标(0,0),这样旋转的图像现在从y=[-181:181]和x=[0:363]延伸要获得这些值,需要转换图像的所有四个角,然后计算最大值和最小值。
xmax = size(I,2);
ymax = size(I,2);
corner1 = [xmax; 0; 0]+0.5;
corner2 = [xmax; ymax; 0]+0.5;
corner3 = [0; ymax; 0]+0.5;
corner4 = [0; 0; 0]+0.5;
tc1 = Rpoints*corner1;
tc2 = Rpoints*corner2;
tc3 = Rpoints*corner3;
tc4 = Rpoints*corner4;
corners = [tc1 tc2 tc3 tc4];
xlims = minmax(corners(1,:));
ylims = minmax(corners(2,:));

然后可以用这个替换imshow
imshow(Ir, 'xdata', xlims, 'ydata', ylims);

其他的都应该是一样的。
注意,当我这么做的时候,我得到的上面的值和imwarp对象中imref2d产生的值之间有一点差别该函数返回
XWorldLimits: [0.2264 363.2264]
YWorldLimits: [-181.5000 181.5000]

而我的付出
xlims: [0.7071  362.7458];
ylims: [-181.0193  181.0193];

如果不查一下imwarp的来源,我就无法解释这一点,而且,即使不是MEX在那个级别,我也不确定你能走多远才能被指控侵犯知识产权。
这些数字表示图像在轴上的位置,因此如果使用图像来选择点,它们可能会以十分之几的像素关闭如果你只是用图像作为参考,那么它应该足够接近。

关于matlab - 我imrotate()图像,画了两条线,向后旋转这些线,并在原始图像中绘制它们,但是在MATLAB中没有得到预期的结果?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30421612/

相关文章:

c++ - 绕错误的轴旋转

python - 旋转、缩放和平移二维坐标?

wordpress - 如何在 WordPress 中切换语言 "on-the-fly"

machine-learning - matlab中的最小二乘SVM

ios - 根据设备方向切换 View

ios - shouldAutoRotate 不能快速工作

Django 国际化和翻译问题

matlab - 在 Matlab 中将纪元转换为日期

matlab - 在Matlab中,如何对嵌套结构进行排序?

matlab - 如何在 MATLAB 中执行直接 Oblimin 旋转