demo + utils venv
@@ -0,0 +1,113 @@
|
||||
"""
|
||||
==========================================
|
||||
Miscellaneous routines (:mod:`scipy.misc`)
|
||||
==========================================
|
||||
|
||||
.. currentmodule:: scipy.misc
|
||||
|
||||
Various utilities that don't have another home.
|
||||
|
||||
Note that Pillow (https://python-pillow.org/) is not a dependency
|
||||
of SciPy, but the image manipulation functions indicated in the list
|
||||
below are not available without it.
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated/
|
||||
|
||||
ascent - Get example image for processing
|
||||
central_diff_weights - Weights for an n-point central m-th derivative
|
||||
derivative - Find the n-th derivative of a function at a point
|
||||
face - Get example image for processing
|
||||
electrocardiogram - Load an example of a one-dimensional signal.
|
||||
|
||||
Deprecated functions:
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated/
|
||||
|
||||
bytescale - Byte scales an array (image) [requires Pillow]
|
||||
fromimage - Return a copy of a PIL image as a numpy array [requires Pillow]
|
||||
imfilter - Simple filtering of an image [requires Pillow]
|
||||
imread - Read an image file from a filename [requires Pillow]
|
||||
imresize - Resize an image [requires Pillow]
|
||||
imrotate - Rotate an image counter-clockwise [requires Pillow]
|
||||
imsave - Save an array to an image file [requires Pillow]
|
||||
imshow - Simple showing of an image through an external viewer [requires Pillow]
|
||||
toimage - Takes a numpy array and returns a PIL image [requires Pillow]
|
||||
|
||||
|
||||
Deprecated aliases:
|
||||
|
||||
.. autosummary::
|
||||
:toctree: generated/
|
||||
|
||||
comb - Combinations of N things taken k at a time, "N choose k" (imported from `scipy.special`)
|
||||
factorial - The factorial function, ``n! = special.gamma(n+1)``
|
||||
(imported from `scipy.special`)
|
||||
factorial2 - Double factorial, ``(n!)!`` (imported from `scipy.special`)
|
||||
factorialk - ``(...((n!)!)!...)!`` where there are k '!' (imported from `scipy.special`)
|
||||
logsumexp - Compute the log of the sum of exponentials of input elements
|
||||
(imported from `scipy.special`)
|
||||
pade - Pade approximation to function as the ratio of two polynomials.
|
||||
(imported from `scipy.interpolate`)
|
||||
info - Get help information for a function, class, or module. (imported from `numpy`)
|
||||
source - Print function source code. (imported from `numpy`)
|
||||
who - Print the Numpy arrays in the given dictionary. (imported from `numpy`)
|
||||
|
||||
"""
|
||||
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
__all__ = ['who', 'source', 'info', 'doccer', 'pade',
|
||||
'comb', 'factorial', 'factorial2', 'factorialk', 'logsumexp']
|
||||
|
||||
from . import doccer
|
||||
from .common import *
|
||||
from numpy import who as _who, source as _source, info as _info
|
||||
import numpy as np
|
||||
from scipy.interpolate._pade import pade as _pade
|
||||
from scipy.special import (comb as _comb, logsumexp as _lsm,
|
||||
factorial as _fact, factorial2 as _fact2, factorialk as _factk)
|
||||
|
||||
import sys
|
||||
|
||||
_msg = ("Importing `%(name)s` from scipy.misc is deprecated in scipy 1.0.0. Use "
|
||||
"`scipy.special.%(name)s` instead.")
|
||||
comb = np.deprecate(_comb, message=_msg % {"name": _comb.__name__})
|
||||
logsumexp = np.deprecate(_lsm, message=_msg % {"name": _lsm.__name__})
|
||||
factorial = np.deprecate(_fact, message=_msg % {"name": _fact.__name__})
|
||||
factorial2 = np.deprecate(_fact2, message=_msg % {"name": _fact2.__name__})
|
||||
factorialk = np.deprecate(_factk, message=_msg % {"name": _factk.__name__})
|
||||
|
||||
_msg = ("Importing `pade` from scipy.misc is deprecated in scipy 1.0.0. Use "
|
||||
"`scipy.interpolate.pade` instead.")
|
||||
pade = np.deprecate(_pade, message=_msg)
|
||||
|
||||
_msg = ("Importing `%(name)s` from scipy.misc is deprecated in scipy 1.0.0. Use "
|
||||
"`numpy.%(name)s` instead.")
|
||||
who = np.deprecate(_who, message=_msg % {"name": "who"})
|
||||
source = np.deprecate(_source, message=_msg % {"name": "source"})
|
||||
|
||||
@np.deprecate(message=_msg % {"name": "info.(..., toplevel='scipy')"})
|
||||
def info(object=None,maxwidth=76,output=sys.stdout,toplevel='scipy'):
|
||||
return _info(object, maxwidth, output, toplevel)
|
||||
|
||||
|
||||
info.__doc__ = _info.__doc__
|
||||
del sys
|
||||
|
||||
try:
|
||||
from .pilutil import *
|
||||
from . import pilutil
|
||||
__all__ += pilutil.__all__
|
||||
del pilutil
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
from . import common
|
||||
__all__ += common.__all__
|
||||
del common
|
||||
|
||||
from scipy._lib._testutils import PytestTester
|
||||
test = PytestTester(__name__)
|
||||
del PytestTester
|
||||
@@ -0,0 +1,303 @@
|
||||
"""
|
||||
Functions which are common and require SciPy Base and Level 1 SciPy
|
||||
(special, linalg)
|
||||
"""
|
||||
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
from numpy import arange, newaxis, hstack, product, array, frombuffer, load
|
||||
|
||||
__all__ = ['central_diff_weights', 'derivative', 'ascent', 'face',
|
||||
'electrocardiogram']
|
||||
|
||||
|
||||
def central_diff_weights(Np, ndiv=1):
|
||||
"""
|
||||
Return weights for an Np-point central derivative.
|
||||
|
||||
Assumes equally-spaced function points.
|
||||
|
||||
If weights are in the vector w, then
|
||||
derivative is w[0] * f(x-ho*dx) + ... + w[-1] * f(x+h0*dx)
|
||||
|
||||
Parameters
|
||||
----------
|
||||
Np : int
|
||||
Number of points for the central derivative.
|
||||
ndiv : int, optional
|
||||
Number of divisions. Default is 1.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Can be inaccurate for large number of points.
|
||||
|
||||
"""
|
||||
if Np < ndiv + 1:
|
||||
raise ValueError("Number of points must be at least the derivative order + 1.")
|
||||
if Np % 2 == 0:
|
||||
raise ValueError("The number of points must be odd.")
|
||||
from scipy import linalg
|
||||
ho = Np >> 1
|
||||
x = arange(-ho,ho+1.0)
|
||||
x = x[:,newaxis]
|
||||
X = x**0.0
|
||||
for k in range(1,Np):
|
||||
X = hstack([X,x**k])
|
||||
w = product(arange(1,ndiv+1),axis=0)*linalg.inv(X)[ndiv]
|
||||
return w
|
||||
|
||||
|
||||
def derivative(func, x0, dx=1.0, n=1, args=(), order=3):
|
||||
"""
|
||||
Find the n-th derivative of a function at a point.
|
||||
|
||||
Given a function, use a central difference formula with spacing `dx` to
|
||||
compute the `n`-th derivative at `x0`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
func : function
|
||||
Input function.
|
||||
x0 : float
|
||||
The point at which `n`-th derivative is found.
|
||||
dx : float, optional
|
||||
Spacing.
|
||||
n : int, optional
|
||||
Order of the derivative. Default is 1.
|
||||
args : tuple, optional
|
||||
Arguments
|
||||
order : int, optional
|
||||
Number of points to use, must be odd.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Decreasing the step size too small can result in round-off error.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.misc import derivative
|
||||
>>> def f(x):
|
||||
... return x**3 + x**2
|
||||
>>> derivative(f, 1.0, dx=1e-6)
|
||||
4.9999999999217337
|
||||
|
||||
"""
|
||||
if order < n + 1:
|
||||
raise ValueError("'order' (the number of points used to compute the derivative), "
|
||||
"must be at least the derivative order 'n' + 1.")
|
||||
if order % 2 == 0:
|
||||
raise ValueError("'order' (the number of points used to compute the derivative) "
|
||||
"must be odd.")
|
||||
# pre-computed for n=1 and 2 and low-order for speed.
|
||||
if n == 1:
|
||||
if order == 3:
|
||||
weights = array([-1,0,1])/2.0
|
||||
elif order == 5:
|
||||
weights = array([1,-8,0,8,-1])/12.0
|
||||
elif order == 7:
|
||||
weights = array([-1,9,-45,0,45,-9,1])/60.0
|
||||
elif order == 9:
|
||||
weights = array([3,-32,168,-672,0,672,-168,32,-3])/840.0
|
||||
else:
|
||||
weights = central_diff_weights(order,1)
|
||||
elif n == 2:
|
||||
if order == 3:
|
||||
weights = array([1,-2.0,1])
|
||||
elif order == 5:
|
||||
weights = array([-1,16,-30,16,-1])/12.0
|
||||
elif order == 7:
|
||||
weights = array([2,-27,270,-490,270,-27,2])/180.0
|
||||
elif order == 9:
|
||||
weights = array([-9,128,-1008,8064,-14350,8064,-1008,128,-9])/5040.0
|
||||
else:
|
||||
weights = central_diff_weights(order,2)
|
||||
else:
|
||||
weights = central_diff_weights(order, n)
|
||||
val = 0.0
|
||||
ho = order >> 1
|
||||
for k in range(order):
|
||||
val += weights[k]*func(x0+(k-ho)*dx,*args)
|
||||
return val / product((dx,)*n,axis=0)
|
||||
|
||||
|
||||
def ascent():
|
||||
"""
|
||||
Get an 8-bit grayscale bit-depth, 512 x 512 derived image for easy use in demos
|
||||
|
||||
The image is derived from accent-to-the-top.jpg at
|
||||
http://www.public-domain-image.com/people-public-domain-images-pictures/
|
||||
|
||||
Parameters
|
||||
----------
|
||||
None
|
||||
|
||||
Returns
|
||||
-------
|
||||
ascent : ndarray
|
||||
convenient image to use for testing and demonstration
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import scipy.misc
|
||||
>>> ascent = scipy.misc.ascent()
|
||||
>>> ascent.shape
|
||||
(512, 512)
|
||||
>>> ascent.max()
|
||||
255
|
||||
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> plt.gray()
|
||||
>>> plt.imshow(ascent)
|
||||
>>> plt.show()
|
||||
|
||||
"""
|
||||
import pickle
|
||||
import os
|
||||
fname = os.path.join(os.path.dirname(__file__),'ascent.dat')
|
||||
with open(fname, 'rb') as f:
|
||||
ascent = array(pickle.load(f))
|
||||
return ascent
|
||||
|
||||
|
||||
def face(gray=False):
|
||||
"""
|
||||
Get a 1024 x 768, color image of a raccoon face.
|
||||
|
||||
raccoon-procyon-lotor.jpg at http://www.public-domain-image.com
|
||||
|
||||
Parameters
|
||||
----------
|
||||
gray : bool, optional
|
||||
If True return 8-bit grey-scale image, otherwise return a color image
|
||||
|
||||
Returns
|
||||
-------
|
||||
face : ndarray
|
||||
image of a racoon face
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import scipy.misc
|
||||
>>> face = scipy.misc.face()
|
||||
>>> face.shape
|
||||
(768, 1024, 3)
|
||||
>>> face.max()
|
||||
255
|
||||
>>> face.dtype
|
||||
dtype('uint8')
|
||||
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> plt.gray()
|
||||
>>> plt.imshow(face)
|
||||
>>> plt.show()
|
||||
|
||||
"""
|
||||
import bz2
|
||||
import os
|
||||
with open(os.path.join(os.path.dirname(__file__), 'face.dat'), 'rb') as f:
|
||||
rawdata = f.read()
|
||||
data = bz2.decompress(rawdata)
|
||||
face = frombuffer(data, dtype='uint8')
|
||||
face.shape = (768, 1024, 3)
|
||||
if gray is True:
|
||||
face = (0.21 * face[:,:,0] + 0.71 * face[:,:,1] + 0.07 * face[:,:,2]).astype('uint8')
|
||||
return face
|
||||
|
||||
|
||||
def electrocardiogram():
|
||||
"""
|
||||
Load an electrocardiogram as an example for a one-dimensional signal.
|
||||
|
||||
The returned signal is a 5 minute long electrocardiogram (ECG), a medical
|
||||
recording of the heart's electrical activity, sampled at 360 Hz.
|
||||
|
||||
Returns
|
||||
-------
|
||||
ecg : ndarray
|
||||
The electrocardiogram in millivolt (mV) sampled at 360 Hz.
|
||||
|
||||
Notes
|
||||
-----
|
||||
The provided signal is an excerpt (19:35 to 24:35) from the `record 208`_
|
||||
(lead MLII) provided by the MIT-BIH Arrhythmia Database [1]_ on
|
||||
PhysioNet [2]_. The excerpt includes noise induced artifacts, typical
|
||||
heartbeats as well as pathological changes.
|
||||
|
||||
.. _record 208: https://physionet.org/physiobank/database/html/mitdbdir/records.htm#208
|
||||
|
||||
.. versionadded:: 1.1.0
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] Moody GB, Mark RG. The impact of the MIT-BIH Arrhythmia Database.
|
||||
IEEE Eng in Med and Biol 20(3):45-50 (May-June 2001).
|
||||
(PMID: 11446209); :doi:`10.13026/C2F305`
|
||||
.. [2] Goldberger AL, Amaral LAN, Glass L, Hausdorff JM, Ivanov PCh,
|
||||
Mark RG, Mietus JE, Moody GB, Peng C-K, Stanley HE. PhysioBank,
|
||||
PhysioToolkit, and PhysioNet: Components of a New Research Resource
|
||||
for Complex Physiologic Signals. Circulation 101(23):e215-e220;
|
||||
:doi:`10.1161/01.CIR.101.23.e215`
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.misc import electrocardiogram
|
||||
>>> ecg = electrocardiogram()
|
||||
>>> ecg
|
||||
array([-0.245, -0.215, -0.185, ..., -0.405, -0.395, -0.385])
|
||||
>>> ecg.shape, ecg.mean(), ecg.std()
|
||||
((108000,), -0.16510875, 0.5992473991177294)
|
||||
|
||||
As stated the signal features several areas with a different morphology.
|
||||
E.g. the first few seconds show the electrical activity of a heart in
|
||||
normal sinus rhythm as seen below.
|
||||
|
||||
>>> import matplotlib.pyplot as plt
|
||||
>>> fs = 360
|
||||
>>> time = np.arange(ecg.size) / fs
|
||||
>>> plt.plot(time, ecg)
|
||||
>>> plt.xlabel("time in s")
|
||||
>>> plt.ylabel("ECG in mV")
|
||||
>>> plt.xlim(9, 10.2)
|
||||
>>> plt.ylim(-1, 1.5)
|
||||
>>> plt.show()
|
||||
|
||||
After second 16 however, the first premature ventricular contractions, also
|
||||
called extrasystoles, appear. These have a different morphology compared to
|
||||
typical heartbeats. The difference can easily be observed in the following
|
||||
plot.
|
||||
|
||||
>>> plt.plot(time, ecg)
|
||||
>>> plt.xlabel("time in s")
|
||||
>>> plt.ylabel("ECG in mV")
|
||||
>>> plt.xlim(46.5, 50)
|
||||
>>> plt.ylim(-2, 1.5)
|
||||
>>> plt.show()
|
||||
|
||||
At several points large artifacts disturb the recording, e.g.:
|
||||
|
||||
>>> plt.plot(time, ecg)
|
||||
>>> plt.xlabel("time in s")
|
||||
>>> plt.ylabel("ECG in mV")
|
||||
>>> plt.xlim(207, 215)
|
||||
>>> plt.ylim(-2, 3.5)
|
||||
>>> plt.show()
|
||||
|
||||
Finally, examining the power spectrum reveals that most of the biosignal is
|
||||
made up of lower frequencies. At 60 Hz the noise induced by the mains
|
||||
electricity can be clearly observed.
|
||||
|
||||
>>> from scipy.signal import welch
|
||||
>>> f, Pxx = welch(ecg, fs=fs, nperseg=2048, scaling="spectrum")
|
||||
>>> plt.semilogy(f, Pxx)
|
||||
>>> plt.xlabel("Frequency in Hz")
|
||||
>>> plt.ylabel("Power spectrum of the ECG in mV**2")
|
||||
>>> plt.xlim(f[[0, -1]])
|
||||
>>> plt.show()
|
||||
"""
|
||||
import os
|
||||
file_path = os.path.join(os.path.dirname(__file__), "ecg.dat")
|
||||
with load(file_path) as file:
|
||||
ecg = file["ecg"].astype(int) # np.uint16 -> int
|
||||
# Convert raw output of ADC to mV: (ecg - adc_zero) / adc_gain
|
||||
ecg = (ecg - 1024) / 200.0
|
||||
return ecg
|
||||
@@ -0,0 +1,250 @@
|
||||
''' Utilities to allow inserting docstring fragments for common
|
||||
parameters into function and method docstrings'''
|
||||
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import sys
|
||||
|
||||
__all__ = ['docformat', 'inherit_docstring_from', 'indentcount_lines',
|
||||
'filldoc', 'unindent_dict', 'unindent_string']
|
||||
|
||||
|
||||
def docformat(docstring, docdict=None):
|
||||
''' Fill a function docstring from variables in dictionary
|
||||
|
||||
Adapt the indent of the inserted docs
|
||||
|
||||
Parameters
|
||||
----------
|
||||
docstring : string
|
||||
docstring from function, possibly with dict formatting strings
|
||||
docdict : dict, optional
|
||||
dictionary with keys that match the dict formatting strings
|
||||
and values that are docstring fragments to be inserted. The
|
||||
indentation of the inserted docstrings is set to match the
|
||||
minimum indentation of the ``docstring`` by adding this
|
||||
indentation to all lines of the inserted string, except the
|
||||
first
|
||||
|
||||
Returns
|
||||
-------
|
||||
outstring : string
|
||||
string with requested ``docdict`` strings inserted
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> docformat(' Test string with %(value)s', {'value':'inserted value'})
|
||||
' Test string with inserted value'
|
||||
>>> docstring = 'First line\\n Second line\\n %(value)s'
|
||||
>>> inserted_string = "indented\\nstring"
|
||||
>>> docdict = {'value': inserted_string}
|
||||
>>> docformat(docstring, docdict)
|
||||
'First line\\n Second line\\n indented\\n string'
|
||||
'''
|
||||
if not docstring:
|
||||
return docstring
|
||||
if docdict is None:
|
||||
docdict = {}
|
||||
if not docdict:
|
||||
return docstring
|
||||
lines = docstring.expandtabs().splitlines()
|
||||
# Find the minimum indent of the main docstring, after first line
|
||||
if len(lines) < 2:
|
||||
icount = 0
|
||||
else:
|
||||
icount = indentcount_lines(lines[1:])
|
||||
indent = ' ' * icount
|
||||
# Insert this indent to dictionary docstrings
|
||||
indented = {}
|
||||
for name, dstr in docdict.items():
|
||||
lines = dstr.expandtabs().splitlines()
|
||||
try:
|
||||
newlines = [lines[0]]
|
||||
for line in lines[1:]:
|
||||
newlines.append(indent+line)
|
||||
indented[name] = '\n'.join(newlines)
|
||||
except IndexError:
|
||||
indented[name] = dstr
|
||||
return docstring % indented
|
||||
|
||||
|
||||
def inherit_docstring_from(cls):
|
||||
"""
|
||||
This decorator modifies the decorated function's docstring by
|
||||
replacing occurrences of '%(super)s' with the docstring of the
|
||||
method of the same name from the class `cls`.
|
||||
|
||||
If the decorated method has no docstring, it is simply given the
|
||||
docstring of `cls`s method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
cls : Python class or instance
|
||||
A class with a method with the same name as the decorated method.
|
||||
The docstring of the method in this class replaces '%(super)s' in the
|
||||
docstring of the decorated method.
|
||||
|
||||
Returns
|
||||
-------
|
||||
f : function
|
||||
The decorator function that modifies the __doc__ attribute
|
||||
of its argument.
|
||||
|
||||
Examples
|
||||
--------
|
||||
In the following, the docstring for Bar.func created using the
|
||||
docstring of `Foo.func`.
|
||||
|
||||
>>> class Foo(object):
|
||||
... def func(self):
|
||||
... '''Do something useful.'''
|
||||
... return
|
||||
...
|
||||
>>> class Bar(Foo):
|
||||
... @inherit_docstring_from(Foo)
|
||||
... def func(self):
|
||||
... '''%(super)s
|
||||
... Do it fast.
|
||||
... '''
|
||||
... return
|
||||
...
|
||||
>>> b = Bar()
|
||||
>>> b.func.__doc__
|
||||
'Do something useful.\n Do it fast.\n '
|
||||
|
||||
"""
|
||||
def _doc(func):
|
||||
cls_docstring = getattr(cls, func.__name__).__doc__
|
||||
func_docstring = func.__doc__
|
||||
if func_docstring is None:
|
||||
func.__doc__ = cls_docstring
|
||||
else:
|
||||
new_docstring = func_docstring % dict(super=cls_docstring)
|
||||
func.__doc__ = new_docstring
|
||||
return func
|
||||
return _doc
|
||||
|
||||
|
||||
def extend_notes_in_docstring(cls, notes):
|
||||
"""
|
||||
This decorator replaces the decorated function's docstring
|
||||
with the docstring from corresponding method in `cls`.
|
||||
It extends the 'Notes' section of that docstring to include
|
||||
the given `notes`.
|
||||
"""
|
||||
def _doc(func):
|
||||
cls_docstring = getattr(cls, func.__name__).__doc__
|
||||
# If python is called with -OO option,
|
||||
# there is no docstring
|
||||
if cls_docstring is None:
|
||||
return func
|
||||
end_of_notes = cls_docstring.find(' References\n')
|
||||
if end_of_notes == -1:
|
||||
end_of_notes = cls_docstring.find(' Examples\n')
|
||||
if end_of_notes == -1:
|
||||
end_of_notes = len(cls_docstring)
|
||||
func.__doc__ = (cls_docstring[:end_of_notes] + notes +
|
||||
cls_docstring[end_of_notes:])
|
||||
return func
|
||||
return _doc
|
||||
|
||||
|
||||
def replace_notes_in_docstring(cls, notes):
|
||||
"""
|
||||
This decorator replaces the decorated function's docstring
|
||||
with the docstring from corresponding method in `cls`.
|
||||
It replaces the 'Notes' section of that docstring with
|
||||
the given `notes`.
|
||||
"""
|
||||
def _doc(func):
|
||||
cls_docstring = getattr(cls, func.__name__).__doc__
|
||||
notes_header = ' Notes\n -----\n'
|
||||
# If python is called with -OO option,
|
||||
# there is no docstring
|
||||
if cls_docstring is None:
|
||||
return func
|
||||
start_of_notes = cls_docstring.find(notes_header)
|
||||
end_of_notes = cls_docstring.find(' References\n')
|
||||
if end_of_notes == -1:
|
||||
end_of_notes = cls_docstring.find(' Examples\n')
|
||||
if end_of_notes == -1:
|
||||
end_of_notes = len(cls_docstring)
|
||||
func.__doc__ = (cls_docstring[:start_of_notes + len(notes_header)] +
|
||||
notes +
|
||||
cls_docstring[end_of_notes:])
|
||||
return func
|
||||
return _doc
|
||||
|
||||
|
||||
def indentcount_lines(lines):
|
||||
''' Minimum indent for all lines in line list
|
||||
|
||||
>>> lines = [' one', ' two', ' three']
|
||||
>>> indentcount_lines(lines)
|
||||
1
|
||||
>>> lines = []
|
||||
>>> indentcount_lines(lines)
|
||||
0
|
||||
>>> lines = [' one']
|
||||
>>> indentcount_lines(lines)
|
||||
1
|
||||
>>> indentcount_lines([' '])
|
||||
0
|
||||
'''
|
||||
indentno = sys.maxsize
|
||||
for line in lines:
|
||||
stripped = line.lstrip()
|
||||
if stripped:
|
||||
indentno = min(indentno, len(line) - len(stripped))
|
||||
if indentno == sys.maxsize:
|
||||
return 0
|
||||
return indentno
|
||||
|
||||
|
||||
def filldoc(docdict, unindent_params=True):
|
||||
''' Return docstring decorator using docdict variable dictionary
|
||||
|
||||
Parameters
|
||||
----------
|
||||
docdict : dictionary
|
||||
dictionary containing name, docstring fragment pairs
|
||||
unindent_params : {False, True}, boolean, optional
|
||||
If True, strip common indentation from all parameters in
|
||||
docdict
|
||||
|
||||
Returns
|
||||
-------
|
||||
decfunc : function
|
||||
decorator that applies dictionary to input function docstring
|
||||
|
||||
'''
|
||||
if unindent_params:
|
||||
docdict = unindent_dict(docdict)
|
||||
|
||||
def decorate(f):
|
||||
f.__doc__ = docformat(f.__doc__, docdict)
|
||||
return f
|
||||
return decorate
|
||||
|
||||
|
||||
def unindent_dict(docdict):
|
||||
''' Unindent all strings in a docdict '''
|
||||
can_dict = {}
|
||||
for name, dstr in docdict.items():
|
||||
can_dict[name] = unindent_string(dstr)
|
||||
return can_dict
|
||||
|
||||
|
||||
def unindent_string(docstring):
|
||||
''' Set docstring to minimum indent for all lines, including first
|
||||
|
||||
>>> unindent_string(' two')
|
||||
'two'
|
||||
>>> unindent_string(' two\\n three')
|
||||
'two\\n three'
|
||||
'''
|
||||
lines = docstring.expandtabs().splitlines()
|
||||
icount = indentcount_lines(lines)
|
||||
if icount == 0:
|
||||
return docstring
|
||||
return '\n'.join([line[icount:] for line in lines])
|
||||
@@ -0,0 +1,621 @@
|
||||
"""
|
||||
A collection of image utilities using the Python Imaging Library (PIL).
|
||||
|
||||
Note that PIL is not a dependency of SciPy and this module is not
|
||||
available on systems that don't have PIL installed.
|
||||
|
||||
"""
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
# Functions which need the PIL
|
||||
|
||||
import numpy
|
||||
import tempfile
|
||||
|
||||
from numpy import (amin, amax, ravel, asarray, arange, ones, newaxis,
|
||||
transpose, iscomplexobj, uint8, issubdtype, array)
|
||||
|
||||
try:
|
||||
from PIL import Image, ImageFilter
|
||||
except ImportError:
|
||||
import Image
|
||||
import ImageFilter
|
||||
|
||||
|
||||
if not hasattr(Image, 'frombytes'):
|
||||
Image.frombytes = Image.fromstring
|
||||
|
||||
__all__ = ['fromimage', 'toimage', 'imsave', 'imread', 'bytescale',
|
||||
'imrotate', 'imresize', 'imshow', 'imfilter']
|
||||
|
||||
|
||||
@numpy.deprecate(message="`bytescale` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.")
|
||||
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.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
data : ndarray
|
||||
PIL image data array.
|
||||
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 : uint8 ndarray
|
||||
The byte-scaled array.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from scipy.misc import bytescale
|
||||
>>> img = np.array([[ 91.06794177, 3.39058326, 84.4221549 ],
|
||||
... [ 73.88003259, 80.91433048, 4.88878881],
|
||||
... [ 51.53875334, 34.45808177, 27.5873488 ]])
|
||||
>>> bytescale(img)
|
||||
array([[255, 0, 236],
|
||||
[205, 225, 4],
|
||||
[140, 90, 70]], dtype=uint8)
|
||||
>>> bytescale(img, high=200, low=100)
|
||||
array([[200, 100, 192],
|
||||
[180, 188, 102],
|
||||
[155, 135, 128]], dtype=uint8)
|
||||
>>> bytescale(img, cmin=0, cmax=255)
|
||||
array([[91, 3, 84],
|
||||
[74, 81, 5],
|
||||
[52, 34, 28]], dtype=uint8)
|
||||
|
||||
"""
|
||||
if data.dtype == uint8:
|
||||
return data
|
||||
|
||||
if high > 255:
|
||||
raise ValueError("`high` should be less than or equal to 255.")
|
||||
if low < 0:
|
||||
raise ValueError("`low` should be greater than or equal to 0.")
|
||||
if high < low:
|
||||
raise ValueError("`high` should be greater than or equal to `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 - cmin) * scale + low
|
||||
return (bytedata.clip(low, high) + 0.5).astype(uint8)
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imread` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use ``imageio.imread`` instead.")
|
||||
def imread(name, flatten=False, mode=None):
|
||||
"""
|
||||
Read an image from a file as an array.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str or file object
|
||||
The file name or file object to be read.
|
||||
flatten : bool, optional
|
||||
If True, flattens the color layers into a single gray-scale layer.
|
||||
mode : str, optional
|
||||
Mode to convert image to, e.g. ``'RGB'``. See the Notes for more
|
||||
details.
|
||||
|
||||
Returns
|
||||
-------
|
||||
imread : ndarray
|
||||
The array obtained by reading the image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
`imread` uses the Python Imaging Library (PIL) to read an image.
|
||||
The following notes are from the PIL documentation.
|
||||
|
||||
`mode` can be one of the following strings:
|
||||
|
||||
* 'L' (8-bit pixels, black and white)
|
||||
* 'P' (8-bit pixels, mapped to any other mode using a color palette)
|
||||
* 'RGB' (3x8-bit pixels, true color)
|
||||
* 'RGBA' (4x8-bit pixels, true color with transparency mask)
|
||||
* 'CMYK' (4x8-bit pixels, color separation)
|
||||
* 'YCbCr' (3x8-bit pixels, color video format)
|
||||
* 'I' (32-bit signed integer pixels)
|
||||
* 'F' (32-bit floating point pixels)
|
||||
|
||||
PIL also provides limited support for a few special modes, including
|
||||
'LA' ('L' with alpha), 'RGBX' (true color with padding) and 'RGBa'
|
||||
(true color with premultiplied alpha).
|
||||
|
||||
When translating a color image to black and white (mode 'L', 'I' or
|
||||
'F'), the library uses the ITU-R 601-2 luma transform::
|
||||
|
||||
L = R * 299/1000 + G * 587/1000 + B * 114/1000
|
||||
|
||||
When `flatten` is True, the image is converted using mode 'F'.
|
||||
When `mode` is not None and `flatten` is True, the image is first
|
||||
converted according to `mode`, and the result is then flattened using
|
||||
mode 'F'.
|
||||
|
||||
"""
|
||||
|
||||
im = Image.open(name)
|
||||
return fromimage(im, flatten=flatten, mode=mode)
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imsave` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use ``imageio.imwrite`` instead.")
|
||||
def imsave(name, arr, format=None):
|
||||
"""
|
||||
Save an array as an image.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str or file object
|
||||
Output file name or file object.
|
||||
arr : ndarray, MxN or MxNx3 or MxNx4
|
||||
Array containing image values. If the shape is ``MxN``, the array
|
||||
represents a grey-level image. Shape ``MxNx3`` stores the red, green
|
||||
and blue bands along the last dimension. An alpha layer may be
|
||||
included, specified as the last colour band of an ``MxNx4`` array.
|
||||
format : str
|
||||
Image format. If omitted, the format to use is determined from the
|
||||
file name extension. If a file object was used instead of a file name,
|
||||
this parameter should always be used.
|
||||
|
||||
Examples
|
||||
--------
|
||||
Construct an array of gradient intensity values and save to file:
|
||||
|
||||
>>> from scipy.misc import imsave
|
||||
>>> x = np.zeros((255, 255))
|
||||
>>> x = np.zeros((255, 255), dtype=np.uint8)
|
||||
>>> x[:] = np.arange(255)
|
||||
>>> imsave('gradient.png', x)
|
||||
|
||||
Construct an array with three colour bands (R, G, B) and store to file:
|
||||
|
||||
>>> rgb = np.zeros((255, 255, 3), dtype=np.uint8)
|
||||
>>> rgb[..., 0] = np.arange(255)
|
||||
>>> rgb[..., 1] = 55
|
||||
>>> rgb[..., 2] = 1 - np.arange(255)
|
||||
>>> imsave('rgb_gradient.png', rgb)
|
||||
|
||||
"""
|
||||
im = toimage(arr, channel_axis=2)
|
||||
if format is None:
|
||||
im.save(name)
|
||||
else:
|
||||
im.save(name, format)
|
||||
return
|
||||
|
||||
|
||||
@numpy.deprecate(message="`fromimage` is deprecated in SciPy 1.0.0. "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use ``np.asarray(im)`` instead.")
|
||||
def fromimage(im, flatten=False, mode=None):
|
||||
"""
|
||||
Return a copy of a PIL image as a numpy array.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
im : PIL image
|
||||
Input image.
|
||||
flatten : bool
|
||||
If true, convert the output to grey-scale.
|
||||
mode : str, optional
|
||||
Mode to convert image to, e.g. ``'RGB'``. See the Notes of the
|
||||
`imread` docstring for more details.
|
||||
|
||||
Returns
|
||||
-------
|
||||
fromimage : ndarray
|
||||
The different colour bands/channels are stored in the
|
||||
third dimension, such that a grey-image is MxN, an
|
||||
RGB-image MxNx3 and an RGBA-image MxNx4.
|
||||
|
||||
"""
|
||||
if not Image.isImageType(im):
|
||||
raise TypeError("Input is not a PIL image.")
|
||||
|
||||
if mode is not None:
|
||||
if mode != im.mode:
|
||||
im = im.convert(mode)
|
||||
elif im.mode == 'P':
|
||||
# Mode 'P' means there is an indexed "palette". If we leave the mode
|
||||
# as 'P', then when we do `a = array(im)` below, `a` will be a 2-D
|
||||
# containing the indices into the palette, and not a 3-D array
|
||||
# containing the RGB or RGBA values.
|
||||
if 'transparency' in im.info:
|
||||
im = im.convert('RGBA')
|
||||
else:
|
||||
im = im.convert('RGB')
|
||||
|
||||
if flatten:
|
||||
im = im.convert('F')
|
||||
elif im.mode == '1':
|
||||
# Workaround for crash in PIL. When im is 1-bit, the call array(im)
|
||||
# can cause a seg. fault, or generate garbage. See
|
||||
# https://github.com/scipy/scipy/issues/2138 and
|
||||
# https://github.com/python-pillow/Pillow/issues/350.
|
||||
#
|
||||
# This converts im from a 1-bit image to an 8-bit image.
|
||||
im = im.convert('L')
|
||||
|
||||
a = array(im)
|
||||
return a
|
||||
|
||||
|
||||
_errstr = "Mode is unknown or incompatible with input array shape."
|
||||
|
||||
|
||||
@numpy.deprecate(message="`toimage` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use Pillow's ``Image.fromarray`` directly instead.")
|
||||
def toimage(arr, high=255, low=0, cmin=None, cmax=None, pal=None,
|
||||
mode=None, channel_axis=None):
|
||||
"""Takes a numpy array and returns a PIL image.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
The mode of the PIL image depends on the array shape and the `pal` and
|
||||
`mode` keywords.
|
||||
|
||||
For 2-D arrays, if `pal` is a valid (N,3) byte-array giving the RGB values
|
||||
(from 0 to 255) then ``mode='P'``, otherwise ``mode='L'``, unless mode
|
||||
is given as 'F' or 'I' in which case a float and/or integer array is made.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Notes
|
||||
-----
|
||||
For 3-D arrays, the `channel_axis` argument tells which dimension of the
|
||||
array holds the channel data.
|
||||
|
||||
For 3-D arrays if one of the dimensions is 3, the mode is 'RGB'
|
||||
by default or 'YCbCr' if selected.
|
||||
|
||||
The numpy array must be either 2 dimensional or 3 dimensional.
|
||||
|
||||
"""
|
||||
data = asarray(arr)
|
||||
if iscomplexobj(data):
|
||||
raise ValueError("Cannot convert a complex-valued array.")
|
||||
shape = list(data.shape)
|
||||
valid = len(shape) == 2 or ((len(shape) == 3) and
|
||||
((3 in shape) or (4 in shape)))
|
||||
if not valid:
|
||||
raise ValueError("'arr' does not have a suitable array shape for "
|
||||
"any mode.")
|
||||
if len(shape) == 2:
|
||||
shape = (shape[1], shape[0]) # columns show up first
|
||||
if mode == 'F':
|
||||
data32 = data.astype(numpy.float32)
|
||||
image = Image.frombytes(mode, shape, data32.tostring())
|
||||
return image
|
||||
if mode in [None, 'L', 'P']:
|
||||
bytedata = bytescale(data, high=high, low=low,
|
||||
cmin=cmin, cmax=cmax)
|
||||
image = Image.frombytes('L', shape, bytedata.tostring())
|
||||
if pal is not None:
|
||||
image.putpalette(asarray(pal, dtype=uint8).tostring())
|
||||
# Becomes a mode='P' automagically.
|
||||
elif mode == 'P': # default gray-scale
|
||||
pal = (arange(0, 256, 1, dtype=uint8)[:, newaxis] *
|
||||
ones((3,), dtype=uint8)[newaxis, :])
|
||||
image.putpalette(asarray(pal, dtype=uint8).tostring())
|
||||
return image
|
||||
if mode == '1': # high input gives threshold for 1
|
||||
bytedata = (data > high)
|
||||
image = Image.frombytes('1', shape, bytedata.tostring())
|
||||
return image
|
||||
if cmin is None:
|
||||
cmin = amin(ravel(data))
|
||||
if cmax is None:
|
||||
cmax = amax(ravel(data))
|
||||
data = (data*1.0 - cmin)*(high - low)/(cmax - cmin) + low
|
||||
if mode == 'I':
|
||||
data32 = data.astype(numpy.uint32)
|
||||
image = Image.frombytes(mode, shape, data32.tostring())
|
||||
else:
|
||||
raise ValueError(_errstr)
|
||||
return image
|
||||
|
||||
# if here then 3-d array with a 3 or a 4 in the shape length.
|
||||
# Check for 3 in datacube shape --- 'RGB' or 'YCbCr'
|
||||
if channel_axis is None:
|
||||
if (3 in shape):
|
||||
ca = numpy.flatnonzero(asarray(shape) == 3)[0]
|
||||
else:
|
||||
ca = numpy.flatnonzero(asarray(shape) == 4)
|
||||
if len(ca):
|
||||
ca = ca[0]
|
||||
else:
|
||||
raise ValueError("Could not find channel dimension.")
|
||||
else:
|
||||
ca = channel_axis
|
||||
|
||||
numch = shape[ca]
|
||||
if numch not in [3, 4]:
|
||||
raise ValueError("Channel axis dimension is not valid.")
|
||||
|
||||
bytedata = bytescale(data, high=high, low=low, cmin=cmin, cmax=cmax)
|
||||
if ca == 2:
|
||||
strdata = bytedata.tostring()
|
||||
shape = (shape[1], shape[0])
|
||||
elif ca == 1:
|
||||
strdata = transpose(bytedata, (0, 2, 1)).tostring()
|
||||
shape = (shape[2], shape[0])
|
||||
elif ca == 0:
|
||||
strdata = transpose(bytedata, (1, 2, 0)).tostring()
|
||||
shape = (shape[2], shape[1])
|
||||
if mode is None:
|
||||
if numch == 3:
|
||||
mode = 'RGB'
|
||||
else:
|
||||
mode = 'RGBA'
|
||||
|
||||
if mode not in ['RGB', 'RGBA', 'YCbCr', 'CMYK']:
|
||||
raise ValueError(_errstr)
|
||||
|
||||
if mode in ['RGB', 'YCbCr']:
|
||||
if numch != 3:
|
||||
raise ValueError("Invalid array shape for mode.")
|
||||
if mode in ['RGBA', 'CMYK']:
|
||||
if numch != 4:
|
||||
raise ValueError("Invalid array shape for mode.")
|
||||
|
||||
# Here we know data and mode is correct
|
||||
image = Image.frombytes(mode, shape, strdata)
|
||||
return image
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imrotate` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use ``skimage.transform.rotate`` instead.")
|
||||
def imrotate(arr, angle, interp='bilinear'):
|
||||
"""
|
||||
Rotate an image counter-clockwise by angle degrees.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
Input array of image to be rotated.
|
||||
angle : float
|
||||
The angle of rotation.
|
||||
interp : str, optional
|
||||
Interpolation
|
||||
|
||||
- 'nearest' : for nearest neighbor
|
||||
- 'bilinear' : for bilinear
|
||||
- 'lanczos' : for lanczos
|
||||
- 'cubic' : for bicubic
|
||||
- 'bicubic' : for bicubic
|
||||
|
||||
Returns
|
||||
-------
|
||||
imrotate : ndarray
|
||||
The rotated array of image.
|
||||
|
||||
"""
|
||||
arr = asarray(arr)
|
||||
func = {'nearest': 0, 'lanczos': 1, 'bilinear': 2, 'bicubic': 3, 'cubic': 3}
|
||||
im = toimage(arr)
|
||||
im = im.rotate(angle, resample=func[interp])
|
||||
return fromimage(im)
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imshow` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use ``matplotlib.pyplot.imshow`` instead.")
|
||||
def imshow(arr):
|
||||
"""
|
||||
Simple showing of an image through an external viewer.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
Uses the image viewer specified by the environment variable
|
||||
SCIPY_PIL_IMAGE_VIEWER, or if that is not defined then `see`,
|
||||
to view a temporary file generated from array data.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
Array of image data to show.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> a = np.tile(np.arange(255), (255,1))
|
||||
>>> from scipy import misc
|
||||
>>> misc.imshow(a)
|
||||
|
||||
"""
|
||||
im = toimage(arr)
|
||||
fnum, fname = tempfile.mkstemp('.png')
|
||||
try:
|
||||
im.save(fname)
|
||||
except Exception:
|
||||
raise RuntimeError("Error saving temporary image data.")
|
||||
|
||||
import os
|
||||
os.close(fnum)
|
||||
|
||||
cmd = os.environ.get('SCIPY_PIL_IMAGE_VIEWER', 'see')
|
||||
status = os.system("%s %s" % (cmd, fname))
|
||||
|
||||
os.unlink(fname)
|
||||
if status != 0:
|
||||
raise RuntimeError('Could not execute image viewer.')
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imresize` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.3.0.\n"
|
||||
"Use Pillow instead: ``numpy.array(Image.fromarray(arr).resize())``.")
|
||||
def imresize(arr, size, interp='bilinear', mode=None):
|
||||
"""
|
||||
Resize an image.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
The array of image to be resized.
|
||||
size : int, float or tuple
|
||||
* int - Percentage of current size.
|
||||
* float - Fraction of current size.
|
||||
* tuple - Size of the output image (height, width).
|
||||
|
||||
interp : str, optional
|
||||
Interpolation to use for re-sizing ('nearest', 'lanczos', 'bilinear',
|
||||
'bicubic' or 'cubic').
|
||||
mode : str, optional
|
||||
The PIL image mode ('P', 'L', etc.) to convert `arr` before resizing.
|
||||
If ``mode=None`` (the default), 2-D images will be treated like
|
||||
``mode='L'``, i.e. casting to long integer. For 3-D and 4-D arrays,
|
||||
`mode` will be set to ``'RGB'`` and ``'RGBA'`` respectively.
|
||||
|
||||
Returns
|
||||
-------
|
||||
imresize : ndarray
|
||||
The resized array of image.
|
||||
|
||||
See Also
|
||||
--------
|
||||
toimage : Implicitly used to convert `arr` according to `mode`.
|
||||
scipy.ndimage.zoom : More generic implementation that does not use PIL.
|
||||
|
||||
"""
|
||||
im = toimage(arr, mode=mode)
|
||||
ts = type(size)
|
||||
if issubdtype(ts, numpy.signedinteger):
|
||||
percent = size / 100.0
|
||||
size = tuple((array(im.size)*percent).astype(int))
|
||||
elif issubdtype(type(size), numpy.floating):
|
||||
size = tuple((array(im.size)*size).astype(int))
|
||||
else:
|
||||
size = (size[1], size[0])
|
||||
func = {'nearest': 0, 'lanczos': 1, 'bilinear': 2, 'bicubic': 3, 'cubic': 3}
|
||||
imnew = im.resize(size, resample=func[interp])
|
||||
return fromimage(imnew)
|
||||
|
||||
|
||||
@numpy.deprecate(message="`imfilter` is deprecated in SciPy 1.0.0, "
|
||||
"and will be removed in 1.2.0.\n"
|
||||
"Use Pillow filtering functionality directly.")
|
||||
def imfilter(arr, ftype):
|
||||
"""
|
||||
Simple filtering of an image.
|
||||
|
||||
This function is only available if Python Imaging Library (PIL) is installed.
|
||||
|
||||
.. warning::
|
||||
|
||||
This function uses `bytescale` under the hood to rescale images to use
|
||||
the full (0, 255) range if ``mode`` is one of ``None, 'L', 'P', 'l'``.
|
||||
It will also cast data for 2-D images to ``uint32`` for ``mode=None``
|
||||
(which is the default).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arr : ndarray
|
||||
The array of Image in which the filter is to be applied.
|
||||
ftype : str
|
||||
The filter that has to be applied. Legal values are:
|
||||
'blur', 'contour', 'detail', 'edge_enhance', 'edge_enhance_more',
|
||||
'emboss', 'find_edges', 'smooth', 'smooth_more', 'sharpen'.
|
||||
|
||||
Returns
|
||||
-------
|
||||
imfilter : ndarray
|
||||
The array with filter applied.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
*Unknown filter type.* If the filter you are trying
|
||||
to apply is unsupported.
|
||||
|
||||
"""
|
||||
_tdict = {'blur': ImageFilter.BLUR,
|
||||
'contour': ImageFilter.CONTOUR,
|
||||
'detail': ImageFilter.DETAIL,
|
||||
'edge_enhance': ImageFilter.EDGE_ENHANCE,
|
||||
'edge_enhance_more': ImageFilter.EDGE_ENHANCE_MORE,
|
||||
'emboss': ImageFilter.EMBOSS,
|
||||
'find_edges': ImageFilter.FIND_EDGES,
|
||||
'smooth': ImageFilter.SMOOTH,
|
||||
'smooth_more': ImageFilter.SMOOTH_MORE,
|
||||
'sharpen': ImageFilter.SHARPEN
|
||||
}
|
||||
|
||||
im = toimage(arr)
|
||||
if ftype not in _tdict:
|
||||
raise ValueError("Unknown filter type.")
|
||||
return fromimage(im.filter(_tdict[ftype]))
|
||||
@@ -0,0 +1,14 @@
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
|
||||
def configuration(parent_package='',top_path=None):
|
||||
from numpy.distutils.misc_util import Configuration
|
||||
config = Configuration('misc',parent_package,top_path)
|
||||
config.add_data_files('*.dat')
|
||||
config.add_data_dir('tests')
|
||||
return config
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy.distutils.core import setup
|
||||
setup(**configuration(top_path='').todict())
|
||||
|
After Width: | Height: | Size: 102 B |
|
After Width: | Height: | Size: 139 B |
|
After Width: | Height: | Size: 98 B |
|
After Width: | Height: | Size: 140 B |
|
After Width: | Height: | Size: 106 B |
|
After Width: | Height: | Size: 153 B |
|
After Width: | Height: | Size: 125 B |
|
After Width: | Height: | Size: 144 B |
|
After Width: | Height: | Size: 83 B |
|
After Width: | Height: | Size: 86 B |
|
After Width: | Height: | Size: 133 B |
|
After Width: | Height: | Size: 159 B |
|
After Width: | Height: | Size: 149 B |
|
After Width: | Height: | Size: 157 B |
|
After Width: | Height: | Size: 91 B |
|
After Width: | Height: | Size: 97 B |
|
After Width: | Height: | Size: 100 B |
|
After Width: | Height: | Size: 112 B |
|
After Width: | Height: | Size: 77 B |
|
After Width: | Height: | Size: 208 B |
|
After Width: | Height: | Size: 116 B |
|
After Width: | Height: | Size: 2.1 KiB |
|
After Width: | Height: | Size: 449 B |
|
After Width: | Height: | Size: 412 B |
|
After Width: | Height: | Size: 169 B |
@@ -0,0 +1,40 @@
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import pytest
|
||||
from numpy.testing import assert_equal, assert_allclose, assert_almost_equal
|
||||
from scipy._lib._numpy_compat import suppress_warnings
|
||||
|
||||
from scipy.misc import pade, logsumexp, face, ascent, electrocardiogram
|
||||
from scipy.special import logsumexp as sc_logsumexp
|
||||
|
||||
|
||||
def test_logsumexp():
|
||||
# make sure logsumexp can be imported from either scipy.misc or
|
||||
# scipy.special
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning, "`logsumexp` is deprecated")
|
||||
assert_allclose(logsumexp([0, 1]), sc_logsumexp([0, 1]), atol=1e-16)
|
||||
|
||||
|
||||
def test_pade():
|
||||
# make sure scipy.misc.pade exists
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning, "`pade` is deprecated")
|
||||
pade([1, 2], 1)
|
||||
|
||||
|
||||
def test_face():
|
||||
assert_equal(face().shape, (768, 1024, 3))
|
||||
|
||||
|
||||
def test_ascent():
|
||||
assert_equal(ascent().shape, (512, 512))
|
||||
|
||||
|
||||
def test_electrocardiogram():
|
||||
# Test shape, dtype and stats of signal
|
||||
ecg = electrocardiogram()
|
||||
assert ecg.dtype == float
|
||||
assert_equal(ecg.shape, (108000,))
|
||||
assert_almost_equal(ecg.mean(), -0.16510875)
|
||||
assert_almost_equal(ecg.std(), 0.5992473991177294)
|
||||
@@ -0,0 +1,125 @@
|
||||
''' Some tests for the documenting decorator and support functions '''
|
||||
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import sys
|
||||
import pytest
|
||||
from numpy.testing import assert_equal
|
||||
|
||||
from scipy.misc import doccer
|
||||
|
||||
# python -OO strips docstrings
|
||||
DOCSTRINGS_STRIPPED = sys.flags.optimize > 1
|
||||
|
||||
docstring = \
|
||||
"""Docstring
|
||||
%(strtest1)s
|
||||
%(strtest2)s
|
||||
%(strtest3)s
|
||||
"""
|
||||
param_doc1 = \
|
||||
"""Another test
|
||||
with some indent"""
|
||||
|
||||
param_doc2 = \
|
||||
"""Another test, one line"""
|
||||
|
||||
param_doc3 = \
|
||||
""" Another test
|
||||
with some indent"""
|
||||
|
||||
doc_dict = {'strtest1':param_doc1,
|
||||
'strtest2':param_doc2,
|
||||
'strtest3':param_doc3}
|
||||
|
||||
filled_docstring = \
|
||||
"""Docstring
|
||||
Another test
|
||||
with some indent
|
||||
Another test, one line
|
||||
Another test
|
||||
with some indent
|
||||
"""
|
||||
|
||||
|
||||
def test_unindent():
|
||||
assert_equal(doccer.unindent_string(param_doc1), param_doc1)
|
||||
assert_equal(doccer.unindent_string(param_doc2), param_doc2)
|
||||
assert_equal(doccer.unindent_string(param_doc3), param_doc1)
|
||||
|
||||
|
||||
def test_unindent_dict():
|
||||
d2 = doccer.unindent_dict(doc_dict)
|
||||
assert_equal(d2['strtest1'], doc_dict['strtest1'])
|
||||
assert_equal(d2['strtest2'], doc_dict['strtest2'])
|
||||
assert_equal(d2['strtest3'], doc_dict['strtest1'])
|
||||
|
||||
|
||||
def test_docformat():
|
||||
udd = doccer.unindent_dict(doc_dict)
|
||||
formatted = doccer.docformat(docstring, udd)
|
||||
assert_equal(formatted, filled_docstring)
|
||||
single_doc = 'Single line doc %(strtest1)s'
|
||||
formatted = doccer.docformat(single_doc, doc_dict)
|
||||
# Note - initial indent of format string does not
|
||||
# affect subsequent indent of inserted parameter
|
||||
assert_equal(formatted, """Single line doc Another test
|
||||
with some indent""")
|
||||
|
||||
|
||||
@pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstrings stripped")
|
||||
def test_decorator():
|
||||
# with unindentation of parameters
|
||||
decorator = doccer.filldoc(doc_dict, True)
|
||||
|
||||
@decorator
|
||||
def func():
|
||||
""" Docstring
|
||||
%(strtest3)s
|
||||
"""
|
||||
assert_equal(func.__doc__, """ Docstring
|
||||
Another test
|
||||
with some indent
|
||||
""")
|
||||
|
||||
# without unindentation of parameters
|
||||
decorator = doccer.filldoc(doc_dict, False)
|
||||
|
||||
@decorator
|
||||
def func():
|
||||
""" Docstring
|
||||
%(strtest3)s
|
||||
"""
|
||||
assert_equal(func.__doc__, """ Docstring
|
||||
Another test
|
||||
with some indent
|
||||
""")
|
||||
|
||||
|
||||
@pytest.mark.skipif(DOCSTRINGS_STRIPPED, reason="docstrings stripped")
|
||||
def test_inherit_docstring_from():
|
||||
|
||||
class Foo(object):
|
||||
def func(self):
|
||||
'''Do something useful.'''
|
||||
return
|
||||
|
||||
def func2(self):
|
||||
'''Something else.'''
|
||||
|
||||
class Bar(Foo):
|
||||
@doccer.inherit_docstring_from(Foo)
|
||||
def func(self):
|
||||
'''%(super)sABC'''
|
||||
return
|
||||
|
||||
@doccer.inherit_docstring_from(Foo)
|
||||
def func2(self):
|
||||
# No docstring.
|
||||
return
|
||||
|
||||
assert_equal(Bar.func.__doc__, Foo.func.__doc__ + 'ABC')
|
||||
assert_equal(Bar.func2.__doc__, Foo.func2.__doc__)
|
||||
bar = Bar()
|
||||
assert_equal(bar.func.__doc__, Foo.func.__doc__ + 'ABC')
|
||||
assert_equal(bar.func2.__doc__, Foo.func2.__doc__)
|
||||
@@ -0,0 +1,283 @@
|
||||
from __future__ import division, print_function, absolute_import
|
||||
|
||||
import os.path
|
||||
import tempfile
|
||||
import shutil
|
||||
import numpy as np
|
||||
import glob
|
||||
|
||||
import pytest
|
||||
from pytest import raises as assert_raises
|
||||
from numpy.testing import (assert_equal, assert_allclose,
|
||||
assert_array_equal, assert_)
|
||||
from scipy._lib._numpy_compat import suppress_warnings
|
||||
from scipy import misc
|
||||
from numpy.ma.testutils import assert_mask_equal
|
||||
|
||||
try:
|
||||
import PIL.Image
|
||||
except ImportError:
|
||||
_have_PIL = False
|
||||
else:
|
||||
_have_PIL = True
|
||||
|
||||
|
||||
# Function / method decorator for skipping PIL tests on import failure
|
||||
_pilskip = pytest.mark.skipif(not _have_PIL, reason='Need to import PIL for this test')
|
||||
|
||||
datapath = os.path.dirname(__file__)
|
||||
|
||||
@_pilskip
|
||||
class TestPILUtil(object):
|
||||
def test_imresize(self):
|
||||
im = np.random.random((10, 20))
|
||||
for T in np.sctypes['float'] + [float]:
|
||||
# 1.1 rounds to below 1.1 for float16, 1.101 works
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im1 = misc.imresize(im, T(1.101))
|
||||
assert_equal(im1.shape, (11, 22))
|
||||
|
||||
def test_imresize2(self):
|
||||
im = np.random.random((20, 30))
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im2 = misc.imresize(im, (30, 40), interp='bicubic')
|
||||
assert_equal(im2.shape, (30, 40))
|
||||
|
||||
def test_imresize3(self):
|
||||
im = np.random.random((15, 30))
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im2 = misc.imresize(im, (30, 60), interp='nearest')
|
||||
assert_equal(im2.shape, (30, 60))
|
||||
|
||||
def test_imresize4(self):
|
||||
im = np.array([[1, 2],
|
||||
[3, 4]])
|
||||
# Check that resizing by target size, float and int are the same
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im2 = misc.imresize(im, (4, 4), mode='F') # output size
|
||||
im3 = misc.imresize(im, 2., mode='F') # fraction
|
||||
im4 = misc.imresize(im, 200, mode='F') # percentage
|
||||
assert_equal(im2, im3)
|
||||
assert_equal(im2, im4)
|
||||
|
||||
def test_imresize5(self):
|
||||
im = np.random.random((25, 15))
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im2 = misc.imresize(im, (30, 60), interp='lanczos')
|
||||
assert_equal(im2.shape, (30, 60))
|
||||
|
||||
def test_bytescale(self):
|
||||
x = np.array([0, 1, 2], np.uint8)
|
||||
y = np.array([0, 1, 2])
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
assert_equal(misc.bytescale(x), x)
|
||||
assert_equal(misc.bytescale(y), [0, 128, 255])
|
||||
|
||||
def test_bytescale_keywords(self):
|
||||
x = np.array([40, 60, 120, 200, 300, 500])
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
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 test_bytescale_cscale_lowhigh(self):
|
||||
a = np.arange(10)
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
actual = misc.bytescale(a, cmin=3, cmax=6, low=100, high=200)
|
||||
expected = [100, 100, 100, 100, 133, 167, 200, 200, 200, 200]
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_bytescale_mask(self):
|
||||
a = np.ma.MaskedArray(data=[1, 2, 3], mask=[False, False, True])
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
actual = misc.bytescale(a)
|
||||
expected = [0, 255, 3]
|
||||
assert_equal(expected, actual)
|
||||
assert_mask_equal(a.mask, actual.mask)
|
||||
assert_(isinstance(actual, np.ma.MaskedArray))
|
||||
|
||||
def test_bytescale_rounding(self):
|
||||
a = np.array([-0.5, 0.5, 1.5, 2.5, 3.5])
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
actual = misc.bytescale(a, cmin=0, cmax=10, low=0, high=10)
|
||||
expected = [0, 1, 2, 3, 4]
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_bytescale_low_greaterthan_high(self):
|
||||
with assert_raises(ValueError):
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
misc.bytescale(np.arange(3), low=10, high=5)
|
||||
|
||||
def test_bytescale_low_lessthan_0(self):
|
||||
with assert_raises(ValueError):
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
misc.bytescale(np.arange(3), low=-1)
|
||||
|
||||
def test_bytescale_high_greaterthan_255(self):
|
||||
with assert_raises(ValueError):
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
misc.bytescale(np.arange(3), high=256)
|
||||
|
||||
def test_bytescale_low_equals_high(self):
|
||||
a = np.arange(3)
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
actual = misc.bytescale(a, low=10, high=10)
|
||||
expected = [10, 10, 10]
|
||||
assert_equal(actual, expected)
|
||||
|
||||
def test_imsave(self):
|
||||
picdir = os.path.join(datapath, "data")
|
||||
for png in glob.iglob(picdir + "/*.png"):
|
||||
with suppress_warnings() as sup:
|
||||
# PIL causes a Py3k ResourceWarning
|
||||
sup.filter(message="unclosed file")
|
||||
sup.filter(DeprecationWarning)
|
||||
img = misc.imread(png)
|
||||
tmpdir = tempfile.mkdtemp()
|
||||
try:
|
||||
fn1 = os.path.join(tmpdir, 'test.png')
|
||||
fn2 = os.path.join(tmpdir, 'testimg')
|
||||
with suppress_warnings() as sup:
|
||||
# PIL causes a Py3k ResourceWarning
|
||||
sup.filter(message="unclosed file")
|
||||
sup.filter(DeprecationWarning)
|
||||
misc.imsave(fn1, img)
|
||||
misc.imsave(fn2, img, 'PNG')
|
||||
|
||||
with suppress_warnings() as sup:
|
||||
# PIL causes a Py3k ResourceWarning
|
||||
sup.filter(message="unclosed file")
|
||||
sup.filter(DeprecationWarning)
|
||||
data1 = misc.imread(fn1)
|
||||
data2 = misc.imread(fn2)
|
||||
assert_allclose(data1, img)
|
||||
assert_allclose(data2, img)
|
||||
assert_equal(data1.shape, img.shape)
|
||||
assert_equal(data2.shape, img.shape)
|
||||
finally:
|
||||
shutil.rmtree(tmpdir)
|
||||
|
||||
|
||||
def check_fromimage(filename, irange, shape):
|
||||
fp = open(filename, "rb")
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
img = misc.fromimage(PIL.Image.open(fp))
|
||||
fp.close()
|
||||
imin, imax = irange
|
||||
assert_equal(img.min(), imin)
|
||||
assert_equal(img.max(), imax)
|
||||
assert_equal(img.shape, shape)
|
||||
|
||||
|
||||
@_pilskip
|
||||
def test_fromimage():
|
||||
# Test generator for parametric tests
|
||||
# Tuples in the list are (filename, (datamin, datamax), shape).
|
||||
files = [('icon.png', (0, 255), (48, 48, 4)),
|
||||
('icon_mono.png', (0, 255), (48, 48, 4)),
|
||||
('icon_mono_flat.png', (0, 255), (48, 48, 3))]
|
||||
for fn, irange, shape in files:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
check_fromimage(os.path.join(datapath, 'data', fn), irange, shape)
|
||||
|
||||
|
||||
@_pilskip
|
||||
def test_imread_indexed_png():
|
||||
# The file `foo3x5x4indexed.png` was created with this array
|
||||
# (3x5 is (height)x(width)):
|
||||
data = np.array([[[127, 0, 255, 255],
|
||||
[127, 0, 255, 255],
|
||||
[127, 0, 255, 255],
|
||||
[127, 0, 255, 255],
|
||||
[127, 0, 255, 255]],
|
||||
[[192, 192, 255, 0],
|
||||
[192, 192, 255, 0],
|
||||
[0, 0, 255, 0],
|
||||
[0, 0, 255, 0],
|
||||
[0, 0, 255, 0]],
|
||||
[[0, 31, 255, 255],
|
||||
[0, 31, 255, 255],
|
||||
[0, 31, 255, 255],
|
||||
[0, 31, 255, 255],
|
||||
[0, 31, 255, 255]]], dtype=np.uint8)
|
||||
|
||||
filename = os.path.join(datapath, 'data', 'foo3x5x4indexed.png')
|
||||
with open(filename, 'rb') as f:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im = misc.imread(f)
|
||||
assert_array_equal(im, data)
|
||||
|
||||
|
||||
@_pilskip
|
||||
def test_imread_1bit():
|
||||
# box1.png is a 48x48 grayscale image with bit depth 1.
|
||||
# The border pixels are 1 and the rest are 0.
|
||||
filename = os.path.join(datapath, 'data', 'box1.png')
|
||||
with open(filename, 'rb') as f:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im = misc.imread(f)
|
||||
assert_equal(im.dtype, np.uint8)
|
||||
expected = np.zeros((48, 48), dtype=np.uint8)
|
||||
# When scaled up from 1 bit to 8 bits, 1 becomes 255.
|
||||
expected[:, 0] = 255
|
||||
expected[:, -1] = 255
|
||||
expected[0, :] = 255
|
||||
expected[-1, :] = 255
|
||||
assert_equal(im, expected)
|
||||
|
||||
|
||||
@_pilskip
|
||||
def test_imread_2bit():
|
||||
# blocks2bit.png is a 12x12 grayscale image with bit depth 2.
|
||||
# The pattern is 4 square subblocks of size 6x6. Upper left
|
||||
# is all 0, upper right is all 1, lower left is all 2, lower
|
||||
# right is all 3.
|
||||
# When scaled up to 8 bits, the values become [0, 85, 170, 255].
|
||||
filename = os.path.join(datapath, 'data', 'blocks2bit.png')
|
||||
with open(filename, 'rb') as f:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im = misc.imread(f)
|
||||
assert_equal(im.dtype, np.uint8)
|
||||
expected = np.zeros((12, 12), dtype=np.uint8)
|
||||
expected[:6, 6:] = 85
|
||||
expected[6:, :6] = 170
|
||||
expected[6:, 6:] = 255
|
||||
assert_equal(im, expected)
|
||||
|
||||
|
||||
@_pilskip
|
||||
def test_imread_4bit():
|
||||
# pattern4bit.png is a 12(h) x 31(w) grayscale image with bit depth 4.
|
||||
# The value in row j and column i is maximum(j, i) % 16.
|
||||
# When scaled up to 8 bits, the values become [0, 17, 34, ..., 255].
|
||||
filename = os.path.join(datapath, 'data', 'pattern4bit.png')
|
||||
with open(filename, 'rb') as f:
|
||||
with suppress_warnings() as sup:
|
||||
sup.filter(DeprecationWarning)
|
||||
im = misc.imread(f)
|
||||
assert_equal(im.dtype, np.uint8)
|
||||
j, i = np.meshgrid(np.arange(12), np.arange(31), indexing='ij')
|
||||
expected = 17*(np.maximum(j, i) % 16).astype(np.uint8)
|
||||
assert_equal(im, expected)
|
||||
|
||||