Python 比较抽取然后上采样二维数组的问题

Python issue comparing decimated then upsampled 2D arrays

我正在尝试研究随着我逐渐抽取照片而导致的图像质量下降。

为此,我设计了这个实验: - 获取输入图像并在循环中在每次迭代中抽取 n 倍和 n-2 倍,获得新图像 A 和 B - 使用 sp.ndimage.interpolation.zoom 上采样到原始大小 A 和 B,缩放因子为 n 和 n-2 - 计算每次迭代时上采样 A 和 B 之间元素差异的元素的 mse - 检查 mse 从迭代到迭代的变化。

这是我的代码:

import numpy as np
import scipy as sp
import matplotlib.pyplot as plt
from skimage import io, feature, color, exposure

# import an image
tut=io.imread('http://www.two-views.com/images/Tut%20bone%20frag.jpg') 
tut=color.rgb2gray(io.imread('Tut.jpg'))  

# contrast stretching
p2, p98 = np.percentile(tut, (2, 98))
st_tut = exposure.rescale_intensity(tut, in_range=(p2, p98))

# decimate progressively, upsample, calculate mse
mse_tut = []

for n in range(6,50,2):
        temp1 = st_tut[::n,::n]
        temp2 = st_tut[::n-2,::n-2]
        tempz1 = sp.ndimage.interpolation.zoom(temp1, n, order=2)
        tempz2 = sp.ndimage.interpolation.zoom(temp2, n-2, order=2)
        mse_temp = ((tempz2 - tempz1) ** 2).mean(axis=None)
        mse_tut.append(mse_temp)

问题是我收到此错误消息:

---> 11 mse_temp = ((tempz2 - tempz1) ** 2).mean(axis=None)

ValueError: operands could not be broadcast together with shapes (400,400) (402,402)

我不确定为什么会发生这种情况,因为当我在下面尝试此操作时,一切运行顺利:

temp1 = st_tut[::10,::10]
temp2 = st_tut[::8,::8]

tempz1 = sp.ndimage.interpolation.zoom(temp1, 10, order=2)
tempz2 = sp.ndimage.interpolation.zoom(temp2, 8, order=2)

print temp1.shape, temp2.shape
print tempz1.shape, tempz2.shape

mse_temp = ((tempz2 - tempz1) ** 2).mean(axis=None)
print mse_temp

(40, 40) (50, 50)

(400, 400) (400, 400)

0.00981401032334

这是因为在具有相同数量元素的数组中,切片操作和缩放操作并不总是 return。

切片操作与 step 2(仅作为示例)一起使用时,如果原始数组有 2*n 个元素,则只会 return 一个两倍小的数组。否则,它将 return 元素数量的一半(向下舍入)加 1:

>>> [0,1,2,3][::2]  # 4-element array, will be reduced to 2
[0, 2]  
>>> [0,1,2,3,4][::2] # 5-element array, will be reduced to 3
[0, 2, 4]

"Zooming" 那些乘以 2 的结果数组,只会在第一种情况下得到一个具有相同元素数量的数组,但在第二种情况下不会。

因此,结果完全取决于输入数组的大小:在您的情况下,如果它是 n 和 (n-2) 的倍数,那么您就可以了。否则,你不是。

我可以用另一个例子来总结一下:

>>> import numpy as np
>>> 
>>> D = np.arange(10)
>>> for n in range(3,7,2):
...     print(D[::n].shape[0]*n, D[::n-2].shape[0]*(n-2))
... 
12 10
10 12
>>> 

将其与 D = np.arange(15) 的情况进行比较,例如,它是 3 和 1 以及 5 和 3(本例中使用的 2 个后续迭代)的倍数。

让我们看一下 "smooth" 案例,了解发生了什么。 temp1 是一个 400x400 / 10 = 40x40 数组。 400 正好除以 10。同样 temp2 正好是 50x50。当您上采样时,数组恢复为 400x400,因为它们是维度的精确倍数。

现在让我们看看当您拥有 n = 6 时会发生什么。 temp1400x400 / 6 + 1 = 67x67 数组。整数除法在这里适用,因为您实际上是每六个元素步进一次。 temp2 是一个 400x400 / 8 = 50x50 数组。对于temp2400平均分为n-2。现在当你上采样时,你会得到一个 66x66 * 6 = 402x402 数组和一个 400x400 数组。

您可以通过执行以下操作来对此进行测试:

 >>> import numpy as np
 >>> x = np.ones((400, 400))
 >>> x.shape
 (400, 400)
 >>> x[::6, ::6].shape
 (67, 67)

这个问题有几个显而易见的解决方案:

  1. Select n 的值,其中 nn-2 使得 400 是两者的倍数。这可能会大大限制您的操作范围。虽然这是一个合法的解决方案,但我不推荐它。
  2. scipy.ndimage.interpolation.zoomfloat 作为缩放参数。不要只传入 nn-2,而是分别传入 400 / temp1.shape[0]400 / temp2.shape[0]。例如,如果 temp167x67,这会将其放大 5.97014925373 而不是 6,从而使上采样大小正好 400x400.