为什么MinMaxScaler会为图像添加线条?

时间:2016-06-10 15:15:06

标签: numpy image-processing machine-learning scikit-learn

我想将图像的像素值标准化为每个通道(R,G,B)的范围[0,1]。

最小示例

import Ember from 'ember';
import ToriiFirebaseAdapter from 'emberfire/torii-adapters/firebase';

export default ToriiFirebaseAdapter.extend({
  firebase: Ember.inject.service()
});

会发生什么

考虑https://commons.wikimedia.org/wiki/File:Crocodylus-johnsoni-3.jpg, 我得到以下"标准化"结果:

enter image description here

正如您所看到的,右侧有从上到下的线条。那里发生了什么?在我看来,规范化出错了。如果是这样:我该如何解决?

1 个答案:

答案 0 :(得分:4)

在scikit-learn中,形状为(m,n)的二维数组通常被解释为 m 样本的集合,每个样本都有 n 功能。

MinMaxScaler.fit_transform()会转换每个功能,因此您的数组的每一列都会独立于其他列进行转换。这导致图像中出现垂直“条纹”。

您似乎打算独立缩放每个颜色通道。要使用MinMaxScaler执行此操作,请重新整形输入,以便每个通道都成为一列。也就是说,如果原始图像具有形状(m,n,3),则在将其传递给fit_transform()方法之前将其重新整形为(m * n,3),然后恢复结果的形状以创建转换阵列。

例如,

ascolumns = original.reshape(-1, 3)
t = scaler.fit_transform(ascolumns)
transformed = t.reshape(original.shape)

有了这个,transformed看起来像这样:

image

图像看起来与原始图像完全一样,因为事实证明在数组original中,每个通道中的最小值和最大值分别为0和255:

In [41]: original.min(axis=(0, 1))
Out[41]: array([0, 0, 0], dtype=uint8)

In [42]: original.max(axis=(0, 1))
Out[42]: array([255, 255, 255], dtype=uint8)

因此,在这种情况下,所有fit_transform都会将所有输入值均匀地转换为浮点范围[0.0,1.0]。如果其中一个通道的最小值或最大值不同,则转换后的图像看起来会有所不同。

顺便说一句,使用纯粹的numpy进行转换并不困难。 (我使用的是Python 3,所以在下面,除法会自动将结果转换为浮点数。如果你使用的是Python 2,你需要将其中一个参数转换为浮点数,或者使用{{1} }。)

from __future__ import division

(该方法的一个潜在问题是,如果其中一个通道是常量,它将产生错误,因为In [58]: omin = original.min(axis=(0, 1), keepdims=True) In [59]: omax = original.max(axis=(0, 1), keepdims=True) In [60]: xformed = (original - omin)/(omax - omin) In [61]: np.allclose(xformed, transformed) Out[61]: True 中的一个值将为0。)