获取两幅图像之间的高斯模糊西格玛

Obtain sigma of gaussian blur between two images

假设我有一张图片 A,我用 Sigam=3 在上面应用了高斯模糊,所以我得到了另一张图片 B。如果给出 A,B,有没有办法知道应用的西格玛?

进一步说明:

图片A:

图片 B:

我想写一个接受 A,B 和 return 的函数 Sigma:

double get_sigma(cv::Mat const& A,cv::Mat const& B);

有什么建议吗?

EDIT1: 建议的方法在实践中以其原始形式不起作用(即只使用 9 个方程 3 x 3 kernel),后来我才意识到这一点。请参阅下面的 EDIT1 以了解有效的方法的解释和 EDIT2。

EDIT2: 根据 Humam 的建议,我使用最小二乘估计 (LSE) 来查找系数。

在这种情况下,我认为您可以通过求解线性方程组来估计滤波器内核。线性滤波器通过其系数对 window 中的像素进行加权,然后求和并将该值分配给结果图像中 window 的中心像素。因此,对于像

这样的 3 x 3 过滤器

过滤图像中得到的像素值

result_pix_value = h11 * a(y, x) + h12 * a(y, x+1) + h13 * a(y, x+2) +
                   h21 * a(y+1, x) + h22 * a(y+1, x+1) + h23 * a(y+1, x+2) +
                   h31 * a(y+2, x) + h32 * a(y+2, x+1) + h33 * a(y+2, x+2)

其中 a's 是原始图像中 window 内的像素值。此处,对于 3 x 3 过滤器,您有 9 个未知数,因此您需要 9 个方程。您可以使用结果图像中的 9 个像素获得这 9 个方程。然后你可以组成一个Ax = b系统并求解x以获得滤波器系数。有了可用的系数,我想你可以找到 sigma。

在下面的示例中,我使用如图所示的非重叠 windows 来获得方程。

您不必知道过滤器的大小。如果使用更大的尺寸,则不相关的系数将接近于零。

您的结果图像大小与输入图像不同,因此我没有使用该图像进行后续计算。我使用您的输入图像并应用我自己的滤镜。

我在 Octave 中对此进行了测试。如果你有Octave/Matlab,你可以很快运行它。 Octave需要加载镜像包

我正在使用以下内核来模糊图像:

h =

   0.10963   0.11184   0.10963
   0.11184   0.11410   0.11184
   0.10963   0.11184   0.10963

当我使用 window 尺寸 5 估算它时,我得到以下结果。正如我所说,不相关的系数接近于零。

g =

  9.5787e-015  -3.1508e-014  1.2974e-015  -3.4897e-015  1.2739e-014
  -3.7248e-014  1.0963e-001  1.1184e-001  1.0963e-001  1.8418e-015
  4.1825e-014  1.1184e-001  1.1410e-001  1.1184e-001  -7.3554e-014
  -2.4861e-014  1.0963e-001  1.1184e-001  1.0963e-001  9.7664e-014
  1.3692e-014  4.6182e-016  -2.9215e-014  3.1305e-014  -4.4875e-014

编辑 1: 首先,我很抱歉。

  • 这种方法在实践中并不奏效。我在代码中使用了 filt = conv2(a, h, 'same'); 。在这种情况下生成的图像数据类型是 double,而在实际图像中数据类型通常是 uint8,因此会丢失信息,我们可以将其视为噪声。我用较小的修改 filt = floor(conv2(a, h, 'same')); 模拟了这个,然后我没有得到预期的结果。
  • 采样方法并不理想,因为它可能会导致系统退化。更好的方法是使用随机抽样,避免边界并确保 b 向量中的条目是唯一的。在理想情况下,就像在我的代码中一样,我们确保系统 Ax = b 以这种方式具有唯一的解决方案。
  • 一种方法是将其重新表述为 Mv = 0 系统,并尝试在约束 squared-norm v = 1 下最小化 Mv 的平方范数,我们可以使用 SVD 求解。我在这里可能是错的,我还没有尝试过。
  • 另一种方法是利用高斯核的对称性。然后 3x3 内核将只有 3 个未知数而不是 9 个。我认为,这样我们就对上一段的 v 施加了额外的约束。
  • 我会尝试这些并 post 结果,即使我没有得到预期的结果。

EDIT2:

  • 使用LSE,我们可以找到滤波器系数为pinv(A'A)A'b。为了完成,我添加了一个简单(且缓慢)的 LSE 代码。

初始八度代码:

clear all

im = double(imread('I2vxD.png'));

k = 5;
r = floor(k/2);

a = im(:, :, 1);  % take the red channel
h = fspecial('gaussian', [3 3], 5); % filter with a 3x3 gaussian
filt = conv2(a, h, 'same');

% use non-overlapping windows to for the Ax = b syatem
% NOTE: boundry error checking isn't performed in the code below
s = floor(size(a)/2);
y = s(1);
x = s(2);

w = k*k;
y1 = s(1)-floor(w/2) + r;
y2 = s(1)+floor(w/2);
x1 = s(2)-floor(w/2) + r;
x2 = s(2)+floor(w/2);

b = [];
A = [];
for y = y1:k:y2
  for x = x1:k:x2
    b = [b; filt(y, x)];
    f = a(y-r:y+r, x-r:x+r);
    A = [A; f(:)'];
  end
end

% estimated filter kernel
g = reshape(A\b, k, k)

LSE 方法:

clear all

im = double(imread('I2vxD.png'));

k = 5;
r = floor(k/2);

a = im(:, :, 1);  % take the red channel
h = fspecial('gaussian', [3 3], 5); % filter with a 3x3 gaussian
filt = floor(conv2(a, h, 'same'));

s = size(a);
y1 = r+2; y2 = s(1)-r-2;
x1 = r+2; x2 = s(2)-r-2;

b = [];
A = [];

for y = y1:2:y2
  for x = x1:2:x2
    b = [b; filt(y, x)];
    f = a(y-r:y+r, x-r:x+r);
    f = f(:)';
    A = [A; f];
  end
end

g = reshape(A\b, k, k) % A\b returns the least squares solution
%g = reshape(pinv(A'*A)*A'*b, k, k)