Python 当使用各种不同的方法缩小尺寸时,图像梯度会变得不准确

Python 当使用各种不同的方法缩小尺寸时,图像梯度会变得不准确,python,numpy,image-processing,python-imaging-library,Python,Numpy,Image Processing,Python Imaging Library,我们有一个用Python编写的相当复杂的图像处理脚本,它使用PIL和numpy。对于其中一个步骤,我们有一个非常敏感的多通道渐变,这是一个查找表。创建后,它将保存为多个不同的较小分辨率。然而,当这种情况发生时,具有从左到右渐变的绿色通道突然看起来失去了知觉。每50像素左右,它应该会丢失255个值中的1个。相反,它开始以每100像素2的值下降。这导致了巨大的问题,我不明白PIL为什么要这么做。然而,我确实在地图的其他部分看到了1的跳跃,所以我认为这不是一个简单的问题,因为它缺少一点精度。我还注意到

我们有一个用Python编写的相当复杂的图像处理脚本,它使用PIL和numpy。对于其中一个步骤,我们有一个非常敏感的多通道渐变,这是一个查找表。创建后,它将保存为多个不同的较小分辨率。然而,当这种情况发生时,具有从左到右渐变的绿色通道突然看起来失去了知觉。每50像素左右,它应该会丢失255个值中的1个。相反,它开始以每100像素2的值下降。这导致了巨大的问题,我不明白PIL为什么要这么做。然而,我确实在地图的其他部分看到了1的跳跃,所以我认为这不是一个简单的问题,因为它缺少一点精度。我还注意到在另一个频道上,整个地图似乎移动了1个值。即使使用“最近的”过滤器,一旦缩放,整个东西似乎都不准确

对于全尺寸图像,我们使用以下方法从numpy阵列创建它:

image = Image.fromarray(imageIn.astype(np.uint8))
然后我们将其缩小:

new_image = image.resize(new_size, scaleFilter)
比例总是最大的一半,我已经尝试了所有可用的比例选项

然后,我们将其保存为PNG,如下所示:

new_image.save(file_name, 'PNG')
我们使用相同的save命令在步骤1之后直接保存这两个较大的文件,这样就可以了。在规模之后,我们有绿色通道的问题。任何帮助都会很好

编辑:

现在看来,这似乎是SciPy中的一个问题。以下仍然是问题的原因:

    new_array = misc.imresize(imageIn, (x_size, y_size, 4), interp='nearest')
    misc.imsave(file_name,new_array)
我不明白我是如何得到最近的扭曲。我将此数组分配为float64,但它必须涉及代码中的舍入问题

编辑#2:

我更进一步,尝试OSX内置程序sips下载它,得到了同样的失真!然后我用Adobe After Effects试用了一下,效果很好。然后我安装了imagemagick,现在可以正常工作了。我仍然会将奖金奖励给任何能够解释为什么在所有这些方法中都会发生这种情况的人

编辑#3

根据请求,这里是缩放和未缩放的精灵贴图的一部分。在创建这些文件的过程中,我发现OSX内置的“预览”应用程序在缩小时也会导致缩放问题,所以我实际上不得不使用photoshop来获取原始剪辑

原件:

以扭曲为尺度。尝试沿水平轴查看绿色通道

请注意,这些剪辑不是完全相同的像素,而是从您可以通过形状看到的相同区域剪切而成

编辑#4


我现在已经尝试在应用程序中通过OpenGL进行这种缩放,我发现这种情况也会发生!这与使用固定位数进行双线性插值的一些基本问题有关?

当使用skimage按50%缩放时,以下代码似乎是正确的:

import numpy
import skimage
import skimage.io

img = skimage.io.imread('uY173.png')

import skimage.transform

img50_order0 = skimage.img_as_ubyte( skimage.transform.rescale(img, 0.5, order=0, clip=True) )
img50_order1 = skimage.img_as_ubyte( skimage.transform.rescale(img, 0.5, order=1, clip=True) )

img50_lm = numpy.rint( skimage.transform.downscale_local_mean(img, (2,2,1), clip=True) )

import scipy.ndimage.interpolation

img50_nd = scipy.ndimage.interpolation.zoom(img, (0.5, 0.5, 1))

# plot section of green channel along horizontal axis
plot(img50_order0[50, :, 1])
plot(img50_order1[50, :, 1])
plot(img50_lm[50, :, 1])
plot(img50_nd[50, :, 1])

这并不(据我所知)依赖于引擎盖下的PIL。源图像被读取为uint8,在每个图像中以细微不同的方式进行处理和舍入,从而产生uint8输出。但是,所有这些之间的差异永远不会超过1,而且台阶的大小永远不会超过2。

1/50不是与2/100相同吗?我很困惑。
scaleFilter
是什么?
imresize()
imsave()
都会在内部调用
toimage()
,这似乎会将像素值重新缩放到0-255。SciPy的问题是,它在内部调用PIL来进行大小调整,这就是行为相同的原因。我更喜欢OpenCV,特别是当我使用numpy时,因为没有来回转换(与PIL不同,加载了cv2的图像存储为numpy数组)。PIL()在“预乘alpha”空间中调整大小,这导致一些透明度信息泄漏到颜色通道中。这个想法是不混合透明和不透明像素的颜色,我想这是一个普通图像想要的颜色,但这对查找表没有好处。由于使用
uint8
中介,问题被夸大了(在PIL中)。