【问题标题】:Spiral loop on a matrix from a point从点开始在矩阵上的螺旋环
【发布时间】:2015-06-10 13:01:44
【问题描述】:

我有一个如下所示的 2D 网格,想从 X、Y 开始并保存窗口的角 (W) 和 (OP) 的重叠。我已经尝试过these 代码,但它们都不符合我的目的。

正如演示的那样,我想从一个随机点(黑色单元格)开始,并将每个新窗口的角位置(由黑色圆圈显示)保存在一个螺旋循环中。该算法应该用于任何网格大小(不一定是正方形)和任何起点位置。

Matlab 也有一个函数(螺旋),和我想要的类似,但它不需要网格、窗口大小和重叠(OP)。

我希望这个数字有以下输出:(8,12) (11,12) (11,9) (8,9) (4,9) (4,12) (4,15) ...

我正在使用以下代码,它从一个角落开始,使用定义的 W、OP 和矩阵大小逐步填充矩阵:

W = [10 12];
OP = [4 3];

M = zeros(100,110);

for i=[1:W(1)-OP(1):size(M,1)-W(1), size(M,1)-W(1)+1]
  for j=[1:W(2)-OP(2):size(M,2)-W(2), size(M,2)-W(2)+1]
      block = rand(W(1),W(2));
      M(i:i+W(1)-1, j:j+W(2)-1) = block;
      imagesc(M); axis equal tight xy
      pause(.1)
  end;
end;

所以,以更清晰的方式,我应该如何更改“上方”代码以便从位置(x,y)开始并根据 W、OP 和大小(M)螺旋填充整个矩阵。

谢谢!

【问题讨论】:

  • 图很不清楚。我不知道您要保存哪些位置。
  • 您能否使用最少的样本输入数据并告诉我们预期的输出?此外,重叠区域的宽度可能不止一个元素,对吧?
  • 我编辑了这个问题。是的,OP 可以是多个元素。
  • 我在文档中看不到任何 spiral 函数。你有参考吗?
  • @Sam:我假设您的示例应该是 (8,12) (11,12) (11,9) (8,9) (5,9) (5,12) (5,15),所以步长总是 3?

标签: arrays matlab loops matrix


【解决方案1】:

基本问题

让数据定义为:

step = 3;  %// step size
x0 = 8;    %// x coordinate of origin
y0 = 12;   %// y coordinate of origin
N = 32;    %// number of steps

那么螺旋的坐标可以作为复平面中的值得到如下

z = x0+1j*y0 + step*cumsum([0 -1j.^(-floor(sqrt(4*(0:N)+1))-1)]);

当然,xy坐标是那么

x = real(z);
y = imag(z);

使用上面给出的示例值,plot(z,'o-')(或plot(x,y,'o-'))会生成图表

关键是生成序列1,2,3,3,4,4,5,5,5,6,6,6,7,7,7,7,8,8,8,8... 我感谢 OEIS for solving that part。该序列原来是 4n+1 的平方根的整数部分,对于 n=1,2,3,...

如何包含重叠和窗口大小

为了考虑重叠,在Daniel's suggestion 之后,从step 中减去它的值。

考虑窗口大小,N 应该足够大,以使螺旋线到达窗口边界外的某个点;然后只保留前面的点。

由于很难预先计算N 的大小,一种可能的方法是以指数方式 在循环中增加N,直到它足够大。指数增长确保循环迭代的次数会很小。下面的代码使用 2 的幂来表示 N

%// Data
step = 3;     %// step size
overlap = 1;  %// overlap
x0 = 20;      %// x coordinate of origin
y0 = 15;      %// y coordinate of origin
xmin = 0;     %// window boundary: min x
xmax = 40;    %// window boundary: max x
ymax = 30;    %// window boundary: min y
ymin = 0;     %// window boundary: max y

