Skip to content

Commit

Permalink
BUG: fix pilutil.bytescale scaling behavior. Closes #1748.
Browse files Browse the repository at this point in the history
Thanks to kingson for the patch.
  • Loading branch information
rgommers committed Oct 30, 2012
1 parent 43c7982 commit 1aee114
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 19 deletions.
50 changes: 34 additions & 16 deletions scipy/misc/pilutil.py
Expand Up @@ -30,23 +30,27 @@ def bytescale(data, cmin=None, cmax=None, high=255, low=0):
"""
Byte scales an array (image).
Byte scaling means converting the input image to uint8 dtype and scaling
the range to ``(low, high)`` (default 0-255).
If the input image already has dtype uint8, no scaling is done.
Parameters
----------
data : ndarray
PIL image data array.
cmin : Scalar
Bias scaling of small values, Default is data.min().
cmax : scalar
Bias scaling of large values, Default is data.max().
high : scalar
Scale max value to `high`.
low : scalar
Scale min value to `low`.
cmin : scalar, optional
Bias scaling of small values. Default is ``data.min()``.
cmax : scalar, optional
Bias scaling of large values. Default is ``data.max()``.
high : scalar, optional
Scale max value to `high`. Default is 255.
low : scalar, optional
Scale min value to `low`. Default is 0.
Returns
-------
img_array : ndarray
Bytescaled array.
img_array : uint8 ndarray
The byte-scaled array.
Examples
--------
Expand All @@ -69,12 +73,26 @@ def bytescale(data, cmin=None, cmax=None, high=255, low=0):
"""
if data.dtype == uint8:
return data
high = high - low
if cmin is None: cmin = data.min()
if cmax is None: cmax = data.max()
scale = high *1.0 / (cmax-cmin or 1)
bytedata = ((data*1.0-cmin)*scale + 0.4999).astype(uint8)
return bytedata + cast[uint8](low)

if high < low:
raise ValueError("`high` should be larger than `low`.")

if cmin is None:
cmin = data.min()
if cmax is None:
cmax = data.max()

cscale = cmax - cmin
if cscale < 0:
raise ValueError("`cmax` should be larger than `cmin`.")
elif cscale == 0:
cscale = 1

scale = float(high - low) / cscale
bytedata = (data * 1.0 - cmin) * scale + 0.4999
bytedata[bytedata > high] = high
bytedata[bytedata < 0] = 0
return cast[uint8](bytedata) + cast[uint8](low)

def imread(name,flatten=0):
"""
Expand Down
15 changes: 12 additions & 3 deletions scipy/misc/tests/test_pilutil.py
Expand Up @@ -39,10 +39,19 @@ def test_imresize3(self):
assert_equal(im2.shape, (30,60))

def test_bytescale(self):
x = np.array([0,1,2],np.uint8)
x = np.array([0,1,2], np.uint8)
y = np.array([0,1,2])
assert_equal(misc.bytescale(x),x)
assert_equal(misc.bytescale(y),[0,127,255])
assert_equal(misc.bytescale(x), x)
assert_equal(misc.bytescale(y), [0,127,255])

def test_bytescale_keywords(self):
x = np.array([40, 60, 120, 200, 300, 500])
res_lowhigh = misc.bytescale(x, low=10, high=143)
assert_equal(res_lowhigh, [10, 16, 33, 56, 85, 143])
res_cmincmax = misc.bytescale(x, cmin=60, cmax=300)
assert_equal(res_cmincmax, [0, 0, 64, 149, 255, 255])

assert_equal(misc.bytescale(np.array([3, 3, 3]), low=4), [4, 4, 4])

def tst_fromimage(filename, irange):
fp = open(filename, "rb")
Expand Down

0 comments on commit 1aee114

Please sign in to comment.