快速计算warp矩阵

时间:2014-01-29 10:02:56

标签: image performance matlab

对于固定和给定的tform,图像处理工具箱中的imwarp命令

  B = imwarp(A,tform)

相对于A是线性的,意味着存在一些稀疏矩阵W,取决于tform但不依赖于A ,这样可以等效地实现上述

  B(:)=W*A(:)

对于所有固定已知尺寸的A [n,n]。我的问题是是否有快速/有效的计算选项W.当我需要转置操作W时,矩阵形式是必要的。'* B(:),或者如果我需要做W \ B(:)或类似的线性代数我不能直接通过imwarp做的事情。

我知道可以通过

逐列计算W
   E=zeros(n);
   W=spalloc(n^2,n^2,4*n^2);

   for i=1:n^2

    E(i)=1;
     tmp=imwarp(E,tform);
    E(i)=0;

    W(:,i)=tmp(:);

   end

但这是蛮力而且缓慢。

例程FUNC2MAT稍微更优,因为它使用循环来计算/收集每列W(:,i)的稀疏条目数据I,J,S。然后,在循环之后,它使用它来构造整个稀疏矩阵。它还提供使用PARFOR循环的选项。但是,这仍然比我想要的慢。

有人可以提出更多速度最佳的替代方案吗?

修改

对于那些对我的说法感到不舒服的说法,即(a,tform)是线性的w.r.t. A,我在下面包含了演示脚本,它测试了随机输入图像和tform数据的叠加属性。它可以反复运行,看nonlinearityError总是很小,很容易归因于浮点噪声。

tform=affine2d(rand(3,2));
 %tform=projective2d(rand(3));

fun=@(A) imwarp(A,tform,'cubic');

I1=rand(100); I2=rand(100);
c1=rand; c2=rand;


LHS=fun(c1*I1+c2*I2);  %left hand side
RHS=c1*fun(I1)+c2*fun(I2); %right hand side

linearityError = norm(LHS(:)-RHS(:),'inf')

2 个答案:

答案 0 :(得分:0)

实际上非常简单:

W = sparse(B(:)/A(:));

请注意,W不是唯一的,但此操作可能会产生最稀疏的结果。另一种计算方法是

W = sparse( B(:) * pinv(A(:)) );

但这导致稀疏(但仍然有效)的结果要少得多。

答案 1 :(得分:0)

我使用光流场[u,v]构建了变形矩阵,它适用于我的应用

% this function computes the warping matrix

% M x N is the size of the image

function [ Fw ] = generateFwi( u,v,M,N )

  Fw = zeros(M*N, M*N);

  k =1;

  for i=1:M

    for j= 1:N

      newcoord(1) = i+u(i,j);
      newcoord(2) = j+v(i,j);



      newi = newcoord(1);


      newj = newcoord(2);


      if newi >0 && newj >0

        newi1x = floor(newi);
        newi1y = floor(newj);
        newi2x = floor(newi);
        newi2y = ceil(newj);
        newi3x = ceil(newi);  % four nearest points to the given point
        newi3y = floor(newj);
        newi4x = ceil(newi);
        newi4y = ceil(newj);
        x1 = [newi,newj;newi1x,newi1y];
        x2 = [newi,newj;newi2x,newi2y];
        x3 = [newi,newj;newi3x,newi3y];
        x4 = [newi,newj;newi4x,newi4y];
        w1 = pdist(x1,'euclidean');
        w2 = pdist(x2,'euclidean');
        w3 = pdist(x3,'euclidean');
        w4 = pdist(x4,'euclidean');
        if ceil(newi) == floor(newi) && ceil(newj)==floor(newj)  % both the new coordinates are integers
          Fw(k,(newi1x-1)*N+newi1y) = 1;
        else if ceil(newi) == floor(newi)  % one of the new coordinates is an integer
          w = w1+w2;  
          w1new = w1/w;
          w2new = w2/w;
          W  = w1new*w2new;
          y1coord = (newi1x-1)*N+newi1y;
          y2coord = (newi2x-1)*N+newi2y;
          if y1coord <= M*N && y2coord <=M*N
            Fw(k,y1coord) = W/w2new;
            Fw(k,y2coord) = W/w1new;
          end
          else if ceil(newj) == floor(newj)  % one of the new coordinates is an integer
            w = w1+w3;
            w1 = w1/w;
            w3 = w3/w;
            W = w1*w3;
            y1coord = (newi1x-1)*N+newi1y;
            y2coord = (newi3x-1)*N+newi3y;
            if y1coord <= M*N && y2coord <=M*N
              Fw(k,y1coord) = W/w3;
              Fw(k,y2coord) = W/w1;
            end
            else        % both the new coordinates are not integers
              w  = w1+w2+w3+w4;
              w1 = w1/w;
              w2 = w2/w;
              w3 = w3/w;
              w4 = w4/w;
              W = w1*w2*w3 + w2*w3*w4 + w3*w4*w1 + w4*w1*w2;
              y1coord = (newi1x-1)*N+newi1y;
              y2coord = (newi2x-1)*N+newi2y;
              y3coord = (newi3x-1)*N+newi3y;
              y4coord = (newi4x-1)*N+newi4y;
              if y1coord <= M*N && y2coord <= M*N && y3coord <= M*N && y4coord <= M*N
                Fw(k,y1coord) = w2*w3*w4/W;
                Fw(k,y2coord) = w3*w4*w1/W;
                Fw(k,y3coord) = w4*w1*w2/W;  
                Fw(k,y4coord) = w1*w2*w3/W;
              end
            end
          end
        end
      else
        Fw(k,k) = 1;
      end
      k=k+1;
    end
  end 
end