%// Computations
stepov = step-overlap;
N = 8; %// Initial value. Will be increased as needed
done = false;
while ~done
    z = x0+1j*y0 + stepov*cumsum([0 -1j.^(-floor(sqrt(4*(0:N)+1))-1)]);
        %// compute coordinates of N points
    ind = find(real(z)<xmin | real(z)>xmax | imag(z)<ymin | imag(z)>ymax, 1);
        %// find index of first z out of boundary, if any
    done = ~isempty(ind); %// exit if we have reached outside window boundary
    N = N*2; %// increase number of steps for next try
end
z = z(1:ind-1); %// only keep values that are within the boundary
x = real(z);
y = imag(z);

根据代码中的数据,得到的图形如下。请注意,最后一点是 (38,0)。下一个点是 (38,-2),它位于窗口边界之外。

【讨论】:

  • 很好很聪明!再加上您使用1j 作为虚数单位的事实:)
  • @Benoit_11 谢谢!当一个问题可以用复数自然地解决时,我喜欢它:-)
  • 同意这很优雅!我把这个问题变成了最喜欢的哈哈
  • 感谢您的回答。如何在您的脚本中使用描述的参数? (OP,网格大小)您已经考虑了原点和步长,但我还需要考虑 OP 和网格大小。
  • @Sam:您必须将step 设置为gridsize-op。生成左下角时,只有到下一个左下角的距离是相关的。
【解决方案2】:

这是一段产生预期输出的代码。那里只需要对spiral_generic 进行细微更改即可满足您的要求:

function demo()
spiral_generic([10,11],[3,4])
W = [10 12];
OP = [4 3];
%make sure your start point is really on the grid of r and c, this is not checked!
start = [19,28];
M = zeros(100,110);
r=[1:W(1)-OP(1):size(M,1)-W(1), size(M,1)-W(1)+1];
c=[1:W(2)-OP(2):size(M,2)-W(2), size(M,2)-W(2)+1];
startindex=[find(r==start(1),1,'first'),find(c==start(2),1,'first')];
A=spiral_generic([numel(r),numel(c)],startindex);
[~,idx]=sort(A(:));
[ridx,cidx]=ind2sub(size(A),idx);
%blocks contains the lower left corners in order of processing.
blocks=[r(ridx);c(cidx)];
for blockindex=blocks
       block = rand(W(1),W(2));
       M(blockindex(1):blockindex(1)+W(1)-1, blockindex(2):blockindex(2)+W(2)-1) = block;
       imagesc(M);
       pause(.1)
end

end
function A = spiral_generic(n, P)
% Makes NxN matrix filled up spirally starting with point P
  r = max([P - 1, n - P]);              % Radius of the bigger matrix
  M = spiral(2 * r + 1);                % Bigger matrix itself
  M = permute(M,[2,1]);                 % changing start direction of the spiral
  M = M(:,end:-1:1);                    % chaning spin orientation
  C = r + 1 - (P - 1);                  % Top-left corner of A in M
  A = M(C(1):C(1)+n(1)-1, C(2):C(2)+n(2)-1);  % Get the submatrix
  [~, order] = sort(A(:));              % Get elements' order
  A(order) = 1:(n(1)*n(2));                     % Fill with continous values
end

【讨论】:

  • 对方阵有用吗?我的矩阵不是正方形,它的大小是 101x200,我的窗口大小不是正方形,它是 20x15,重叠是 5
  • @Sam:已更新,需要进行小改动。
  • 我可以定义起点吗? (代码中的“中心”),因为我的起点不在矩阵的中心。看上图可以看到黑色单元格不在中间。
  • 是的,中心可以改变。您没有描述到达边界时它的行为方式,因此术语 floor(min(center./window_size))*2+1 可能需要更改。
  • 我用这个更正了它:for blockindex=1:size(blocks,2) block = rand(W(1),W(2)); M(blocks(1,blockindex):blocks(1,blockindex)+W(1)-1, blocks(2,blockindex):blocks(2,blockindex)+W(2)-1) = block;图像c(M);轴等于紧 xy 暂停(.1)结束
猜你喜欢
  • 2022-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多