快速/高效的方法来分解可分离的整数2D滤波器系数


21

我希望能够快速确定给定的整数系数2D内核是否可分为两个具有整数系数的1D内核。例如

 2   3   2
 4   6   4
 2   3   2

可分为

 2   3   2

 1
 2
 1

使用整数算术对可分离性的实际测试似乎相当简单,但是事实证明,分解为具有整数系数的一维滤波器比较困难。困难似乎在于以下事实:行或列之间的比率可能是非整数(比率分数),例如,在上述示例中,比率为2、1 / 2、3 / 2和2/3。

我真的不想使用像SVD这样的繁重方法,因为(a)满足我的需求在计算上相对昂贵,并且(b)仍然不一定有助于确定整数系数。

有任何想法吗 ?


更多信息

系数可以为正,负或零,并且可能存在一些病理情况,其中一维向量或两个一维向量之和为零。

-1   2  -1
 0   0   0
 1  -2   1

可分为

 1  -2   1

-1
 0
 1

1
我记得在大学时曾试图解决这个问题。我几乎成功了,但我不记得如何。=)既然您提到了它,我就不会停止思考!
声音

@Phonon:呵呵-一直在想-我可以从中得到一些启发。;-)
Paul R

除了double或float值,是否可以做同样的事情?
Diego Catalano 2014年

@DiegoCatalano:请参阅下面的丹尼斯答案,以及他在math.stackexchange.com上链接到的问题-我认为这对于更通用的浮点系数情况可能有用。
Paul R

@PaulR,一个人如何通过电子邮件与您联系?谢谢。
罗伊

Answers:


11

我已经@Phonon回答了,并对其进行了一些修改,以使它仅在顶部和左侧使用GCD方法,而不是在行/列总和上使用GCD方法。这似乎可以更好地处理病理病例。如果顶行或左列全为零,则仍然可能失败,但是可以在应用此方法之前检查这些情况。

function [X, Y, valid] = separate(M)    % separate 2D kernel M into X and Y vectors 
  X = M(1, :);                          % init X = top row of M
  Y = M(:, 1);                          % init Y = left column of M
  nx = numel(X);                        % nx = no of columns in M
  ny = numel(Y);                        % ny = no of rows in M
  gx = X(1);                            % gx = GCD of top row
  for i = 2:nx
    gx = gcd(gx, X(i));
  end
  gy = Y(1);                            % gy = GCD of left column
  for i = 2:ny
    gy = gcd(gy, Y(i));
  end
  X = X / gx;                           % scale X by GCD of X
  Y = Y / gy;                           % scale Y by GCD of Y
  scale = M(1, 1) / (X(1) * Y(1));      % calculate scale factor
  X = X * scale;                        % apply scale factor to X
  valid = all(all((M == Y * X)));       % result valid if we get back our original M
end

非常感谢@Phonon@Jason R为此提供了最初的想法。


10

得到它了!发布MATLAB代码,将在今晚或明天发布说明

% Two original arrays
N = 3;
range = 800;
a = round( range*(rand(N,1)-0.5) )
b = round( range*(rand(1,N)-0.5) )

% Create a matrix;
M = a*b;
N = size(M,1);

% Sanity check
disp([num2str(rank(M)) ' <- this should be 1!']);

% Sum across rows and columns
Sa = M * ones(N,1);
Sb = ones(1,N) * M;

% Get rid of zeros
SSa = Sa( Sa~=0 );
SSb = Sb( Sb~=0 );

if isempty(SSa) | isempty(SSb)
    break;
end

% Sizes of array without zeros
Na = numel(SSa);
Nb = numel(SSb);

% Find Greatest Common Divisor of Sa and Sb.
Ga = SSa(1);
Gb = SSb(1);

for l=2:Na
    Ga = gcd(Ga,SSa(l));
end

for l=2:Nb
    Gb = gcd(Gb,SSb(l));
end

%Divide by the greatest common divisor
Sa = Sa / Ga;
Sb = Sb / Gb;

%Scale one of the vectors
MM = Sa * Sb;
Sa = Sa * (MM(1) / M(1));

disp('Two arrays found:')
Sa
Sb
disp('Sa * Sb = ');
Sa*Sb
disp('Original = ');
M

谢谢-太好了-昨晚我正醒着,想着分解系数等,但是像这样使用GCD会更加简单和优雅。不幸的是,熨烫工作还是有困难的-它需要同时使用正系数和负系数,这可能导致情况恶化A=[-2 1 0 -1 2]; B=[2 -3 6 0 -1]; M=A'*B;。这里的问题是sum(A) = 0这样Sb = [0 0 0 0 0]。我将尝试修改您的算法,以便它使用系数的绝对值之和,看看是否有帮助。再次感谢您的帮助。
Paul R

确定-它看起来像你仍然可以得到GCDS和使用做缩放abs(M),即Sa=abs(M)*ones(N,1); Sb=ones(1,N)*abs(M);然后如上继续,但我还没有看到如何体征恢复SaSb在年底。我在上面的原始问题中添加了一个病理示例来说明问题。
Paul R

我想我现在有一个可行的解决方案-我将其作为单独的答案发布,但是您可以从中获得潜在的想法。再次感谢 !
Paul R

7

也许我正在解决这个问题,但是看来您可以:

  • NMAaii=0,1,,N1
  • j>0

    • aja0jrj
    • [RĴ
    • [RĴ一种Ĵ一种0Ĵ0X
    • 一种Ĵ一种0
  • X

XķñØ[R=Xķ一世=0ñ-1个X一世
  • XñØ[R
    XsC一种Ëd=ķXñØ[Rķ=1个2中号
    ķ中号

这不是最优雅的方法,可能有更好的方法,但是它应该可以工作,实现起来非常简单,并且对于中等大小的矩阵应该相对较快。


谢谢-我想在陷入细节之前我可能正朝着这个方向前进。对我而言,并不是总是100%清楚会使用此方法得出解决方案,但是无论如何,我可能应该对此进行编码,并通过一些示例进行尝试。我有一种预感,可能需要逐行和逐列地应用它,以查看哪种方法产生了“最佳”解决方案。感谢您抽出宝贵的时间来详细说明细节-我将忙于处理细节,并让您知道其工作原理。
Paul R

您是否找不到行的第一个元素的最大公约数,并以此来确定您的基向量?
Jim Clay 2012年

@JimClay:是的,如果您有可用的功能,那实际上就是最后要做的事情。
杰森R

3

xyzA|Axyz|
x y z
yzxx y z x y z ... 反过来。

(摘自 math.stackexchange上的一个可分解卷积的近似卷积。)


1
尽量不要用无法解释的链接回答问题。最好在答案中解释必要的细节,并仅包含链接以供参考;这样,如果链接中断,答案的基本细节仍然存在。
Sam Maloney

@SamMaloney:我认为没有必要这样做。该链接详细介绍了所有内容。它仍然会在“问答”搜索中弹出。那为什么不呢?
Naresh 2013年

1
@Naresh之所以仅提及它,是因为堆栈交换站点的目标之一是建立一个已回答问题的存储库,以备将来参考。因此,尽管我了解到该特定链接是指向另一个SE网站的,并且应该相当安全,但通常的最佳做法是不要指望从现在起仍可以使用几年的链接。在给出的答案,这些“两个简单的方法的概要将确保信息被保留,即使有事链接的问题,正如我虽然说,这是更多的关于答案的链接的最佳做法的一般性意见。
Sam Maloney
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.