Fixed database typo and removed unnecessary class identifier.
136
venv/Lib/site-packages/skimage/__init__.py
Normal file
|
@ -0,0 +1,136 @@
|
|||
"""Image Processing for Python
|
||||
|
||||
``scikit-image`` (a.k.a. ``skimage``) is a collection of algorithms for image
|
||||
processing and computer vision.
|
||||
|
||||
The main package of ``skimage`` only provides a few utilities for converting
|
||||
between image data types; for most features, you need to import one of the
|
||||
following subpackages:
|
||||
|
||||
Subpackages
|
||||
-----------
|
||||
color
|
||||
Color space conversion.
|
||||
data
|
||||
Test images and example data.
|
||||
draw
|
||||
Drawing primitives (lines, text, etc.) that operate on NumPy arrays.
|
||||
exposure
|
||||
Image intensity adjustment, e.g., histogram equalization, etc.
|
||||
feature
|
||||
Feature detection and extraction, e.g., texture analysis corners, etc.
|
||||
filters
|
||||
Sharpening, edge finding, rank filters, thresholding, etc.
|
||||
graph
|
||||
Graph-theoretic operations, e.g., shortest paths.
|
||||
io
|
||||
Reading, saving, and displaying images and video.
|
||||
measure
|
||||
Measurement of image properties, e.g., similarity and contours.
|
||||
morphology
|
||||
Morphological operations, e.g., opening or skeletonization.
|
||||
restoration
|
||||
Restoration algorithms, e.g., deconvolution algorithms, denoising, etc.
|
||||
segmentation
|
||||
Partitioning an image into multiple regions.
|
||||
transform
|
||||
Geometric and other transforms, e.g., rotation or the Radon transform.
|
||||
util
|
||||
Generic utilities.
|
||||
viewer
|
||||
A simple graphical user interface for visualizing results and exploring
|
||||
parameters.
|
||||
|
||||
Utility Functions
|
||||
-----------------
|
||||
img_as_float
|
||||
Convert an image to floating point format, with values in [0, 1].
|
||||
Is similar to `img_as_float64`, but will not convert lower-precision
|
||||
floating point arrays to `float64`.
|
||||
img_as_float32
|
||||
Convert an image to single-precision (32-bit) floating point format,
|
||||
with values in [0, 1].
|
||||
img_as_float64
|
||||
Convert an image to double-precision (64-bit) floating point format,
|
||||
with values in [0, 1].
|
||||
img_as_uint
|
||||
Convert an image to unsigned integer format, with values in [0, 65535].
|
||||
img_as_int
|
||||
Convert an image to signed integer format, with values in [-32768, 32767].
|
||||
img_as_ubyte
|
||||
Convert an image to unsigned byte format, with values in [0, 255].
|
||||
img_as_bool
|
||||
Convert an image to boolean format, with values either True or False.
|
||||
dtype_limits
|
||||
Return intensity limits, i.e. (min, max) tuple, of the image's dtype.
|
||||
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
|
||||
__version__ = '0.17.2'
|
||||
|
||||
from ._shared.version_requirements import ensure_python_version
|
||||
ensure_python_version((3, 5))
|
||||
|
||||
# Logic for checking for improper install and importing while in the source
|
||||
# tree when package has not been installed inplace.
|
||||
# Code adapted from scikit-learn's __check_build module.
|
||||
_INPLACE_MSG = """
|
||||
It appears that you are importing a local scikit-image source tree. For
|
||||
this, you need to have an inplace install. Maybe you are in the source
|
||||
directory and you need to try from another location."""
|
||||
|
||||
_STANDARD_MSG = """
|
||||
Your install of scikit-image appears to be broken.
|
||||
Try re-installing the package following the instructions at:
|
||||
https://scikit-image.org/docs/stable/install.html """
|
||||
|
||||
|
||||
def _raise_build_error(e):
|
||||
# Raise a comprehensible error
|
||||
import os.path as osp
|
||||
local_dir = osp.split(__file__)[0]
|
||||
msg = _STANDARD_MSG
|
||||
if local_dir == "skimage":
|
||||
# Picking up the local install: this will work only if the
|
||||
# install is an 'inplace build'
|
||||
msg = _INPLACE_MSG
|
||||
raise ImportError("""%s
|
||||
It seems that scikit-image has not been built correctly.
|
||||
%s""" % (e, msg))
|
||||
|
||||
|
||||
try:
|
||||
# This variable is injected in the __builtins__ by the build
|
||||
# process. It used to enable importing subpackages of skimage when
|
||||
# the binaries are not built
|
||||
__SKIMAGE_SETUP__
|
||||
except NameError:
|
||||
__SKIMAGE_SETUP__ = False
|
||||
|
||||
if __SKIMAGE_SETUP__:
|
||||
sys.stderr.write('Partial import of skimage during the build process.\n')
|
||||
# We are not importing the rest of the scikit during the build
|
||||
# process, as it may not be compiled yet
|
||||
else:
|
||||
try:
|
||||
from ._shared import geometry
|
||||
del geometry
|
||||
except ImportError as e:
|
||||
_raise_build_error(e)
|
||||
|
||||
# All skimage root imports go here
|
||||
from .util.dtype import (img_as_float32,
|
||||
img_as_float64,
|
||||
img_as_float,
|
||||
img_as_int,
|
||||
img_as_uint,
|
||||
img_as_ubyte,
|
||||
img_as_bool,
|
||||
dtype_limits)
|
||||
from .data import data_dir
|
||||
from .util.lookfor import lookfor
|
||||
|
||||
del sys
|
BIN
venv/Lib/site-packages/skimage/__pycache__/_build.cpython-36.pyc
Normal file
BIN
venv/Lib/site-packages/skimage/__pycache__/setup.cpython-36.pyc
Normal file
86
venv/Lib/site-packages/skimage/_build.py
Normal file
|
@ -0,0 +1,86 @@
|
|||
import sys
|
||||
import os
|
||||
from distutils.version import LooseVersion
|
||||
from multiprocessing import cpu_count
|
||||
|
||||
CYTHON_VERSION = '0.23.4'
|
||||
|
||||
# WindowsError is not defined on unix systems
|
||||
try:
|
||||
WindowsError
|
||||
except NameError:
|
||||
class WindowsError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
def _compiled_filename(f):
|
||||
"""Check for the presence of a .pyx[.in] file as a .c or .cpp."""
|
||||
basename = f.replace('.in', '').replace('.pyx', '')
|
||||
for ext in ('.c', '.cpp'):
|
||||
filename = basename + ext
|
||||
if os.path.exists(filename):
|
||||
return filename
|
||||
else:
|
||||
raise RuntimeError('Cython >= %s is required to build '
|
||||
'scikit-image from git checkout' %
|
||||
CYTHON_VERSION)
|
||||
|
||||
|
||||
def cython(pyx_files, working_path=''):
|
||||
"""Use Cython to convert the given files to C.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pyx_files : list of str
|
||||
The input .pyx files.
|
||||
|
||||
"""
|
||||
# Do not build cython files if target is clean
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == 'clean':
|
||||
return
|
||||
|
||||
try:
|
||||
from Cython import __version__
|
||||
if LooseVersion(__version__) < CYTHON_VERSION:
|
||||
raise RuntimeError('Cython >= %s needed to build scikit-image' % CYTHON_VERSION)
|
||||
|
||||
from Cython.Build import cythonize
|
||||
except ImportError:
|
||||
# If cython is not found, the build will make use of
|
||||
# the distributed .c or .cpp files if present
|
||||
c_files_used = [_compiled_filename(os.path.join(working_path, f))
|
||||
for f in pyx_files]
|
||||
|
||||
print("Cython >= %s not found; falling back to pre-built %s" \
|
||||
% (CYTHON_VERSION, " ".join(c_files_used)))
|
||||
else:
|
||||
pyx_files = [os.path.join(working_path, f) for f in pyx_files]
|
||||
for i, pyxfile in enumerate(pyx_files):
|
||||
if pyxfile.endswith('.pyx.in'):
|
||||
process_tempita_pyx(pyxfile)
|
||||
pyx_files[i] = pyxfile.replace('.pyx.in', '.pyx')
|
||||
|
||||
# Cython doesn't automatically choose a number of threads > 1
|
||||
# https://github.com/cython/cython/blob/a0bbb940c847dfe92cac446c8784c34c28c92836/Cython/Build/Dependencies.py#L923-L925
|
||||
cythonize(pyx_files, nthreads=cpu_count(),
|
||||
compiler_directives={'language_level': 3})
|
||||
|
||||
|
||||
def process_tempita_pyx(fromfile):
|
||||
try:
|
||||
try:
|
||||
from Cython import Tempita as tempita
|
||||
except ImportError:
|
||||
import tempita
|
||||
except ImportError:
|
||||
raise Exception('Building requires Tempita: '
|
||||
'pip install --user Tempita')
|
||||
template = tempita.Template.from_filename(fromfile,
|
||||
encoding=sys.getdefaultencoding())
|
||||
pyxcontent = template.substitute()
|
||||
if not fromfile.endswith('.pyx.in'):
|
||||
raise ValueError("Unexpected extension of %s." % fromfile)
|
||||
|
||||
pyxfile = os.path.splitext(fromfile)[0] # split off the .in ending
|
||||
with open(pyxfile, "w") as f:
|
||||
f.write(pyxcontent)
|
0
venv/Lib/site-packages/skimage/_shared/__init__.py
Normal file
55
venv/Lib/site-packages/skimage/_shared/_geometry.py
Normal file
|
@ -0,0 +1,55 @@
|
|||
__all__ = ['polygon_clip', 'polygon_area']
|
||||
|
||||
import numpy as np
|
||||
|
||||
|
||||
def polygon_clip(rp, cp, r0, c0, r1, c1):
|
||||
"""Clip a polygon to the given bounding box.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
rp, cp : (N,) ndarray of double
|
||||
Row and column coordinates of the polygon.
|
||||
(r0, c0), (r1, c1) : double
|
||||
Top-left and bottom-right coordinates of the bounding box.
|
||||
|
||||
Returns
|
||||
-------
|
||||
r_clipped, c_clipped : (M,) ndarray of double
|
||||
Coordinates of clipped polygon.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This makes use of Sutherland-Hodgman clipping as implemented in
|
||||
AGG 2.4 and exposed in Matplotlib.
|
||||
|
||||
"""
|
||||
from matplotlib import path, transforms
|
||||
|
||||
poly = path.Path(np.vstack((rp, cp)).T, closed=True)
|
||||
clip_rect = transforms.Bbox([[r0, c0], [r1, c1]])
|
||||
poly_clipped = poly.clip_to_bbox(clip_rect).to_polygons()[0]
|
||||
|
||||
# This should be fixed in matplotlib >1.5
|
||||
if np.all(poly_clipped[-1] == poly_clipped[-2]):
|
||||
poly_clipped = poly_clipped[:-1]
|
||||
|
||||
return poly_clipped[:, 0], poly_clipped[:, 1]
|
||||
|
||||
|
||||
def polygon_area(pr, pc):
|
||||
"""Compute the area of a polygon.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
pr, pc : (N,) array of float
|
||||
Polygon row and column coordinates.
|
||||
|
||||
Returns
|
||||
-------
|
||||
a : float
|
||||
Area of the polygon.
|
||||
"""
|
||||
pr = np.asarray(pr)
|
||||
pc = np.asarray(pc)
|
||||
return 0.5 * np.abs(np.sum((pc[:-1] * pr[1:]) - (pc[1:] * pr[:-1])))
|
27
venv/Lib/site-packages/skimage/_shared/_tempfile.py
Normal file
|
@ -0,0 +1,27 @@
|
|||
from tempfile import NamedTemporaryFile
|
||||
from contextlib import contextmanager
|
||||
import os
|
||||
|
||||
@contextmanager
|
||||
def temporary_file(suffix=''):
|
||||
"""Yield a writeable temporary filename that is deleted on context exit.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
suffix : string, optional
|
||||
The suffix for the file.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import numpy as np
|
||||
>>> from skimage import io
|
||||
>>> with temporary_file('.tif') as tempfile:
|
||||
... im = np.arange(25, dtype=np.uint8).reshape((5, 5))
|
||||
... io.imsave(tempfile, im)
|
||||
... assert np.all(io.imread(tempfile) == im)
|
||||
"""
|
||||
tempfile_stream = NamedTemporaryFile(suffix=suffix, delete=False)
|
||||
tempfile = tempfile_stream.name
|
||||
tempfile_stream.close()
|
||||
yield tempfile
|
||||
os.remove(tempfile)
|
145
venv/Lib/site-packages/skimage/_shared/_warnings.py
Normal file
|
@ -0,0 +1,145 @@
|
|||
from contextlib import contextmanager
|
||||
import sys
|
||||
import warnings
|
||||
import re
|
||||
import functools
|
||||
import os
|
||||
|
||||
__all__ = ['all_warnings', 'expected_warnings', 'warn']
|
||||
|
||||
|
||||
# A version of `warnings.warn` with a default stacklevel of 2.
|
||||
# functool is used so as not to increase the call stack accidentally
|
||||
warn = functools.partial(warnings.warn, stacklevel=2)
|
||||
|
||||
|
||||
@contextmanager
|
||||
def all_warnings():
|
||||
"""
|
||||
Context for use in testing to ensure that all warnings are raised.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import warnings
|
||||
>>> def foo():
|
||||
... warnings.warn(RuntimeWarning("bar"), stacklevel=2)
|
||||
|
||||
We raise the warning once, while the warning filter is set to "once".
|
||||
Hereafter, the warning is invisible, even with custom filters:
|
||||
|
||||
>>> with warnings.catch_warnings():
|
||||
... warnings.simplefilter('once')
|
||||
... foo() # doctest: +SKIP
|
||||
|
||||
We can now run ``foo()`` without a warning being raised:
|
||||
|
||||
>>> from numpy.testing import assert_warns
|
||||
>>> foo() # doctest: +SKIP
|
||||
|
||||
To catch the warning, we call in the help of ``all_warnings``:
|
||||
|
||||
>>> with all_warnings():
|
||||
... assert_warns(RuntimeWarning, foo)
|
||||
"""
|
||||
# _warnings.py is on the critical import path.
|
||||
# Since this is a testing only function, we lazy import inspect.
|
||||
import inspect
|
||||
# Whenever a warning is triggered, Python adds a __warningregistry__
|
||||
# member to the *calling* module. The exercize here is to find
|
||||
# and eradicate all those breadcrumbs that were left lying around.
|
||||
#
|
||||
# We proceed by first searching all parent calling frames and explicitly
|
||||
# clearing their warning registries (necessary for the doctests above to
|
||||
# pass). Then, we search for all submodules of skimage and clear theirs
|
||||
# as well (necessary for the skimage test suite to pass).
|
||||
|
||||
frame = inspect.currentframe()
|
||||
if frame:
|
||||
for f in inspect.getouterframes(frame):
|
||||
f[0].f_locals['__warningregistry__'] = {}
|
||||
del frame
|
||||
|
||||
for mod_name, mod in list(sys.modules.items()):
|
||||
try:
|
||||
mod.__warningregistry__.clear()
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
with warnings.catch_warnings(record=True) as w:
|
||||
warnings.simplefilter("always")
|
||||
yield w
|
||||
|
||||
|
||||
@contextmanager
|
||||
def expected_warnings(matching):
|
||||
r"""Context for use in testing to catch known warnings matching regexes
|
||||
|
||||
Parameters
|
||||
----------
|
||||
matching : None or a list of strings or compiled regexes
|
||||
Regexes for the desired warning to catch
|
||||
If matching is None, this behaves as a no-op.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> import numpy as np
|
||||
>>> image = np.random.randint(0, 2**16, size=(100, 100), dtype=np.uint16)
|
||||
>>> # rank filters are slow when bit-depth exceeds 10 bits
|
||||
>>> from skimage import filters
|
||||
>>> with expected_warnings(['Bad rank filter performance']):
|
||||
... median_filtered = filters.rank.median(image)
|
||||
|
||||
Notes
|
||||
-----
|
||||
Uses `all_warnings` to ensure all warnings are raised.
|
||||
Upon exiting, it checks the recorded warnings for the desired matching
|
||||
pattern(s).
|
||||
Raises a ValueError if any match was not found or an unexpected
|
||||
warning was raised.
|
||||
Allows for three types of behaviors: `and`, `or`, and `optional` matches.
|
||||
This is done to accommodate different build environments or loop conditions
|
||||
that may produce different warnings. The behaviors can be combined.
|
||||
If you pass multiple patterns, you get an orderless `and`, where all of the
|
||||
warnings must be raised.
|
||||
If you use the `|` operator in a pattern, you can catch one of several
|
||||
warnings.
|
||||
Finally, you can use `|\A\Z` in a pattern to signify it as optional.
|
||||
|
||||
"""
|
||||
if isinstance(matching, str):
|
||||
raise ValueError('``matching`` should be a list of strings and not '
|
||||
'a string itself.')
|
||||
|
||||
# Special case for disabling the context manager
|
||||
if matching is None:
|
||||
yield None
|
||||
return
|
||||
|
||||
strict_warnings = os.environ.get('SKIMAGE_TEST_STRICT_WARNINGS', '1')
|
||||
if strict_warnings.lower() == 'true':
|
||||
strict_warnings = True
|
||||
elif strict_warnings.lower() == 'false':
|
||||
strict_warnings = False
|
||||
else:
|
||||
strict_warnings = bool(int(strict_warnings))
|
||||
|
||||
with all_warnings() as w:
|
||||
# enter context
|
||||
yield w
|
||||
# exited user context, check the recorded warnings
|
||||
# Allow users to provide None
|
||||
while None in matching:
|
||||
matching.remove(None)
|
||||
remaining = [m for m in matching if r'\A\Z' not in m.split('|')]
|
||||
for warn in w:
|
||||
found = False
|
||||
for match in matching:
|
||||
if re.search(match, str(warn.message)) is not None:
|
||||
found = True
|
||||
if match in remaining:
|
||||
remaining.remove(match)
|
||||
if strict_warnings and not found:
|
||||
raise ValueError('Unexpected warning: %s' % str(warn.message))
|
||||
if strict_warnings and (len(remaining) > 0):
|
||||
msg = 'No warning raised matching:\n%s' % '\n'.join(remaining)
|
||||
raise ValueError(msg)
|
BIN
venv/Lib/site-packages/skimage/_shared/fast_exp.cp36-win32.pyd
Normal file
17
venv/Lib/site-packages/skimage/_shared/fft.py
Normal file
|
@ -0,0 +1,17 @@
|
|||
"""Prefer FFTs via the new scipy.fft module when available (SciPy 1.4+)
|
||||
|
||||
Otherwise fall back to numpy.fft.
|
||||
|
||||
Like numpy 1.15+ scipy 1.3+ is also using pocketfft, but a newer
|
||||
C++/pybind11 version called pypocketfft
|
||||
"""
|
||||
try:
|
||||
import scipy.fft
|
||||
from scipy.fft import next_fast_len
|
||||
fftmodule = scipy.fft
|
||||
except ImportError:
|
||||
import numpy.fft
|
||||
fftmodule = numpy.fft
|
||||
from scipy.fftpack import next_fast_len
|
||||
|
||||
__all__ = ['fftmodule', 'next_fast_len']
|
BIN
venv/Lib/site-packages/skimage/_shared/geometry.cp36-win32.pyd
Normal file
37
venv/Lib/site-packages/skimage/_shared/setup.py
Normal file
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import os
|
||||
|
||||
from skimage._build import cython
|
||||
|
||||
base_path = os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
|
||||
def configuration(parent_package='', top_path=None):
|
||||
from numpy.distutils.misc_util import Configuration, get_numpy_include_dirs
|
||||
|
||||
config = Configuration('_shared', parent_package, top_path)
|
||||
|
||||
cython(['geometry.pyx',
|
||||
'transform.pyx',
|
||||
'interpolation.pyx',
|
||||
'fast_exp.pyx'], working_path=base_path)
|
||||
|
||||
config.add_extension('geometry', sources=['geometry.c'])
|
||||
config.add_extension('transform', sources=['transform.c'],
|
||||
include_dirs=[get_numpy_include_dirs()])
|
||||
config.add_extension('interpolation', sources=['interpolation.c'])
|
||||
config.add_extension('fast_exp', sources=['fast_exp.c'])
|
||||
return config
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy.distutils.core import setup
|
||||
setup(maintainer='scikit-image Developers',
|
||||
author='scikit-image Developers',
|
||||
maintainer_email='scikit-image@python.org',
|
||||
description='Transforms',
|
||||
url='https://github.com/scikit-image/scikit-image',
|
||||
license='SciPy License (BSD Style)',
|
||||
**(configuration(top_path='').todict())
|
||||
)
|
270
venv/Lib/site-packages/skimage/_shared/testing.py
Normal file
|
@ -0,0 +1,270 @@
|
|||
"""
|
||||
Testing utilities.
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
import struct
|
||||
import threading
|
||||
import functools
|
||||
from tempfile import NamedTemporaryFile
|
||||
|
||||
import numpy as np
|
||||
from numpy import testing
|
||||
from numpy.testing import (assert_array_equal, assert_array_almost_equal,
|
||||
assert_array_less, assert_array_almost_equal_nulp,
|
||||
assert_equal, TestCase, assert_allclose,
|
||||
assert_almost_equal, assert_, assert_warns,
|
||||
assert_no_warnings)
|
||||
|
||||
import warnings
|
||||
|
||||
from .. import data, io
|
||||
from ..util import img_as_uint, img_as_float, img_as_int, img_as_ubyte
|
||||
import pytest
|
||||
from ._warnings import expected_warnings
|
||||
|
||||
|
||||
SKIP_RE = re.compile(r"(\s*>>>.*?)(\s*)#\s*skip\s+if\s+(.*)$")
|
||||
|
||||
skipif = pytest.mark.skipif
|
||||
xfail = pytest.mark.xfail
|
||||
parametrize = pytest.mark.parametrize
|
||||
raises = pytest.raises
|
||||
fixture = pytest.fixture
|
||||
|
||||
# true if python is running in 32bit mode
|
||||
# Calculate the size of a void * pointer in bits
|
||||
# https://docs.python.org/3/library/struct.html
|
||||
arch32 = struct.calcsize("P") * 8 == 32
|
||||
|
||||
|
||||
def assert_less(a, b, msg=None):
|
||||
message = "%r is not lower than %r" % (a, b)
|
||||
if msg is not None:
|
||||
message += ": " + msg
|
||||
assert a < b, message
|
||||
|
||||
|
||||
def assert_greater(a, b, msg=None):
|
||||
message = "%r is not greater than %r" % (a, b)
|
||||
if msg is not None:
|
||||
message += ": " + msg
|
||||
assert a > b, message
|
||||
|
||||
|
||||
def doctest_skip_parser(func):
|
||||
""" Decorator replaces custom skip test markup in doctests
|
||||
|
||||
Say a function has a docstring::
|
||||
|
||||
>>> something, HAVE_AMODULE, HAVE_BMODULE = 0, False, False
|
||||
>>> something # skip if not HAVE_AMODULE
|
||||
0
|
||||
>>> something # skip if HAVE_BMODULE
|
||||
0
|
||||
|
||||
This decorator will evaluate the expression after ``skip if``. If this
|
||||
evaluates to True, then the comment is replaced by ``# doctest: +SKIP``. If
|
||||
False, then the comment is just removed. The expression is evaluated in the
|
||||
``globals`` scope of `func`.
|
||||
|
||||
For example, if the module global ``HAVE_AMODULE`` is False, and module
|
||||
global ``HAVE_BMODULE`` is False, the returned function will have docstring::
|
||||
|
||||
>>> something # doctest: +SKIP
|
||||
>>> something + else # doctest: +SKIP
|
||||
>>> something # doctest: +SKIP
|
||||
|
||||
"""
|
||||
lines = func.__doc__.split('\n')
|
||||
new_lines = []
|
||||
for line in lines:
|
||||
match = SKIP_RE.match(line)
|
||||
if match is None:
|
||||
new_lines.append(line)
|
||||
continue
|
||||
code, space, expr = match.groups()
|
||||
|
||||
try:
|
||||
# Works as a function decorator
|
||||
if eval(expr, func.__globals__):
|
||||
code = code + space + "# doctest: +SKIP"
|
||||
except AttributeError:
|
||||
# Works as a class decorator
|
||||
if eval(expr, func.__init__.__globals__):
|
||||
code = code + space + "# doctest: +SKIP"
|
||||
|
||||
new_lines.append(code)
|
||||
func.__doc__ = "\n".join(new_lines)
|
||||
return func
|
||||
|
||||
|
||||
def roundtrip(image, plugin, suffix):
|
||||
"""Save and read an image using a specified plugin"""
|
||||
if '.' not in suffix:
|
||||
suffix = '.' + suffix
|
||||
temp_file = NamedTemporaryFile(suffix=suffix, delete=False)
|
||||
fname = temp_file.name
|
||||
temp_file.close()
|
||||
io.imsave(fname, image, plugin=plugin)
|
||||
new = io.imread(fname, plugin=plugin)
|
||||
try:
|
||||
os.remove(fname)
|
||||
except Exception:
|
||||
pass
|
||||
return new
|
||||
|
||||
|
||||
def color_check(plugin, fmt='png'):
|
||||
"""Check roundtrip behavior for color images.
|
||||
|
||||
All major input types should be handled as ubytes and read
|
||||
back correctly.
|
||||
"""
|
||||
img = img_as_ubyte(data.chelsea())
|
||||
r1 = roundtrip(img, plugin, fmt)
|
||||
testing.assert_allclose(img, r1)
|
||||
|
||||
img2 = img > 128
|
||||
r2 = roundtrip(img2, plugin, fmt)
|
||||
testing.assert_allclose(img2, r2.astype(bool))
|
||||
|
||||
img3 = img_as_float(img)
|
||||
r3 = roundtrip(img3, plugin, fmt)
|
||||
testing.assert_allclose(r3, img)
|
||||
|
||||
img4 = img_as_int(img)
|
||||
if fmt.lower() in (('tif', 'tiff')):
|
||||
img4 -= 100
|
||||
r4 = roundtrip(img4, plugin, fmt)
|
||||
testing.assert_allclose(r4, img4)
|
||||
else:
|
||||
r4 = roundtrip(img4, plugin, fmt)
|
||||
testing.assert_allclose(r4, img_as_ubyte(img4))
|
||||
|
||||
img5 = img_as_uint(img)
|
||||
r5 = roundtrip(img5, plugin, fmt)
|
||||
testing.assert_allclose(r5, img)
|
||||
|
||||
|
||||
def mono_check(plugin, fmt='png'):
|
||||
"""Check the roundtrip behavior for images that support most types.
|
||||
|
||||
All major input types should be handled.
|
||||
"""
|
||||
|
||||
img = img_as_ubyte(data.moon())
|
||||
r1 = roundtrip(img, plugin, fmt)
|
||||
testing.assert_allclose(img, r1)
|
||||
|
||||
img2 = img > 128
|
||||
r2 = roundtrip(img2, plugin, fmt)
|
||||
testing.assert_allclose(img2, r2.astype(bool))
|
||||
|
||||
img3 = img_as_float(img)
|
||||
r3 = roundtrip(img3, plugin, fmt)
|
||||
if r3.dtype.kind == 'f':
|
||||
testing.assert_allclose(img3, r3)
|
||||
else:
|
||||
testing.assert_allclose(r3, img_as_uint(img))
|
||||
|
||||
img4 = img_as_int(img)
|
||||
if fmt.lower() in (('tif', 'tiff')):
|
||||
img4 -= 100
|
||||
r4 = roundtrip(img4, plugin, fmt)
|
||||
testing.assert_allclose(r4, img4)
|
||||
else:
|
||||
r4 = roundtrip(img4, plugin, fmt)
|
||||
testing.assert_allclose(r4, img_as_uint(img4))
|
||||
|
||||
img5 = img_as_uint(img)
|
||||
r5 = roundtrip(img5, plugin, fmt)
|
||||
testing.assert_allclose(r5, img5)
|
||||
|
||||
|
||||
def setup_test():
|
||||
"""Default package level setup routine for skimage tests.
|
||||
|
||||
Import packages known to raise warnings, and then
|
||||
force warnings to raise errors.
|
||||
|
||||
Also set the random seed to zero.
|
||||
"""
|
||||
warnings.simplefilter('default')
|
||||
|
||||
from scipy import signal, ndimage, special, optimize, linalg
|
||||
from scipy.io import loadmat
|
||||
from skimage import viewer
|
||||
|
||||
np.random.seed(0)
|
||||
|
||||
warnings.simplefilter('error')
|
||||
|
||||
|
||||
def teardown_test():
|
||||
"""Default package level teardown routine for skimage tests.
|
||||
|
||||
Restore warnings to default behavior
|
||||
"""
|
||||
warnings.simplefilter('default')
|
||||
|
||||
|
||||
def fetch(data_filename):
|
||||
"""Attempt to fetch data, but if unavailable, skip the tests."""
|
||||
try:
|
||||
return data._fetch(data_filename)
|
||||
except (ConnectionError, ModuleNotFoundError):
|
||||
pytest.skip(f'Unable to download {data_filename}')
|
||||
|
||||
|
||||
def test_parallel(num_threads=2, warnings_matching=None):
|
||||
"""Decorator to run the same function multiple times in parallel.
|
||||
|
||||
This decorator is useful to ensure that separate threads execute
|
||||
concurrently and correctly while releasing the GIL.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
num_threads : int, optional
|
||||
The number of times the function is run in parallel.
|
||||
|
||||
warnings_matching: list or None
|
||||
This parameter is passed on to `expected_warnings` so as not to have
|
||||
race conditions with the warnings filters. A single
|
||||
`expected_warnings` context manager is used for all threads.
|
||||
If None, then no warnings are checked.
|
||||
|
||||
"""
|
||||
|
||||
assert num_threads > 0
|
||||
|
||||
def wrapper(func):
|
||||
@functools.wraps(func)
|
||||
def inner(*args, **kwargs):
|
||||
with expected_warnings(warnings_matching):
|
||||
threads = []
|
||||
for i in range(num_threads - 1):
|
||||
thread = threading.Thread(target=func, args=args,
|
||||
kwargs=kwargs)
|
||||
threads.append(thread)
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
result = func(*args, **kwargs)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
return result
|
||||
|
||||
return inner
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
color_check('pil')
|
||||
mono_check('pil')
|
||||
mono_check('pil', 'bmp')
|
||||
mono_check('pil', 'tiff')
|
9
venv/Lib/site-packages/skimage/_shared/tests/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from ..testing import setup_test, teardown_test
|
||||
|
||||
|
||||
def setup():
|
||||
setup_test()
|
||||
|
||||
|
||||
def teardown():
|
||||
teardown_test()
|
|
@ -0,0 +1,21 @@
|
|||
from ..fast_exp import fast_exp
|
||||
import numpy as np
|
||||
|
||||
|
||||
def test_fast_exp():
|
||||
|
||||
X = np.linspace(-5, 0, 5000, endpoint=True)
|
||||
|
||||
# Ground truth
|
||||
Y = np.exp(X)
|
||||
|
||||
# Approximation at double precision
|
||||
_y_f64 = np.array([fast_exp['float64_t'](x) for x in X])
|
||||
|
||||
# Approximation at single precision
|
||||
_y_f32 = np.array([fast_exp['float32_t'](x) for x in X.astype('float32')],
|
||||
dtype='float32')
|
||||
|
||||
for _y in [_y_f64, _y_f32]:
|
||||
|
||||
assert np.abs(Y - _y).mean() < 3e-3
|
|
@ -0,0 +1,75 @@
|
|||
from skimage._shared._geometry import polygon_clip, polygon_area
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_equal, assert_almost_equal
|
||||
|
||||
|
||||
hand = np.array(
|
||||
[[ 1.64516129, 1.16145833 ],
|
||||
[ 1.64516129, 1.59375 ],
|
||||
[ 1.35080645, 1.921875 ],
|
||||
[ 1.375 , 2.18229167 ],
|
||||
[ 1.68548387, 1.9375 ],
|
||||
[ 1.60887097, 2.55208333 ],
|
||||
[ 1.68548387, 2.69791667 ],
|
||||
[ 1.76209677, 2.56770833 ],
|
||||
[ 1.83064516, 1.97395833 ],
|
||||
[ 1.89516129, 2.75 ],
|
||||
[ 1.9516129 , 2.84895833 ],
|
||||
[ 2.01209677, 2.76041667 ],
|
||||
[ 1.99193548, 1.99479167 ],
|
||||
[ 2.11290323, 2.63020833 ],
|
||||
[ 2.2016129 , 2.734375 ],
|
||||
[ 2.25403226, 2.60416667 ],
|
||||
[ 2.14919355, 1.953125 ],
|
||||
[ 2.30645161, 2.36979167 ],
|
||||
[ 2.39112903, 2.36979167 ],
|
||||
[ 2.41532258, 2.1875 ],
|
||||
[ 2.1733871 , 1.703125 ],
|
||||
[ 2.07782258, 1.16666667 ]])
|
||||
|
||||
|
||||
def test_polygon_area():
|
||||
x = [0, 0, 1, 1]
|
||||
y = [0, 1, 1, 0]
|
||||
|
||||
assert_almost_equal(polygon_area(y, x), 1)
|
||||
|
||||
x = [0, 0, 1]
|
||||
y = [0, 1, 1]
|
||||
|
||||
assert_almost_equal(polygon_area(y, x), 0.5)
|
||||
|
||||
x = [0, 0, 0.5, 1, 1, 0.5]
|
||||
y = [0, 1, 0.5, 1, 0, 0.5]
|
||||
|
||||
assert_almost_equal(polygon_area(y, x), 0.5)
|
||||
|
||||
|
||||
def test_poly_clip():
|
||||
x = [0, 1, 2, 1]
|
||||
y = [0, -1, 0, 1]
|
||||
|
||||
yc, xc = polygon_clip(y, x, 0, 0, 1, 1)
|
||||
assert_equal(polygon_area(yc, xc), 0.5)
|
||||
|
||||
x = [-1, 1.5, 1.5, -1]
|
||||
y = [.5, 0.5, 1.5, 1.5]
|
||||
yc, xc = polygon_clip(y, x, 0, 0, 1, 1)
|
||||
assert_equal(polygon_area(yc, xc), 0.5)
|
||||
|
||||
|
||||
def test_hand_clip():
|
||||
(r0, c0, r1, c1) = (1.0, 1.5, 2.1, 2.5)
|
||||
clip_r, clip_c = polygon_clip(hand[:, 1], hand[:, 0], r0, c0, r1, c1)
|
||||
assert_equal(clip_r.size, 19)
|
||||
assert_equal(clip_r[0], clip_r[-1])
|
||||
assert_equal(clip_c[0], clip_c[-1])
|
||||
|
||||
(r0, c0, r1, c1) = (1.0, 1.5, 1.7, 2.5)
|
||||
clip_r, clip_c = polygon_clip(hand[:, 1], hand[:, 0], r0, c0, r1, c1)
|
||||
assert_equal(clip_r.size, 6)
|
||||
|
||||
(r0, c0, r1, c1) = (1.0, 1.5, 1.5, 2.5)
|
||||
clip_r, clip_c = polygon_clip(hand[:, 1], hand[:, 0], r0, c0, r1, c1)
|
||||
assert_equal(clip_r.size, 5)
|
|
@ -0,0 +1,27 @@
|
|||
from skimage._shared.interpolation import coord_map_py
|
||||
from skimage._shared.testing import assert_array_equal
|
||||
|
||||
def test_coord_map():
|
||||
symmetric = [coord_map_py(4, n, 'S') for n in range(-6, 6)]
|
||||
expected_symmetric = [2, 3, 3, 2, 1, 0, 0, 1, 2, 3, 3, 2]
|
||||
assert_array_equal(symmetric, expected_symmetric)
|
||||
|
||||
wrap = [coord_map_py(4, n, 'W') for n in range(-6, 6)]
|
||||
expected_wrap = [2, 3, 0, 1, 2, 3, 0, 1, 2, 3, 0, 1]
|
||||
assert_array_equal(wrap, expected_wrap)
|
||||
|
||||
edge = [coord_map_py(4, n, 'E') for n in range(-6, 6)]
|
||||
expected_edge = [0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3]
|
||||
assert_array_equal(edge, expected_edge)
|
||||
|
||||
reflect = [coord_map_py(4, n, 'R') for n in range(-6, 6)]
|
||||
expected_reflect = [0, 1, 2, 3, 2, 1, 0, 1, 2, 3, 2, 1]
|
||||
assert_array_equal(reflect, expected_reflect)
|
||||
|
||||
reflect = [coord_map_py(1, n, 'R') for n in range(-6, 6)]
|
||||
expected_reflect = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||
assert_array_equal(reflect, expected_reflect)
|
||||
|
||||
other = [coord_map_py(4, n, 'undefined') for n in range(-6, 6)]
|
||||
expected_other = list(range(-6, 6))
|
||||
assert_array_equal(other, expected_other)
|
|
@ -0,0 +1,42 @@
|
|||
import numpy as np
|
||||
from skimage._shared.utils import safe_as_int
|
||||
from skimage._shared import testing
|
||||
|
||||
|
||||
def test_int_cast_not_possible():
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(7.1)
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int([7.1, 0.9])
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(np.r_[7.1, 0.9])
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int((7.1, 0.9))
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(((3, 4, 1),
|
||||
(2, 7.6, 289)))
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(7.1, 0.09)
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int([7.1, 0.9], 0.09)
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(np.r_[7.1, 0.9], 0.09)
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int((7.1, 0.9), 0.09)
|
||||
with testing.raises(ValueError):
|
||||
safe_as_int(((3, 4, 1),
|
||||
(2, 7.6, 289)), 0.25)
|
||||
|
||||
|
||||
def test_int_cast_possible():
|
||||
testing.assert_equal(safe_as_int(7.1, atol=0.11), 7)
|
||||
testing.assert_equal(safe_as_int(-7.1, atol=0.11), -7)
|
||||
testing.assert_equal(safe_as_int(41.9, atol=0.11), 42)
|
||||
testing.assert_array_equal(safe_as_int([2, 42, 5789234.0, 87, 4]),
|
||||
np.r_[2, 42, 5789234, 87, 4])
|
||||
testing.assert_array_equal(safe_as_int(np.r_[[[3, 4, 1.000000001],
|
||||
[7, 2, -8.999999999],
|
||||
[6, 9, -4234918347.]]]),
|
||||
np.r_[[[3, 4, 1],
|
||||
[7, 2, -9],
|
||||
[6, 9, -4234918347]]])
|
129
venv/Lib/site-packages/skimage/_shared/tests/test_testing.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
""" Testing decorators module
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_equal
|
||||
from skimage._shared.testing import doctest_skip_parser, test_parallel
|
||||
from skimage._shared import testing
|
||||
import pytest
|
||||
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from warnings import warn
|
||||
|
||||
|
||||
def test_skipper():
|
||||
def f():
|
||||
pass
|
||||
|
||||
class c():
|
||||
|
||||
def __init__(self):
|
||||
self.me = "I think, therefore..."
|
||||
|
||||
docstring = \
|
||||
""" Header
|
||||
|
||||
>>> something # skip if not HAVE_AMODULE
|
||||
>>> something + else
|
||||
>>> a = 1 # skip if not HAVE_BMODULE
|
||||
>>> something2 # skip if HAVE_AMODULE
|
||||
"""
|
||||
f.__doc__ = docstring
|
||||
c.__doc__ = docstring
|
||||
|
||||
global HAVE_AMODULE, HAVE_BMODULE
|
||||
HAVE_AMODULE = False
|
||||
HAVE_BMODULE = True
|
||||
|
||||
f2 = doctest_skip_parser(f)
|
||||
c2 = doctest_skip_parser(c)
|
||||
assert f is f2
|
||||
assert c is c2
|
||||
|
||||
expected = \
|
||||
""" Header
|
||||
|
||||
>>> something # doctest: +SKIP
|
||||
>>> something + else
|
||||
>>> a = 1
|
||||
>>> something2
|
||||
"""
|
||||
assert_equal(f2.__doc__, expected)
|
||||
assert_equal(c2.__doc__, expected)
|
||||
|
||||
HAVE_AMODULE = True
|
||||
HAVE_BMODULE = False
|
||||
f.__doc__ = docstring
|
||||
c.__doc__ = docstring
|
||||
f2 = doctest_skip_parser(f)
|
||||
c2 = doctest_skip_parser(c)
|
||||
|
||||
assert f is f2
|
||||
expected = \
|
||||
""" Header
|
||||
|
||||
>>> something
|
||||
>>> something + else
|
||||
>>> a = 1 # doctest: +SKIP
|
||||
>>> something2 # doctest: +SKIP
|
||||
"""
|
||||
assert_equal(f2.__doc__, expected)
|
||||
assert_equal(c2.__doc__, expected)
|
||||
|
||||
del HAVE_AMODULE
|
||||
f.__doc__ = docstring
|
||||
c.__doc__ = docstring
|
||||
with testing.raises(NameError):
|
||||
doctest_skip_parser(f)
|
||||
with testing.raises(NameError):
|
||||
doctest_skip_parser(c)
|
||||
|
||||
|
||||
def test_test_parallel():
|
||||
state = []
|
||||
|
||||
@test_parallel()
|
||||
def change_state1():
|
||||
state.append(None)
|
||||
change_state1()
|
||||
assert len(state) == 2
|
||||
|
||||
@test_parallel(num_threads=1)
|
||||
def change_state2():
|
||||
state.append(None)
|
||||
change_state2()
|
||||
assert len(state) == 3
|
||||
|
||||
@test_parallel(num_threads=3)
|
||||
def change_state3():
|
||||
state.append(None)
|
||||
change_state3()
|
||||
assert len(state) == 6
|
||||
|
||||
|
||||
def test_parallel_warning():
|
||||
@test_parallel()
|
||||
def change_state_warns_fails():
|
||||
warn("Test warning for test parallel", stacklevel=2)
|
||||
|
||||
with expected_warnings(['Test warning for test parallel']):
|
||||
change_state_warns_fails()
|
||||
|
||||
@test_parallel(warnings_matching=['Test warning for test parallel'])
|
||||
def change_state_warns_passes():
|
||||
warn("Test warning for test parallel", stacklevel=2)
|
||||
|
||||
change_state_warns_passes()
|
||||
|
||||
|
||||
def test_expected_warnings_noop():
|
||||
# This will ensure the line beolow it behaves like a no-op
|
||||
with expected_warnings(['Expected warnings test']):
|
||||
|
||||
# This should behave as a no-op
|
||||
with expected_warnings(None):
|
||||
warn('Expected warnings test')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
np.testing.run_module_suite()
|
129
venv/Lib/site-packages/skimage/_shared/tests/test_utils.py
Normal file
|
@ -0,0 +1,129 @@
|
|||
import sys
|
||||
import pytest
|
||||
import numpy as np
|
||||
import numpy.testing as npt
|
||||
from skimage._shared.utils import (check_nD, deprecate_kwarg,
|
||||
_validate_interpolation_order,
|
||||
change_default_value)
|
||||
from skimage._shared import testing
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
|
||||
|
||||
def test_change_default_value():
|
||||
|
||||
@change_default_value('arg1', new_value=-1, changed_version='0.12')
|
||||
def foo(arg0, arg1=0, arg2=1):
|
||||
"""Expected docstring"""
|
||||
return arg0, arg1, arg2
|
||||
|
||||
@change_default_value('arg1', new_value=-1, changed_version='0.12',
|
||||
warning_msg="Custom warning message")
|
||||
def bar(arg0, arg1=0, arg2=1):
|
||||
"""Expected docstring"""
|
||||
return arg0, arg1, arg2
|
||||
|
||||
# Assert warning messages
|
||||
with pytest.warns(FutureWarning) as record:
|
||||
assert foo(0) == (0, 0, 1)
|
||||
assert bar(0) == (0, 0, 1)
|
||||
|
||||
expected_msg = ("The new recommended value for arg1 is -1. Until "
|
||||
"version 0.12, the default arg1 value is 0. From "
|
||||
"version 0.12, the arg1 default value will be -1. "
|
||||
"To avoid this warning, please explicitly set arg1 value.")
|
||||
|
||||
assert str(record[0].message) == expected_msg
|
||||
assert str(record[1].message) == "Custom warning message"
|
||||
|
||||
# Assert that nothing happens if arg1 is set
|
||||
with pytest.warns(None) as record:
|
||||
# No kwargs
|
||||
assert foo(0, 2) == (0, 2, 1)
|
||||
assert foo(0, arg1=0) == (0, 0, 1)
|
||||
|
||||
# Function name and doc is preserved
|
||||
assert foo.__name__ == 'foo'
|
||||
if sys.flags.optimize < 2:
|
||||
# if PYTHONOPTIMIZE is set to 2, docstrings are stripped
|
||||
assert foo.__doc__ == 'Expected docstring'
|
||||
|
||||
# Assert no warning was raised
|
||||
assert not record.list
|
||||
|
||||
|
||||
def test_deprecated_kwarg():
|
||||
|
||||
@deprecate_kwarg({'old_arg1': 'new_arg1'})
|
||||
def foo(arg0, new_arg1=1, arg2=None):
|
||||
"""Expected docstring"""
|
||||
return arg0, new_arg1, arg2
|
||||
|
||||
@deprecate_kwarg({'old_arg1': 'new_arg1'},
|
||||
warning_msg="Custom warning message")
|
||||
def bar(arg0, new_arg1=1, arg2=None):
|
||||
"""Expected docstring"""
|
||||
return arg0, new_arg1, arg2
|
||||
|
||||
# Assert that the DeprecationWarning is raised when the deprecated
|
||||
# argument name is used and that the reasult is valid
|
||||
with pytest.warns(FutureWarning) as record:
|
||||
assert foo(0, old_arg1=1) == (0, 1, None)
|
||||
assert bar(0, old_arg1=1) == (0, 1, None)
|
||||
|
||||
msg = ("'old_arg1' is a deprecated argument name "
|
||||
"for `foo`. Please use 'new_arg1' instead.")
|
||||
assert str(record[0].message) == msg
|
||||
assert str(record[1].message) == "Custom warning message"
|
||||
|
||||
# Assert that nothing happens when the function is called with the
|
||||
# new API
|
||||
with pytest.warns(None) as record:
|
||||
# No kwargs
|
||||
assert foo(0) == (0, 1, None)
|
||||
assert foo(0, 2) == (0, 2, None)
|
||||
assert foo(0, 1, 2) == (0, 1, 2)
|
||||
# Kwargs without deprecated argument
|
||||
assert foo(0, new_arg1=1, arg2=2) == (0, 1, 2)
|
||||
assert foo(0, new_arg1=2) == (0, 2, None)
|
||||
assert foo(0, arg2=2) == (0, 1, 2)
|
||||
assert foo(0, 1, arg2=2) == (0, 1, 2)
|
||||
# Function name and doc is preserved
|
||||
assert foo.__name__ == 'foo'
|
||||
if sys.flags.optimize < 2:
|
||||
# if PYTHONOPTIMIZE is set to 2, docstrings are stripped
|
||||
assert foo.__doc__ == 'Expected docstring'
|
||||
|
||||
# Assert no warning was raised
|
||||
assert not record.list
|
||||
|
||||
|
||||
def test_check_nD():
|
||||
z = np.random.random(200**2).reshape((200, 200))
|
||||
x = z[10:30, 30:10]
|
||||
with testing.raises(ValueError):
|
||||
check_nD(x, 2)
|
||||
|
||||
|
||||
@pytest.mark.parametrize('dtype', [bool, int, np.uint8, np.uint16,
|
||||
float, np.float32, np.float64])
|
||||
@pytest.mark.parametrize('order', [None, -1, 0, 1, 2, 3, 4, 5, 6])
|
||||
def test_validate_interpolation_order(dtype, order):
|
||||
if order is None:
|
||||
# Default order
|
||||
assert (_validate_interpolation_order(dtype, None) == 0
|
||||
if dtype == bool else 1)
|
||||
elif order < 0 or order > 5:
|
||||
# Order not in valid range
|
||||
with testing.raises(ValueError):
|
||||
_validate_interpolation_order(dtype, order)
|
||||
elif dtype == bool and order != 0:
|
||||
# Deprecated order for bool array
|
||||
with expected_warnings(["Input image dtype is bool"]):
|
||||
assert _validate_interpolation_order(bool, order) == order
|
||||
else:
|
||||
# Valid use case
|
||||
assert _validate_interpolation_order(dtype, order) == order
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
npt.run_module_suite()
|
|
@ -0,0 +1,41 @@
|
|||
"""Tests for the version requirement functions.
|
||||
|
||||
"""
|
||||
import numpy as np
|
||||
from numpy.testing import assert_equal
|
||||
from skimage._shared import version_requirements as version_req
|
||||
from skimage._shared import testing
|
||||
|
||||
|
||||
def test_get_module_version():
|
||||
assert version_req.get_module_version('numpy')
|
||||
assert version_req.get_module_version('scipy')
|
||||
with testing.raises(ImportError):
|
||||
version_req.get_module_version('fakenumpy')
|
||||
|
||||
|
||||
def test_is_installed():
|
||||
assert version_req.is_installed('python', '>=2.7')
|
||||
assert not version_req.is_installed('numpy', '<1.0')
|
||||
|
||||
|
||||
def test_require():
|
||||
# A function that only runs on Python >2.7 and numpy > 1.5 (should pass)
|
||||
@version_req.require('python', '>2.7')
|
||||
@version_req.require('numpy', '>1.5')
|
||||
def foo():
|
||||
return 1
|
||||
|
||||
assert_equal(foo(), 1)
|
||||
|
||||
# function that requires scipy < 0.1 (should fail)
|
||||
@version_req.require('scipy', '<0.1')
|
||||
def bar():
|
||||
return 0
|
||||
|
||||
with testing.raises(ImportError):
|
||||
bar()
|
||||
|
||||
|
||||
def test_get_module():
|
||||
assert version_req.get_module("numpy") is np
|
|
@ -0,0 +1,37 @@
|
|||
import os
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
import pytest
|
||||
|
||||
|
||||
@pytest.fixture(scope='function')
|
||||
def setup():
|
||||
# Remove any environment variable if it exists
|
||||
old_strictness = os.environ.pop('SKIMAGE_TEST_STRICT_WARNINGS', None)
|
||||
yield
|
||||
# Add the user's desired strictness
|
||||
if old_strictness is not None:
|
||||
os.environ['SKIMAGE_TEST_STRICT_WARNINGS'] = old_strictness
|
||||
|
||||
|
||||
def test_strict_warnigns_default(setup):
|
||||
# By default we should fail on missing expected warnings
|
||||
with pytest.raises(ValueError):
|
||||
with expected_warnings(['some warnings']):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize('strictness', ['1', 'true', 'True', 'TRUE'])
|
||||
def test_strict_warning_true(setup, strictness):
|
||||
os.environ['SKIMAGE_TEST_STRICT_WARNINGS'] = strictness
|
||||
with pytest.raises(ValueError):
|
||||
with expected_warnings(['some warnings']):
|
||||
pass
|
||||
|
||||
|
||||
@pytest.mark.parametrize('strictness', ['0', 'false', 'False', 'FALSE'])
|
||||
def test_strict_warning_false(setup, strictness):
|
||||
# If the user doesnn't wish to be strict about warnigns
|
||||
# the following shouldn't raise any error
|
||||
os.environ['SKIMAGE_TEST_STRICT_WARNINGS'] = strictness
|
||||
with expected_warnings(['some warnings']):
|
||||
pass
|
BIN
venv/Lib/site-packages/skimage/_shared/transform.cp36-win32.pyd
Normal file
375
venv/Lib/site-packages/skimage/_shared/utils.py
Normal file
|
@ -0,0 +1,375 @@
|
|||
import inspect
|
||||
import warnings
|
||||
import functools
|
||||
import sys
|
||||
import numpy as np
|
||||
import numbers
|
||||
|
||||
from ..util import img_as_float
|
||||
from ._warnings import all_warnings, warn
|
||||
|
||||
__all__ = ['deprecated', 'get_bound_method_class', 'all_warnings',
|
||||
'safe_as_int', 'check_nD', 'check_shape_equality', 'warn']
|
||||
|
||||
|
||||
class skimage_deprecation(Warning):
|
||||
"""Create our own deprecation class, since Python >= 2.7
|
||||
silences deprecations by default.
|
||||
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class change_default_value:
|
||||
"""Decorator for changing the default value of an argument.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg_name: str
|
||||
The name of the argument to be updated.
|
||||
new_value: any
|
||||
The argument new value.
|
||||
changed_version : str
|
||||
The package version in which the change will be introduced.
|
||||
warning_msg: str
|
||||
Optional warning message. If None, a generic warning message
|
||||
is used.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, arg_name, *, new_value, changed_version,
|
||||
warning_msg=None):
|
||||
self.arg_name = arg_name
|
||||
self.new_value = new_value
|
||||
self.warning_msg = warning_msg
|
||||
self.changed_version = changed_version
|
||||
|
||||
def __call__(self, func):
|
||||
parameters = inspect.signature(func).parameters
|
||||
arg_idx = list(parameters.keys()).index(self.arg_name)
|
||||
old_value = parameters[self.arg_name].default
|
||||
|
||||
if self.warning_msg is None:
|
||||
self.warning_msg = (
|
||||
f"The new recommended value for {self.arg_name} is "
|
||||
f"{self.new_value}. Until version {self.changed_version}, "
|
||||
f"the default {self.arg_name} value is {old_value}. "
|
||||
f"From version {self.changed_version}, the {self.arg_name} "
|
||||
f"default value will be {self.new_value}. To avoid "
|
||||
f"this warning, please explicitly set {self.arg_name} value.")
|
||||
|
||||
@functools.wraps(func)
|
||||
def fixed_func(*args, **kwargs):
|
||||
if len(args) < arg_idx + 1 and self.arg_name not in kwargs.keys():
|
||||
# warn that arg_name default value changed:
|
||||
warnings.warn(self.warning_msg, FutureWarning, stacklevel=2)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
return fixed_func
|
||||
|
||||
|
||||
class deprecate_kwarg:
|
||||
"""Decorator ensuring backward compatibility when argument names are
|
||||
modified in a function definition.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
arg_mapping: dict
|
||||
Mapping between the function's old argument names and the new
|
||||
ones.
|
||||
warning_msg: str
|
||||
Optional warning message. If None, a generic warning message
|
||||
is used.
|
||||
removed_version : str
|
||||
The package version in which the deprecated argument will be
|
||||
removed.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, kwarg_mapping, warning_msg=None, removed_version=None):
|
||||
self.kwarg_mapping = kwarg_mapping
|
||||
if warning_msg is None:
|
||||
self.warning_msg = ("'{old_arg}' is a deprecated argument name "
|
||||
"for `{func_name}`. ")
|
||||
if removed_version is not None:
|
||||
self.warning_msg += ("It will be removed in version {}. "
|
||||
.format(removed_version))
|
||||
self.warning_msg += "Please use '{new_arg}' instead."
|
||||
else:
|
||||
self.warning_msg = warning_msg
|
||||
|
||||
def __call__(self, func):
|
||||
@functools.wraps(func)
|
||||
def fixed_func(*args, **kwargs):
|
||||
for old_arg, new_arg in self.kwarg_mapping.items():
|
||||
if old_arg in kwargs:
|
||||
# warn that the function interface has changed:
|
||||
warnings.warn(self.warning_msg.format(
|
||||
old_arg=old_arg, func_name=func.__name__,
|
||||
new_arg=new_arg), FutureWarning, stacklevel=2)
|
||||
# Substitute new_arg to old_arg
|
||||
kwargs[new_arg] = kwargs.pop(old_arg)
|
||||
|
||||
# Call the function with the fixed arguments
|
||||
return func(*args, **kwargs)
|
||||
return fixed_func
|
||||
|
||||
|
||||
class deprecated(object):
|
||||
"""Decorator to mark deprecated functions with warning.
|
||||
|
||||
Adapted from <http://wiki.python.org/moin/PythonDecoratorLibrary>.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
alt_func : str
|
||||
If given, tell user what function to use instead.
|
||||
behavior : {'warn', 'raise'}
|
||||
Behavior during call to deprecated function: 'warn' = warn user that
|
||||
function is deprecated; 'raise' = raise error.
|
||||
removed_version : str
|
||||
The package version in which the deprecated function will be removed.
|
||||
"""
|
||||
|
||||
def __init__(self, alt_func=None, behavior='warn', removed_version=None):
|
||||
self.alt_func = alt_func
|
||||
self.behavior = behavior
|
||||
self.removed_version = removed_version
|
||||
|
||||
def __call__(self, func):
|
||||
|
||||
alt_msg = ''
|
||||
if self.alt_func is not None:
|
||||
alt_msg = ' Use ``%s`` instead.' % self.alt_func
|
||||
rmv_msg = ''
|
||||
if self.removed_version is not None:
|
||||
rmv_msg = (' and will be removed in version %s' %
|
||||
self.removed_version)
|
||||
|
||||
msg = ('Function ``%s`` is deprecated' % func.__name__ +
|
||||
rmv_msg + '.' + alt_msg)
|
||||
|
||||
@functools.wraps(func)
|
||||
def wrapped(*args, **kwargs):
|
||||
if self.behavior == 'warn':
|
||||
func_code = func.__code__
|
||||
warnings.simplefilter('always', skimage_deprecation)
|
||||
warnings.warn_explicit(msg,
|
||||
category=skimage_deprecation,
|
||||
filename=func_code.co_filename,
|
||||
lineno=func_code.co_firstlineno + 1)
|
||||
elif self.behavior == 'raise':
|
||||
raise skimage_deprecation(msg)
|
||||
return func(*args, **kwargs)
|
||||
|
||||
# modify doc string to display deprecation warning
|
||||
doc = '**Deprecated function**.' + alt_msg
|
||||
if wrapped.__doc__ is None:
|
||||
wrapped.__doc__ = doc
|
||||
else:
|
||||
wrapped.__doc__ = doc + '\n\n ' + wrapped.__doc__
|
||||
|
||||
return wrapped
|
||||
|
||||
|
||||
def get_bound_method_class(m):
|
||||
"""Return the class for a bound method.
|
||||
|
||||
"""
|
||||
return m.im_class if sys.version < '3' else m.__self__.__class__
|
||||
|
||||
|
||||
def safe_as_int(val, atol=1e-3):
|
||||
"""
|
||||
Attempt to safely cast values to integer format.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
val : scalar or iterable of scalars
|
||||
Number or container of numbers which are intended to be interpreted as
|
||||
integers, e.g., for indexing purposes, but which may not carry integer
|
||||
type.
|
||||
atol : float
|
||||
Absolute tolerance away from nearest integer to consider values in
|
||||
``val`` functionally integers.
|
||||
|
||||
Returns
|
||||
-------
|
||||
val_int : NumPy scalar or ndarray of dtype `np.int64`
|
||||
Returns the input value(s) coerced to dtype `np.int64` assuming all
|
||||
were within ``atol`` of the nearest integer.
|
||||
|
||||
Notes
|
||||
-----
|
||||
This operation calculates ``val`` modulo 1, which returns the mantissa of
|
||||
all values. Then all mantissas greater than 0.5 are subtracted from one.
|
||||
Finally, the absolute tolerance from zero is calculated. If it is less
|
||||
than ``atol`` for all value(s) in ``val``, they are rounded and returned
|
||||
in an integer array. Or, if ``val`` was a scalar, a NumPy scalar type is
|
||||
returned.
|
||||
|
||||
If any value(s) are outside the specified tolerance, an informative error
|
||||
is raised.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> safe_as_int(7.0)
|
||||
7
|
||||
|
||||
>>> safe_as_int([9, 4, 2.9999999999])
|
||||
array([9, 4, 3])
|
||||
|
||||
>>> safe_as_int(53.1)
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
ValueError: Integer argument required but received 53.1, check inputs.
|
||||
|
||||
>>> safe_as_int(53.01, atol=0.01)
|
||||
53
|
||||
|
||||
"""
|
||||
mod = np.asarray(val) % 1 # Extract mantissa
|
||||
|
||||
# Check for and subtract any mod values > 0.5 from 1
|
||||
if mod.ndim == 0: # Scalar input, cannot be indexed
|
||||
if mod > 0.5:
|
||||
mod = 1 - mod
|
||||
else: # Iterable input, now ndarray
|
||||
mod[mod > 0.5] = 1 - mod[mod > 0.5] # Test on each side of nearest int
|
||||
|
||||
try:
|
||||
np.testing.assert_allclose(mod, 0, atol=atol)
|
||||
except AssertionError:
|
||||
raise ValueError("Integer argument required but received "
|
||||
"{0}, check inputs.".format(val))
|
||||
|
||||
return np.round(val).astype(np.int64)
|
||||
|
||||
|
||||
def check_shape_equality(im1, im2):
|
||||
"""Raise an error if the shape do not match."""
|
||||
if not im1.shape == im2.shape:
|
||||
raise ValueError('Input images must have the same dimensions.')
|
||||
return
|
||||
|
||||
|
||||
def check_nD(array, ndim, arg_name='image'):
|
||||
"""
|
||||
Verify an array meets the desired ndims and array isn't empty.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
array : array-like
|
||||
Input array to be validated
|
||||
ndim : int or iterable of ints
|
||||
Allowable ndim or ndims for the array.
|
||||
arg_name : str, optional
|
||||
The name of the array in the original function.
|
||||
|
||||
"""
|
||||
array = np.asanyarray(array)
|
||||
msg_incorrect_dim = "The parameter `%s` must be a %s-dimensional array"
|
||||
msg_empty_array = "The parameter `%s` cannot be an empty array"
|
||||
if isinstance(ndim, int):
|
||||
ndim = [ndim]
|
||||
if array.size == 0:
|
||||
raise ValueError(msg_empty_array % (arg_name))
|
||||
if not array.ndim in ndim:
|
||||
raise ValueError(msg_incorrect_dim % (arg_name, '-or-'.join([str(n) for n in ndim])))
|
||||
|
||||
|
||||
def check_random_state(seed):
|
||||
"""Turn seed into a `np.random.RandomState` instance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
seed : None, int or np.random.RandomState
|
||||
If `seed` is None, return the RandomState singleton used by `np.random`.
|
||||
If `seed` is an int, return a new RandomState instance seeded with `seed`.
|
||||
If `seed` is already a RandomState instance, return it.
|
||||
|
||||
Raises
|
||||
------
|
||||
ValueError
|
||||
If `seed` is of the wrong type.
|
||||
|
||||
"""
|
||||
# Function originally from scikit-learn's module sklearn.utils.validation
|
||||
if seed is None or seed is np.random:
|
||||
return np.random.mtrand._rand
|
||||
if isinstance(seed, (numbers.Integral, np.integer)):
|
||||
return np.random.RandomState(seed)
|
||||
if isinstance(seed, np.random.RandomState):
|
||||
return seed
|
||||
raise ValueError('%r cannot be used to seed a numpy.random.RandomState'
|
||||
' instance' % seed)
|
||||
|
||||
|
||||
def convert_to_float(image, preserve_range):
|
||||
"""Convert input image to float image with the appropriate range.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
preserve_range : bool
|
||||
Determines if the range of the image should be kept or transformed
|
||||
using img_as_float. Also see
|
||||
https://scikit-image.org/docs/dev/user_guide/data_types.html
|
||||
|
||||
Notes:
|
||||
------
|
||||
* Input images with `float32` data type are not upcast.
|
||||
|
||||
Returns
|
||||
-------
|
||||
image : ndarray
|
||||
Transformed version of the input.
|
||||
|
||||
"""
|
||||
if preserve_range:
|
||||
# Convert image to double only if it is not single or double
|
||||
# precision float
|
||||
if image.dtype.char not in 'df':
|
||||
image = image.astype(float)
|
||||
else:
|
||||
image = img_as_float(image)
|
||||
return image
|
||||
|
||||
|
||||
def _validate_interpolation_order(image_dtype, order):
|
||||
"""Validate and return spline interpolation's order.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_dtype : dtype
|
||||
Image dtype.
|
||||
order : int, optional
|
||||
The order of the spline interpolation. The order has to be in
|
||||
the range 0-5. See `skimage.transform.warp` for detail.
|
||||
|
||||
Returns
|
||||
-------
|
||||
order : int
|
||||
if input order is None, returns 0 if image_dtype is bool and 1
|
||||
otherwise. Otherwise, image_dtype is checked and input order
|
||||
is validated accordingly (order > 0 is not supported for bool
|
||||
image dtype)
|
||||
|
||||
"""
|
||||
|
||||
if order is None:
|
||||
return 0 if image_dtype == bool else 1
|
||||
|
||||
if order < 0 or order > 5:
|
||||
raise ValueError("Spline interpolation order has to be in the "
|
||||
"range 0-5.")
|
||||
|
||||
if image_dtype == bool and order != 0:
|
||||
warn("Input image dtype is bool. Interpolation is not defined "
|
||||
"with bool data type. Please set order to 0 or explicitely "
|
||||
"cast input image to another data type. Starting from version "
|
||||
"0.19 a ValueError will be raised instead of this warning.",
|
||||
FutureWarning, stacklevel=2)
|
||||
|
||||
return order
|
180
venv/Lib/site-packages/skimage/_shared/version_requirements.py
Normal file
|
@ -0,0 +1,180 @@
|
|||
import sys
|
||||
|
||||
|
||||
def ensure_python_version(min_version):
|
||||
if not isinstance(min_version, tuple):
|
||||
min_version = (min_version, )
|
||||
if sys.version_info < min_version:
|
||||
# since ensure_python_version is in the critical import path,
|
||||
# we lazy import it.
|
||||
from platform import python_version
|
||||
|
||||
raise ImportError("""
|
||||
|
||||
You are running scikit-image on an unsupported version of Python.
|
||||
|
||||
Unfortunately, scikit-image 0.15 and above no longer work with your installed
|
||||
version of Python (%s). You therefore have two options: either upgrade to
|
||||
Python %s, or install an older version of scikit-image.
|
||||
|
||||
For Python 2.7 or Python 3.4, use
|
||||
|
||||
$ pip install 'scikit-image<0.15'
|
||||
|
||||
Please also consider updating `pip` and `setuptools`:
|
||||
|
||||
$ pip install pip setuptools --upgrade
|
||||
|
||||
Newer versions of these tools avoid installing packages incompatible
|
||||
with your version of Python.
|
||||
""" % (python_version(), '.'.join([str(v) for v in min_version])))
|
||||
|
||||
|
||||
def _check_version(actver, version, cmp_op):
|
||||
"""
|
||||
Check version string of an active module against a required version.
|
||||
|
||||
If dev/prerelease tags result in TypeError for string-number comparison,
|
||||
it is assumed that the dependency is satisfied.
|
||||
Users on dev branches are responsible for keeping their own packages up to
|
||||
date.
|
||||
|
||||
Copyright (C) 2013 The IPython Development Team
|
||||
|
||||
Distributed under the terms of the BSD License.
|
||||
"""
|
||||
# since version_requirements.py is in the critical import path, we
|
||||
# lazy import it
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
try:
|
||||
if cmp_op == '>':
|
||||
return LooseVersion(actver) > LooseVersion(version)
|
||||
elif cmp_op == '>=':
|
||||
return LooseVersion(actver) >= LooseVersion(version)
|
||||
elif cmp_op == '=':
|
||||
return LooseVersion(actver) == LooseVersion(version)
|
||||
elif cmp_op == '<':
|
||||
return LooseVersion(actver) < LooseVersion(version)
|
||||
else:
|
||||
return False
|
||||
except TypeError:
|
||||
return True
|
||||
|
||||
|
||||
def get_module_version(module_name):
|
||||
"""Return module version or None if version can't be retrieved."""
|
||||
mod = __import__(module_name,
|
||||
fromlist=[module_name.rpartition('.')[-1]])
|
||||
return getattr(mod, '__version__', getattr(mod, 'VERSION', None))
|
||||
|
||||
|
||||
def is_installed(name, version=None):
|
||||
"""Test if *name* is installed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of module or "python"
|
||||
version : str, optional
|
||||
Version string to test against.
|
||||
If version is not None, checking version
|
||||
(must have an attribute named '__version__' or 'VERSION')
|
||||
Version may start with =, >=, > or < to specify the exact requirement
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : bool
|
||||
True if `name` is installed matching the optional version.
|
||||
|
||||
Notes
|
||||
-----
|
||||
Original Copyright (C) 2009-2011 Pierre Raybaut
|
||||
Licensed under the terms of the MIT License.
|
||||
"""
|
||||
if name.lower() == 'python':
|
||||
actver = sys.version[:6]
|
||||
else:
|
||||
try:
|
||||
actver = get_module_version(name)
|
||||
except ImportError:
|
||||
return False
|
||||
if version is None:
|
||||
return True
|
||||
else:
|
||||
# since version_requirements is in the critical import path,
|
||||
# we lazy import re
|
||||
import re
|
||||
|
||||
match = re.search('[0-9]', version)
|
||||
assert match is not None, "Invalid version number"
|
||||
symb = version[:match.start()]
|
||||
if not symb:
|
||||
symb = '='
|
||||
assert symb in ('>=', '>', '=', '<'),\
|
||||
"Invalid version condition '%s'" % symb
|
||||
version = version[match.start():]
|
||||
return _check_version(actver, version, symb)
|
||||
|
||||
|
||||
def require(name, version=None):
|
||||
"""Return decorator that forces a requirement for a function or class.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
Name of module or "python".
|
||||
version : str, optional
|
||||
Version string to test against.
|
||||
If version is not None, checking version
|
||||
(must have an attribute named '__version__' or 'VERSION')
|
||||
Version may start with =, >=, > or < to specify the exact requirement
|
||||
|
||||
Returns
|
||||
-------
|
||||
func : function
|
||||
A decorator that raises an ImportError if a function is run
|
||||
in the absence of the input dependency.
|
||||
"""
|
||||
# since version_requirements is in the critical import path, we lazy import
|
||||
# functools
|
||||
import functools
|
||||
|
||||
def decorator(obj):
|
||||
@functools.wraps(obj)
|
||||
def func_wrapped(*args, **kwargs):
|
||||
if is_installed(name, version):
|
||||
return obj(*args, **kwargs)
|
||||
else:
|
||||
msg = '"%s" in "%s" requires "%s'
|
||||
msg = msg % (obj, obj.__module__, name)
|
||||
if not version is None:
|
||||
msg += " %s" % version
|
||||
raise ImportError(msg + '"')
|
||||
return func_wrapped
|
||||
return decorator
|
||||
|
||||
|
||||
def get_module(module_name, version=None):
|
||||
"""Return a module object of name *module_name* if installed.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
module_name : str
|
||||
Name of module.
|
||||
version : str, optional
|
||||
Version string to test against.
|
||||
If version is not None, checking version
|
||||
(must have an attribute named '__version__' or 'VERSION')
|
||||
Version may start with =, >=, > or < to specify the exact requirement
|
||||
|
||||
Returns
|
||||
-------
|
||||
mod : module or None
|
||||
Module if *module_name* is installed matching the optional version
|
||||
or None otherwise.
|
||||
"""
|
||||
if not is_installed(module_name, version):
|
||||
return None
|
||||
return __import__(module_name,
|
||||
fromlist=[module_name.rpartition('.')[-1]])
|
133
venv/Lib/site-packages/skimage/color/__init__.py
Normal file
|
@ -0,0 +1,133 @@
|
|||
from .colorconv import (convert_colorspace,
|
||||
guess_spatial_dimensions,
|
||||
rgba2rgb,
|
||||
rgb2hsv,
|
||||
hsv2rgb,
|
||||
rgb2xyz,
|
||||
xyz2rgb,
|
||||
rgb2rgbcie,
|
||||
rgbcie2rgb,
|
||||
rgb2grey,
|
||||
rgb2gray,
|
||||
gray2rgb,
|
||||
gray2rgba,
|
||||
grey2rgb,
|
||||
xyz2lab,
|
||||
lab2xyz,
|
||||
lab2rgb,
|
||||
rgb2lab,
|
||||
xyz2luv,
|
||||
luv2xyz,
|
||||
luv2rgb,
|
||||
rgb2luv,
|
||||
rgb2hed,
|
||||
hed2rgb,
|
||||
lab2lch,
|
||||
lch2lab,
|
||||
rgb2yuv,
|
||||
yuv2rgb,
|
||||
rgb2yiq,
|
||||
yiq2rgb,
|
||||
rgb2ypbpr,
|
||||
ypbpr2rgb,
|
||||
rgb2ycbcr,
|
||||
ycbcr2rgb,
|
||||
rgb2ydbdr,
|
||||
ydbdr2rgb,
|
||||
separate_stains,
|
||||
combine_stains,
|
||||
rgb_from_hed,
|
||||
hed_from_rgb,
|
||||
rgb_from_hdx,
|
||||
hdx_from_rgb,
|
||||
rgb_from_fgx,
|
||||
fgx_from_rgb,
|
||||
rgb_from_bex,
|
||||
bex_from_rgb,
|
||||
rgb_from_rbd,
|
||||
rbd_from_rgb,
|
||||
rgb_from_gdx,
|
||||
gdx_from_rgb,
|
||||
rgb_from_hax,
|
||||
hax_from_rgb,
|
||||
rgb_from_bro,
|
||||
bro_from_rgb,
|
||||
rgb_from_bpx,
|
||||
bpx_from_rgb,
|
||||
rgb_from_ahx,
|
||||
ahx_from_rgb,
|
||||
rgb_from_hpx,
|
||||
hpx_from_rgb)
|
||||
|
||||
from .colorlabel import color_dict, label2rgb
|
||||
|
||||
from .delta_e import (deltaE_cie76,
|
||||
deltaE_ciede94,
|
||||
deltaE_ciede2000,
|
||||
deltaE_cmc,
|
||||
)
|
||||
|
||||
|
||||
__all__ = ['convert_colorspace',
|
||||
'guess_spatial_dimensions',
|
||||
'rgba2rgb',
|
||||
'rgb2hsv',
|
||||
'hsv2rgb',
|
||||
'rgb2xyz',
|
||||
'xyz2rgb',
|
||||
'rgb2rgbcie',
|
||||
'rgbcie2rgb',
|
||||
'rgb2grey',
|
||||
'rgb2gray',
|
||||
'gray2rgb',
|
||||
'gray2rgba',
|
||||
'grey2rgb',
|
||||
'xyz2lab',
|
||||
'lab2xyz',
|
||||
'lab2rgb',
|
||||
'rgb2lab',
|
||||
'rgb2hed',
|
||||
'hed2rgb',
|
||||
'lab2lch',
|
||||
'lch2lab',
|
||||
'rgb2yuv',
|
||||
'yuv2rgb',
|
||||
'rgb2yiq',
|
||||
'yiq2rgb',
|
||||
'rgb2ypbpr',
|
||||
'ypbpr2rgb',
|
||||
'rgb2ycbcr',
|
||||
'ycbcr2rgb',
|
||||
'rgb2ydbdr',
|
||||
'ydbdr2rgb',
|
||||
'separate_stains',
|
||||
'combine_stains',
|
||||
'rgb_from_hed',
|
||||
'hed_from_rgb',
|
||||
'rgb_from_hdx',
|
||||
'hdx_from_rgb',
|
||||
'rgb_from_fgx',
|
||||
'fgx_from_rgb',
|
||||
'rgb_from_bex',
|
||||
'bex_from_rgb',
|
||||
'rgb_from_rbd',
|
||||
'rbd_from_rgb',
|
||||
'rgb_from_gdx',
|
||||
'gdx_from_rgb',
|
||||
'rgb_from_hax',
|
||||
'hax_from_rgb',
|
||||
'rgb_from_bro',
|
||||
'bro_from_rgb',
|
||||
'rgb_from_bpx',
|
||||
'bpx_from_rgb',
|
||||
'rgb_from_ahx',
|
||||
'ahx_from_rgb',
|
||||
'rgb_from_hpx',
|
||||
'hpx_from_rgb',
|
||||
'color_dict',
|
||||
'label2rgb',
|
||||
'deltaE_cie76',
|
||||
'deltaE_ciede94',
|
||||
'deltaE_ciede2000',
|
||||
'deltaE_cmc',
|
||||
]
|
79
venv/Lib/site-packages/skimage/color/adapt_rgb.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import functools
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .. import color
|
||||
from ..util.dtype import _convert
|
||||
|
||||
|
||||
__all__ = ['adapt_rgb', 'hsv_value', 'each_channel']
|
||||
|
||||
|
||||
def is_rgb_like(image):
|
||||
"""Return True if the image *looks* like it's RGB.
|
||||
|
||||
This function should not be public because it is only intended to be used
|
||||
for functions that don't accept volumes as input, since checking an image's
|
||||
shape is fragile.
|
||||
"""
|
||||
return (image.ndim == 3) and (image.shape[2] in (3, 4))
|
||||
|
||||
|
||||
def adapt_rgb(apply_to_rgb):
|
||||
"""Return decorator that adapts to RGB images to a gray-scale filter.
|
||||
|
||||
This function is only intended to be used for functions that don't accept
|
||||
volumes as input, since checking an image's shape is fragile.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
apply_to_rgb : function
|
||||
Function that returns a filtered image from an image-filter and RGB
|
||||
image. This will only be called if the image is RGB-like.
|
||||
"""
|
||||
def decorator(image_filter):
|
||||
@functools.wraps(image_filter)
|
||||
def image_filter_adapted(image, *args, **kwargs):
|
||||
if is_rgb_like(image):
|
||||
return apply_to_rgb(image_filter, image, *args, **kwargs)
|
||||
else:
|
||||
return image_filter(image, *args, **kwargs)
|
||||
return image_filter_adapted
|
||||
return decorator
|
||||
|
||||
|
||||
def hsv_value(image_filter, image, *args, **kwargs):
|
||||
"""Return color image by applying `image_filter` on HSV-value of `image`.
|
||||
|
||||
Note that this function is intended for use with `adapt_rgb`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_filter : function
|
||||
Function that filters a gray-scale image.
|
||||
image : array
|
||||
Input image. Note that RGBA images are treated as RGB.
|
||||
"""
|
||||
# Slice the first three channels so that we remove any alpha channels.
|
||||
hsv = color.rgb2hsv(image[:, :, :3])
|
||||
value = hsv[:, :, 2].copy()
|
||||
value = image_filter(value, *args, **kwargs)
|
||||
hsv[:, :, 2] = _convert(value, hsv.dtype)
|
||||
return color.hsv2rgb(hsv)
|
||||
|
||||
|
||||
def each_channel(image_filter, image, *args, **kwargs):
|
||||
"""Return color image by applying `image_filter` on channels of `image`.
|
||||
|
||||
Note that this function is intended for use with `adapt_rgb`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image_filter : function
|
||||
Function that filters a gray-scale image.
|
||||
image : array
|
||||
Input image.
|
||||
"""
|
||||
c_new = [image_filter(c, *args, **kwargs)
|
||||
for c in np.moveaxis(image, -1, 0)]
|
||||
return np.moveaxis(np.array(c_new), 0, -1)
|
1900
venv/Lib/site-packages/skimage/color/colorconv.py
Normal file
237
venv/Lib/site-packages/skimage/color/colorlabel.py
Normal file
|
@ -0,0 +1,237 @@
|
|||
import itertools
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .._shared.utils import warn, change_default_value
|
||||
from ..util import img_as_float
|
||||
from . import rgb_colors
|
||||
from .colorconv import rgb2gray, gray2rgb
|
||||
|
||||
|
||||
__all__ = ['color_dict', 'label2rgb', 'DEFAULT_COLORS']
|
||||
|
||||
|
||||
DEFAULT_COLORS = ('red', 'blue', 'yellow', 'magenta', 'green',
|
||||
'indigo', 'darkorange', 'cyan', 'pink', 'yellowgreen')
|
||||
|
||||
|
||||
color_dict = {k: v for k, v in rgb_colors.__dict__.items()
|
||||
if isinstance(v, tuple)}
|
||||
|
||||
|
||||
def _rgb_vector(color):
|
||||
"""Return RGB color as (1, 3) array.
|
||||
|
||||
This RGB array gets multiplied by masked regions of an RGB image, which are
|
||||
partially flattened by masking (i.e. dimensions 2D + RGB -> 1D + RGB).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
color : str or array
|
||||
Color name in `color_dict` or RGB float values between [0, 1].
|
||||
"""
|
||||
if isinstance(color, str):
|
||||
color = color_dict[color]
|
||||
# Slice to handle RGBA colors.
|
||||
return np.array(color[:3])
|
||||
|
||||
|
||||
def _match_label_with_color(label, colors, bg_label, bg_color):
|
||||
"""Return `unique_labels` and `color_cycle` for label array and color list.
|
||||
|
||||
Colors are cycled for normal labels, but the background color should only
|
||||
be used for the background.
|
||||
"""
|
||||
# Temporarily set background color; it will be removed later.
|
||||
if bg_color is None:
|
||||
bg_color = (0, 0, 0)
|
||||
bg_color = _rgb_vector([bg_color])
|
||||
|
||||
# map labels to their ranks among all labels from small to large
|
||||
unique_labels, mapped_labels = np.unique(label, return_inverse=True)
|
||||
|
||||
# get rank of bg_label
|
||||
bg_label_rank_list = mapped_labels[label.flat == bg_label]
|
||||
|
||||
# The rank of each label is the index of the color it is matched to in
|
||||
# color cycle. bg_label should always be mapped to the first color, so
|
||||
# its rank must be 0. Other labels should be ranked from small to large
|
||||
# from 1.
|
||||
if len(bg_label_rank_list) > 0:
|
||||
bg_label_rank = bg_label_rank_list[0]
|
||||
mapped_labels[mapped_labels < bg_label_rank] += 1
|
||||
mapped_labels[label.flat == bg_label] = 0
|
||||
else:
|
||||
mapped_labels += 1
|
||||
|
||||
# Modify labels and color cycle so background color is used only once.
|
||||
color_cycle = itertools.cycle(colors)
|
||||
color_cycle = itertools.chain(bg_color, color_cycle)
|
||||
|
||||
return mapped_labels, color_cycle
|
||||
|
||||
|
||||
@change_default_value("bg_label", new_value=0, changed_version="0.19")
|
||||
def label2rgb(label, image=None, colors=None, alpha=0.3,
|
||||
bg_label=-1, bg_color=(0, 0, 0), image_alpha=1, kind='overlay'):
|
||||
"""Return an RGB image where color-coded labels are painted over the image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
label : array, shape (M, N)
|
||||
Integer array of labels with the same shape as `image`.
|
||||
image : array, shape (M, N, 3), optional
|
||||
Image used as underlay for labels. If the input is an RGB image, it's
|
||||
converted to grayscale before coloring.
|
||||
colors : list, optional
|
||||
List of colors. If the number of labels exceeds the number of colors,
|
||||
then the colors are cycled.
|
||||
alpha : float [0, 1], optional
|
||||
Opacity of colorized labels. Ignored if image is `None`.
|
||||
bg_label : int, optional
|
||||
Label that's treated as the background. If `bg_label` is specified,
|
||||
`bg_color` is `None`, and `kind` is `overlay`,
|
||||
background is not painted by any colors.
|
||||
bg_color : str or array, optional
|
||||
Background color. Must be a name in `color_dict` or RGB float values
|
||||
between [0, 1].
|
||||
image_alpha : float [0, 1], optional
|
||||
Opacity of the image.
|
||||
kind : string, one of {'overlay', 'avg'}
|
||||
The kind of color image desired. 'overlay' cycles over defined colors
|
||||
and overlays the colored labels over the original image. 'avg' replaces
|
||||
each labeled segment with its average color, for a stained-class or
|
||||
pastel painting appearance.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : array of float, shape (M, N, 3)
|
||||
The result of blending a cycling colormap (`colors`) for each distinct
|
||||
value in `label` with the image, at a certain alpha value.
|
||||
"""
|
||||
if kind == 'overlay':
|
||||
return _label2rgb_overlay(label, image, colors, alpha, bg_label,
|
||||
bg_color, image_alpha)
|
||||
elif kind == 'avg':
|
||||
return _label2rgb_avg(label, image, bg_label, bg_color)
|
||||
else:
|
||||
raise ValueError("`kind` must be either 'overlay' or 'avg'.")
|
||||
|
||||
|
||||
def _label2rgb_overlay(label, image=None, colors=None, alpha=0.3,
|
||||
bg_label=-1, bg_color=None, image_alpha=1):
|
||||
"""Return an RGB image where color-coded labels are painted over the image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
label : array, shape (M, N)
|
||||
Integer array of labels with the same shape as `image`.
|
||||
image : array, shape (M, N, 3), optional
|
||||
Image used as underlay for labels. If the input is an RGB image, it's
|
||||
converted to grayscale before coloring.
|
||||
colors : list, optional
|
||||
List of colors. If the number of labels exceeds the number of colors,
|
||||
then the colors are cycled.
|
||||
alpha : float [0, 1], optional
|
||||
Opacity of colorized labels. Ignored if image is `None`.
|
||||
bg_label : int, optional
|
||||
Label that's treated as the background. If `bg_label` is specified and
|
||||
`bg_color` is `None`, background is not painted by any colors.
|
||||
bg_color : str or array, optional
|
||||
Background color. Must be a name in `color_dict` or RGB float values
|
||||
between [0, 1].
|
||||
image_alpha : float [0, 1], optional
|
||||
Opacity of the image.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : array of float, shape (M, N, 3)
|
||||
The result of blending a cycling colormap (`colors`) for each distinct
|
||||
value in `label` with the image, at a certain alpha value.
|
||||
"""
|
||||
if colors is None:
|
||||
colors = DEFAULT_COLORS
|
||||
colors = [_rgb_vector(c) for c in colors]
|
||||
|
||||
if image is None:
|
||||
image = np.zeros(label.shape + (3,), dtype=np.float64)
|
||||
# Opacity doesn't make sense if no image exists.
|
||||
alpha = 1
|
||||
else:
|
||||
if not image.shape[:2] == label.shape:
|
||||
raise ValueError("`image` and `label` must be the same shape")
|
||||
|
||||
if image.min() < 0:
|
||||
warn("Negative intensities in `image` are not supported")
|
||||
|
||||
if image.ndim > label.ndim:
|
||||
image = img_as_float(rgb2gray(image))
|
||||
else:
|
||||
image = img_as_float(image)
|
||||
image = gray2rgb(image) * image_alpha + (1 - image_alpha)
|
||||
|
||||
# Ensure that all labels are non-negative so we can index into
|
||||
# `label_to_color` correctly.
|
||||
offset = min(label.min(), bg_label)
|
||||
if offset != 0:
|
||||
label = label - offset # Make sure you don't modify the input array.
|
||||
bg_label -= offset
|
||||
|
||||
new_type = np.min_scalar_type(int(label.max()))
|
||||
if new_type == np.bool:
|
||||
new_type = np.uint8
|
||||
label = label.astype(new_type)
|
||||
|
||||
mapped_labels_flat, color_cycle = _match_label_with_color(label, colors,
|
||||
bg_label, bg_color)
|
||||
|
||||
if len(mapped_labels_flat) == 0:
|
||||
return image
|
||||
|
||||
dense_labels = range(max(mapped_labels_flat) + 1)
|
||||
|
||||
label_to_color = np.array([c for i, c in zip(dense_labels, color_cycle)])
|
||||
|
||||
mapped_labels = label
|
||||
mapped_labels.flat = mapped_labels_flat
|
||||
result = label_to_color[mapped_labels] * alpha + image * (1 - alpha)
|
||||
|
||||
# Remove background label if its color was not specified.
|
||||
remove_background = 0 in mapped_labels_flat and bg_color is None
|
||||
if remove_background:
|
||||
result[label == bg_label] = image[label == bg_label]
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def _label2rgb_avg(label_field, image, bg_label=0, bg_color=(0, 0, 0)):
|
||||
"""Visualise each segment in `label_field` with its mean color in `image`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
label_field : array of int
|
||||
A segmentation of an image.
|
||||
image : array, shape ``label_field.shape + (3,)``
|
||||
A color image of the same spatial shape as `label_field`.
|
||||
bg_label : int, optional
|
||||
A value in `label_field` to be treated as background.
|
||||
bg_color : 3-tuple of int, optional
|
||||
The color for the background label
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : array, same shape and type as `image`
|
||||
The output visualization.
|
||||
"""
|
||||
out = np.zeros_like(image)
|
||||
labels = np.unique(label_field)
|
||||
bg = (labels == bg_label)
|
||||
if bg.any():
|
||||
labels = labels[labels != bg_label]
|
||||
mask = (label_field == bg_label).nonzero()
|
||||
out[mask] = bg_color
|
||||
for label in labels:
|
||||
mask = (label_field == label).nonzero()
|
||||
color = image[mask].mean(axis=0)
|
||||
out[mask] = color
|
||||
return out
|
340
venv/Lib/site-packages/skimage/color/delta_e.py
Normal file
|
@ -0,0 +1,340 @@
|
|||
"""
|
||||
Functions for calculating the "distance" between colors.
|
||||
|
||||
Implicit in these definitions of "distance" is the notion of "Just Noticeable
|
||||
Distance" (JND). This represents the distance between colors where a human can
|
||||
perceive different colors. Humans are more sensitive to certain colors than
|
||||
others, which different deltaE metrics correct for with varying degrees of
|
||||
sophistication.
|
||||
|
||||
The literature often mentions 1 as the minimum distance for visual
|
||||
differentiation, but more recent studies (Mahy 1994) peg JND at 2.3
|
||||
|
||||
The delta-E notation comes from the German word for "Sensation" (Empfindung).
|
||||
|
||||
Reference
|
||||
---------
|
||||
https://en.wikipedia.org/wiki/Color_difference
|
||||
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
|
||||
from .colorconv import lab2lch, _cart2polar_2pi
|
||||
|
||||
|
||||
def deltaE_cie76(lab1, lab2):
|
||||
"""Euclidean distance between two points in Lab color space
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab1 : array_like
|
||||
reference color (Lab colorspace)
|
||||
lab2 : array_like
|
||||
comparison color (Lab colorspace)
|
||||
|
||||
Returns
|
||||
-------
|
||||
dE : array_like
|
||||
distance between colors `lab1` and `lab2`
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://en.wikipedia.org/wiki/Color_difference
|
||||
.. [2] A. R. Robertson, "The CIE 1976 color-difference formulae,"
|
||||
Color Res. Appl. 2, 7-11 (1977).
|
||||
"""
|
||||
lab1 = np.asarray(lab1)
|
||||
lab2 = np.asarray(lab2)
|
||||
L1, a1, b1 = np.rollaxis(lab1, -1)[:3]
|
||||
L2, a2, b2 = np.rollaxis(lab2, -1)[:3]
|
||||
return np.sqrt((L2 - L1) ** 2 + (a2 - a1) ** 2 + (b2 - b1) ** 2)
|
||||
|
||||
|
||||
def deltaE_ciede94(lab1, lab2, kH=1, kC=1, kL=1, k1=0.045, k2=0.015):
|
||||
"""Color difference according to CIEDE 94 standard
|
||||
|
||||
Accommodates perceptual non-uniformities through the use of application
|
||||
specific scale factors (`kH`, `kC`, `kL`, `k1`, and `k2`).
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab1 : array_like
|
||||
reference color (Lab colorspace)
|
||||
lab2 : array_like
|
||||
comparison color (Lab colorspace)
|
||||
kH : float, optional
|
||||
Hue scale
|
||||
kC : float, optional
|
||||
Chroma scale
|
||||
kL : float, optional
|
||||
Lightness scale
|
||||
k1 : float, optional
|
||||
first scale parameter
|
||||
k2 : float, optional
|
||||
second scale parameter
|
||||
|
||||
Returns
|
||||
-------
|
||||
dE : array_like
|
||||
color difference between `lab1` and `lab2`
|
||||
|
||||
Notes
|
||||
-----
|
||||
deltaE_ciede94 is not symmetric with respect to lab1 and lab2. CIEDE94
|
||||
defines the scales for the lightness, hue, and chroma in terms of the first
|
||||
color. Consequently, the first color should be regarded as the "reference"
|
||||
color.
|
||||
|
||||
`kL`, `k1`, `k2` depend on the application and default to the values
|
||||
suggested for graphic arts
|
||||
|
||||
========== ============== ==========
|
||||
Parameter Graphic Arts Textiles
|
||||
========== ============== ==========
|
||||
`kL` 1.000 2.000
|
||||
`k1` 0.045 0.048
|
||||
`k2` 0.015 0.014
|
||||
========== ============== ==========
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://en.wikipedia.org/wiki/Color_difference
|
||||
.. [2] http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE94.html
|
||||
"""
|
||||
L1, C1 = np.rollaxis(lab2lch(lab1), -1)[:2]
|
||||
L2, C2 = np.rollaxis(lab2lch(lab2), -1)[:2]
|
||||
|
||||
dL = L1 - L2
|
||||
dC = C1 - C2
|
||||
dH2 = get_dH2(lab1, lab2)
|
||||
|
||||
SL = 1
|
||||
SC = 1 + k1 * C1
|
||||
SH = 1 + k2 * C1
|
||||
|
||||
dE2 = (dL / (kL * SL)) ** 2
|
||||
dE2 += (dC / (kC * SC)) ** 2
|
||||
dE2 += dH2 / (kH * SH) ** 2
|
||||
return np.sqrt(np.maximum(dE2, 0))
|
||||
|
||||
|
||||
def deltaE_ciede2000(lab1, lab2, kL=1, kC=1, kH=1):
|
||||
"""Color difference as given by the CIEDE 2000 standard.
|
||||
|
||||
CIEDE 2000 is a major revision of CIDE94. The perceptual calibration is
|
||||
largely based on experience with automotive paint on smooth surfaces.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab1 : array_like
|
||||
reference color (Lab colorspace)
|
||||
lab2 : array_like
|
||||
comparison color (Lab colorspace)
|
||||
kL : float (range), optional
|
||||
lightness scale factor, 1 for "acceptably close"; 2 for "imperceptible"
|
||||
see deltaE_cmc
|
||||
kC : float (range), optional
|
||||
chroma scale factor, usually 1
|
||||
kH : float (range), optional
|
||||
hue scale factor, usually 1
|
||||
|
||||
Returns
|
||||
-------
|
||||
deltaE : array_like
|
||||
The distance between `lab1` and `lab2`
|
||||
|
||||
Notes
|
||||
-----
|
||||
CIEDE 2000 assumes parametric weighting factors for the lightness, chroma,
|
||||
and hue (`kL`, `kC`, `kH` respectively). These default to 1.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://en.wikipedia.org/wiki/Color_difference
|
||||
.. [2] http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf
|
||||
:DOI:`10.1364/AO.33.008069`
|
||||
.. [3] M. Melgosa, J. Quesada, and E. Hita, "Uniformity of some recent
|
||||
color metrics tested with an accurate color-difference tolerance
|
||||
dataset," Appl. Opt. 33, 8069-8077 (1994).
|
||||
"""
|
||||
lab1 = np.asarray(lab1)
|
||||
lab2 = np.asarray(lab2)
|
||||
unroll = False
|
||||
if lab1.ndim == 1 and lab2.ndim == 1:
|
||||
unroll = True
|
||||
if lab1.ndim == 1:
|
||||
lab1 = lab1[None, :]
|
||||
if lab2.ndim == 1:
|
||||
lab2 = lab2[None, :]
|
||||
L1, a1, b1 = np.rollaxis(lab1, -1)[:3]
|
||||
L2, a2, b2 = np.rollaxis(lab2, -1)[:3]
|
||||
|
||||
# distort `a` based on average chroma
|
||||
# then convert to lch coordines from distorted `a`
|
||||
# all subsequence calculations are in the new coordiantes
|
||||
# (often denoted "prime" in the literature)
|
||||
Cbar = 0.5 * (np.hypot(a1, b1) + np.hypot(a2, b2))
|
||||
c7 = Cbar ** 7
|
||||
G = 0.5 * (1 - np.sqrt(c7 / (c7 + 25 ** 7)))
|
||||
scale = 1 + G
|
||||
C1, h1 = _cart2polar_2pi(a1 * scale, b1)
|
||||
C2, h2 = _cart2polar_2pi(a2 * scale, b2)
|
||||
# recall that c, h are polar coordiantes. c==r, h==theta
|
||||
|
||||
# cide2000 has four terms to delta_e:
|
||||
# 1) Luminance term
|
||||
# 2) Hue term
|
||||
# 3) Chroma term
|
||||
# 4) hue Rotation term
|
||||
|
||||
# lightness term
|
||||
Lbar = 0.5 * (L1 + L2)
|
||||
tmp = (Lbar - 50) ** 2
|
||||
SL = 1 + 0.015 * tmp / np.sqrt(20 + tmp)
|
||||
L_term = (L2 - L1) / (kL * SL)
|
||||
|
||||
# chroma term
|
||||
Cbar = 0.5 * (C1 + C2) # new coordiantes
|
||||
SC = 1 + 0.045 * Cbar
|
||||
C_term = (C2 - C1) / (kC * SC)
|
||||
|
||||
# hue term
|
||||
h_diff = h2 - h1
|
||||
h_sum = h1 + h2
|
||||
CC = C1 * C2
|
||||
|
||||
dH = h_diff.copy()
|
||||
dH[h_diff > np.pi] -= 2 * np.pi
|
||||
dH[h_diff < -np.pi] += 2 * np.pi
|
||||
dH[CC == 0.] = 0. # if r == 0, dtheta == 0
|
||||
dH_term = 2 * np.sqrt(CC) * np.sin(dH / 2)
|
||||
|
||||
Hbar = h_sum.copy()
|
||||
mask = np.logical_and(CC != 0., np.abs(h_diff) > np.pi)
|
||||
Hbar[mask * (h_sum < 2 * np.pi)] += 2 * np.pi
|
||||
Hbar[mask * (h_sum >= 2 * np.pi)] -= 2 * np.pi
|
||||
Hbar[CC == 0.] *= 2
|
||||
Hbar *= 0.5
|
||||
|
||||
T = (1 -
|
||||
0.17 * np.cos(Hbar - np.deg2rad(30)) +
|
||||
0.24 * np.cos(2 * Hbar) +
|
||||
0.32 * np.cos(3 * Hbar + np.deg2rad(6)) -
|
||||
0.20 * np.cos(4 * Hbar - np.deg2rad(63))
|
||||
)
|
||||
SH = 1 + 0.015 * Cbar * T
|
||||
|
||||
H_term = dH_term / (kH * SH)
|
||||
|
||||
# hue rotation
|
||||
c7 = Cbar ** 7
|
||||
Rc = 2 * np.sqrt(c7 / (c7 + 25 ** 7))
|
||||
dtheta = np.deg2rad(30) * np.exp(-((np.rad2deg(Hbar) - 275) / 25) ** 2)
|
||||
R_term = -np.sin(2 * dtheta) * Rc * C_term * H_term
|
||||
|
||||
# put it all together
|
||||
dE2 = L_term ** 2
|
||||
dE2 += C_term ** 2
|
||||
dE2 += H_term ** 2
|
||||
dE2 += R_term
|
||||
ans = np.sqrt(np.maximum(dE2, 0))
|
||||
if unroll:
|
||||
ans = ans[0]
|
||||
return ans
|
||||
|
||||
|
||||
def deltaE_cmc(lab1, lab2, kL=1, kC=1):
|
||||
"""Color difference from the CMC l:c standard.
|
||||
|
||||
This color difference was developed by the Colour Measurement Committee
|
||||
(CMC) of the Society of Dyers and Colourists (United Kingdom). It is
|
||||
intended for use in the textile industry.
|
||||
|
||||
The scale factors `kL`, `kC` set the weight given to differences in
|
||||
lightness and chroma relative to differences in hue. The usual values are
|
||||
``kL=2``, ``kC=1`` for "acceptability" and ``kL=1``, ``kC=1`` for
|
||||
"imperceptibility". Colors with ``dE > 1`` are "different" for the given
|
||||
scale factors.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
lab1 : array_like
|
||||
reference color (Lab colorspace)
|
||||
lab2 : array_like
|
||||
comparison color (Lab colorspace)
|
||||
|
||||
Returns
|
||||
-------
|
||||
dE : array_like
|
||||
distance between colors `lab1` and `lab2`
|
||||
|
||||
Notes
|
||||
-----
|
||||
deltaE_cmc the defines the scales for the lightness, hue, and chroma
|
||||
in terms of the first color. Consequently
|
||||
``deltaE_cmc(lab1, lab2) != deltaE_cmc(lab2, lab1)``
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] https://en.wikipedia.org/wiki/Color_difference
|
||||
.. [2] http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE94.html
|
||||
.. [3] F. J. J. Clarke, R. McDonald, and B. Rigg, "Modification to the
|
||||
JPC79 colour-difference formula," J. Soc. Dyers Colour. 100, 128-132
|
||||
(1984).
|
||||
"""
|
||||
L1, C1, h1 = np.rollaxis(lab2lch(lab1), -1)[:3]
|
||||
L2, C2, h2 = np.rollaxis(lab2lch(lab2), -1)[:3]
|
||||
|
||||
dC = C1 - C2
|
||||
dL = L1 - L2
|
||||
dH2 = get_dH2(lab1, lab2)
|
||||
|
||||
T = np.where(np.logical_and(np.rad2deg(h1) >= 164, np.rad2deg(h1) <= 345),
|
||||
0.56 + 0.2 * np.abs(np.cos(h1 + np.deg2rad(168))),
|
||||
0.36 + 0.4 * np.abs(np.cos(h1 + np.deg2rad(35)))
|
||||
)
|
||||
c1_4 = C1 ** 4
|
||||
F = np.sqrt(c1_4 / (c1_4 + 1900))
|
||||
|
||||
SL = np.where(L1 < 16, 0.511, 0.040975 * L1 / (1. + 0.01765 * L1))
|
||||
SC = 0.638 + 0.0638 * C1 / (1. + 0.0131 * C1)
|
||||
SH = SC * (F * T + 1 - F)
|
||||
|
||||
dE2 = (dL / (kL * SL)) ** 2
|
||||
dE2 += (dC / (kC * SC)) ** 2
|
||||
dE2 += dH2 / (SH ** 2)
|
||||
|
||||
return np.sqrt(np.maximum(dE2, 0))
|
||||
|
||||
|
||||
def get_dH2(lab1, lab2):
|
||||
"""squared hue difference term occurring in deltaE_cmc and deltaE_ciede94
|
||||
|
||||
Despite its name, "dH" is not a simple difference of hue values. We avoid
|
||||
working directly with the hue value, since differencing angles is
|
||||
troublesome. The hue term is usually written as:
|
||||
c1 = sqrt(a1**2 + b1**2)
|
||||
c2 = sqrt(a2**2 + b2**2)
|
||||
term = (a1-a2)**2 + (b1-b2)**2 - (c1-c2)**2
|
||||
dH = sqrt(term)
|
||||
|
||||
However, this has poor roundoff properties when a or b is dominant.
|
||||
Instead, ab is a vector with elements a and b. The same dH term can be
|
||||
re-written as:
|
||||
|ab1-ab2|**2 - (|ab1| - |ab2|)**2
|
||||
and then simplified to:
|
||||
2*|ab1|*|ab2| - 2*dot(ab1, ab2)
|
||||
"""
|
||||
lab1 = np.asarray(lab1)
|
||||
lab2 = np.asarray(lab2)
|
||||
|
||||
a1, b1 = np.rollaxis(lab1, -1)[1:3]
|
||||
a2, b2 = np.rollaxis(lab2, -1)[1:3]
|
||||
|
||||
# magnitude of (a, b) is the chroma
|
||||
C1 = np.hypot(a1, b1)
|
||||
C2 = np.hypot(a2, b2)
|
||||
|
||||
term = (C1 * C2) - (a1 * a2 + b1 * b2)
|
||||
return 2 * term
|
146
venv/Lib/site-packages/skimage/color/rgb_colors.py
Normal file
|
@ -0,0 +1,146 @@
|
|||
aliceblue = (0.941, 0.973, 1)
|
||||
antiquewhite = (0.98, 0.922, 0.843)
|
||||
aqua = (0, 1, 1)
|
||||
aquamarine = (0.498, 1, 0.831)
|
||||
azure = (0.941, 1, 1)
|
||||
beige = (0.961, 0.961, 0.863)
|
||||
bisque = (1, 0.894, 0.769)
|
||||
black = (0, 0, 0)
|
||||
blanchedalmond = (1, 0.922, 0.804)
|
||||
blue = (0, 0, 1)
|
||||
blueviolet = (0.541, 0.169, 0.886)
|
||||
brown = (0.647, 0.165, 0.165)
|
||||
burlywood = (0.871, 0.722, 0.529)
|
||||
cadetblue = (0.373, 0.62, 0.627)
|
||||
chartreuse = (0.498, 1, 0)
|
||||
chocolate = (0.824, 0.412, 0.118)
|
||||
coral = (1, 0.498, 0.314)
|
||||
cornflowerblue = (0.392, 0.584, 0.929)
|
||||
cornsilk = (1, 0.973, 0.863)
|
||||
crimson = (0.863, 0.0784, 0.235)
|
||||
cyan = (0, 1, 1)
|
||||
darkblue = (0, 0, 0.545)
|
||||
darkcyan = (0, 0.545, 0.545)
|
||||
darkgoldenrod = (0.722, 0.525, 0.0431)
|
||||
darkgray = (0.663, 0.663, 0.663)
|
||||
darkgreen = (0, 0.392, 0)
|
||||
darkgrey = (0.663, 0.663, 0.663)
|
||||
darkkhaki = (0.741, 0.718, 0.42)
|
||||
darkmagenta = (0.545, 0, 0.545)
|
||||
darkolivegreen = (0.333, 0.42, 0.184)
|
||||
darkorange = (1, 0.549, 0)
|
||||
darkorchid = (0.6, 0.196, 0.8)
|
||||
darkred = (0.545, 0, 0)
|
||||
darksalmon = (0.914, 0.588, 0.478)
|
||||
darkseagreen = (0.561, 0.737, 0.561)
|
||||
darkslateblue = (0.282, 0.239, 0.545)
|
||||
darkslategray = (0.184, 0.31, 0.31)
|
||||
darkslategrey = (0.184, 0.31, 0.31)
|
||||
darkturquoise = (0, 0.808, 0.82)
|
||||
darkviolet = (0.58, 0, 0.827)
|
||||
deeppink = (1, 0.0784, 0.576)
|
||||
deepskyblue = (0, 0.749, 1)
|
||||
dimgray = (0.412, 0.412, 0.412)
|
||||
dimgrey = (0.412, 0.412, 0.412)
|
||||
dodgerblue = (0.118, 0.565, 1)
|
||||
firebrick = (0.698, 0.133, 0.133)
|
||||
floralwhite = (1, 0.98, 0.941)
|
||||
forestgreen = (0.133, 0.545, 0.133)
|
||||
fuchsia = (1, 0, 1)
|
||||
gainsboro = (0.863, 0.863, 0.863)
|
||||
ghostwhite = (0.973, 0.973, 1)
|
||||
gold = (1, 0.843, 0)
|
||||
goldenrod = (0.855, 0.647, 0.125)
|
||||
gray = (0.502, 0.502, 0.502)
|
||||
green = (0, 0.502, 0)
|
||||
greenyellow = (0.678, 1, 0.184)
|
||||
grey = (0.502, 0.502, 0.502)
|
||||
honeydew = (0.941, 1, 0.941)
|
||||
hotpink = (1, 0.412, 0.706)
|
||||
indianred = (0.804, 0.361, 0.361)
|
||||
indigo = (0.294, 0, 0.51)
|
||||
ivory = (1, 1, 0.941)
|
||||
khaki = (0.941, 0.902, 0.549)
|
||||
lavender = (0.902, 0.902, 0.98)
|
||||
lavenderblush = (1, 0.941, 0.961)
|
||||
lawngreen = (0.486, 0.988, 0)
|
||||
lemonchiffon = (1, 0.98, 0.804)
|
||||
lightblue = (0.678, 0.847, 0.902)
|
||||
lightcoral = (0.941, 0.502, 0.502)
|
||||
lightcyan = (0.878, 1, 1)
|
||||
lightgoldenrodyellow = (0.98, 0.98, 0.824)
|
||||
lightgray = (0.827, 0.827, 0.827)
|
||||
lightgreen = (0.565, 0.933, 0.565)
|
||||
lightgrey = (0.827, 0.827, 0.827)
|
||||
lightpink = (1, 0.714, 0.757)
|
||||
lightsalmon = (1, 0.627, 0.478)
|
||||
lightseagreen = (0.125, 0.698, 0.667)
|
||||
lightskyblue = (0.529, 0.808, 0.98)
|
||||
lightslategray = (0.467, 0.533, 0.6)
|
||||
lightslategrey = (0.467, 0.533, 0.6)
|
||||
lightsteelblue = (0.69, 0.769, 0.871)
|
||||
lightyellow = (1, 1, 0.878)
|
||||
lime = (0, 1, 0)
|
||||
limegreen = (0.196, 0.804, 0.196)
|
||||
linen = (0.98, 0.941, 0.902)
|
||||
magenta = (1, 0, 1)
|
||||
maroon = (0.502, 0, 0)
|
||||
mediumaquamarine = (0.4, 0.804, 0.667)
|
||||
mediumblue = (0, 0, 0.804)
|
||||
mediumorchid = (0.729, 0.333, 0.827)
|
||||
mediumpurple = (0.576, 0.439, 0.859)
|
||||
mediumseagreen = (0.235, 0.702, 0.443)
|
||||
mediumslateblue = (0.482, 0.408, 0.933)
|
||||
mediumspringgreen = (0, 0.98, 0.604)
|
||||
mediumturquoise = (0.282, 0.82, 0.8)
|
||||
mediumvioletred = (0.78, 0.0824, 0.522)
|
||||
midnightblue = (0.098, 0.098, 0.439)
|
||||
mintcream = (0.961, 1, 0.98)
|
||||
mistyrose = (1, 0.894, 0.882)
|
||||
moccasin = (1, 0.894, 0.71)
|
||||
navajowhite = (1, 0.871, 0.678)
|
||||
navy = (0, 0, 0.502)
|
||||
oldlace = (0.992, 0.961, 0.902)
|
||||
olive = (0.502, 0.502, 0)
|
||||
olivedrab = (0.42, 0.557, 0.137)
|
||||
orange = (1, 0.647, 0)
|
||||
orangered = (1, 0.271, 0)
|
||||
orchid = (0.855, 0.439, 0.839)
|
||||
palegoldenrod = (0.933, 0.91, 0.667)
|
||||
palegreen = (0.596, 0.984, 0.596)
|
||||
palevioletred = (0.686, 0.933, 0.933)
|
||||
papayawhip = (1, 0.937, 0.835)
|
||||
peachpuff = (1, 0.855, 0.725)
|
||||
peru = (0.804, 0.522, 0.247)
|
||||
pink = (1, 0.753, 0.796)
|
||||
plum = (0.867, 0.627, 0.867)
|
||||
powderblue = (0.69, 0.878, 0.902)
|
||||
purple = (0.502, 0, 0.502)
|
||||
red = (1, 0, 0)
|
||||
rosybrown = (0.737, 0.561, 0.561)
|
||||
royalblue = (0.255, 0.412, 0.882)
|
||||
saddlebrown = (0.545, 0.271, 0.0745)
|
||||
salmon = (0.98, 0.502, 0.447)
|
||||
sandybrown = (0.98, 0.643, 0.376)
|
||||
seagreen = (0.18, 0.545, 0.341)
|
||||
seashell = (1, 0.961, 0.933)
|
||||
sienna = (0.627, 0.322, 0.176)
|
||||
silver = (0.753, 0.753, 0.753)
|
||||
skyblue = (0.529, 0.808, 0.922)
|
||||
slateblue = (0.416, 0.353, 0.804)
|
||||
slategray = (0.439, 0.502, 0.565)
|
||||
slategrey = (0.439, 0.502, 0.565)
|
||||
snow = (1, 0.98, 0.98)
|
||||
springgreen = (0, 1, 0.498)
|
||||
steelblue = (0.275, 0.51, 0.706)
|
||||
tan = (0.824, 0.706, 0.549)
|
||||
teal = (0, 0.502, 0.502)
|
||||
thistle = (0.847, 0.749, 0.847)
|
||||
tomato = (1, 0.388, 0.278)
|
||||
turquoise = (0.251, 0.878, 0.816)
|
||||
violet = (0.933, 0.51, 0.933)
|
||||
wheat = (0.961, 0.871, 0.702)
|
||||
white = (1, 1, 1)
|
||||
whitesmoke = (0.961, 0.961, 0.961)
|
||||
yellow = (1, 1, 0)
|
||||
yellowgreen = (0.604, 0.804, 0.196)
|
9
venv/Lib/site-packages/skimage/color/tests/__init__.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from ..._shared.testing import setup_test, teardown_test
|
||||
|
||||
|
||||
def setup():
|
||||
setup_test()
|
||||
|
||||
|
||||
def teardown():
|
||||
teardown_test()
|
94
venv/Lib/site-packages/skimage/color/tests/test_adapt_rgb.py
Normal file
|
@ -0,0 +1,94 @@
|
|||
from functools import partial
|
||||
|
||||
import numpy as np
|
||||
|
||||
from skimage import img_as_float, img_as_uint
|
||||
from skimage import color, data, filters
|
||||
from skimage.color.adapt_rgb import adapt_rgb, each_channel, hsv_value
|
||||
|
||||
# Down-sample image for quicker testing.
|
||||
COLOR_IMAGE = data.astronaut()[::5, ::6]
|
||||
GRAY_IMAGE = data.camera()[::5, ::5]
|
||||
|
||||
SIGMA = 3
|
||||
smooth = partial(filters.gaussian, sigma=SIGMA)
|
||||
assert_allclose = partial(np.testing.assert_allclose, atol=1e-8)
|
||||
|
||||
|
||||
@adapt_rgb(each_channel)
|
||||
def edges_each(image):
|
||||
return filters.sobel(image)
|
||||
|
||||
|
||||
@adapt_rgb(each_channel)
|
||||
def smooth_each(image, sigma):
|
||||
return filters.gaussian(image, sigma)
|
||||
|
||||
|
||||
@adapt_rgb(each_channel)
|
||||
def mask_each(image, mask):
|
||||
result = image.copy()
|
||||
result[mask] = 0
|
||||
return result
|
||||
|
||||
|
||||
@adapt_rgb(hsv_value)
|
||||
def edges_hsv(image):
|
||||
return filters.sobel(image)
|
||||
|
||||
|
||||
@adapt_rgb(hsv_value)
|
||||
def smooth_hsv(image, sigma):
|
||||
return filters.gaussian(image, sigma)
|
||||
|
||||
|
||||
@adapt_rgb(hsv_value)
|
||||
def edges_hsv_uint(image):
|
||||
return img_as_uint(filters.sobel(image))
|
||||
|
||||
|
||||
def test_gray_scale_image():
|
||||
# We don't need to test both `hsv_value` and `each_channel` since
|
||||
# `adapt_rgb` is handling gray-scale inputs.
|
||||
assert_allclose(edges_each(GRAY_IMAGE), filters.sobel(GRAY_IMAGE))
|
||||
|
||||
|
||||
def test_each_channel():
|
||||
filtered = edges_each(COLOR_IMAGE)
|
||||
for i, channel in enumerate(np.rollaxis(filtered, axis=-1)):
|
||||
expected = img_as_float(filters.sobel(COLOR_IMAGE[:, :, i]))
|
||||
assert_allclose(channel, expected)
|
||||
|
||||
|
||||
def test_each_channel_with_filter_argument():
|
||||
filtered = smooth_each(COLOR_IMAGE, SIGMA)
|
||||
for i, channel in enumerate(np.rollaxis(filtered, axis=-1)):
|
||||
assert_allclose(channel, smooth(COLOR_IMAGE[:, :, i]))
|
||||
|
||||
|
||||
def test_each_channel_with_asymmetric_kernel():
|
||||
mask = np.triu(np.ones(COLOR_IMAGE.shape[:2], dtype=np.bool_))
|
||||
mask_each(COLOR_IMAGE, mask)
|
||||
|
||||
|
||||
def test_hsv_value():
|
||||
filtered = edges_hsv(COLOR_IMAGE)
|
||||
value = color.rgb2hsv(COLOR_IMAGE)[:, :, 2]
|
||||
assert_allclose(color.rgb2hsv(filtered)[:, :, 2], filters.sobel(value))
|
||||
|
||||
|
||||
def test_hsv_value_with_filter_argument():
|
||||
filtered = smooth_hsv(COLOR_IMAGE, SIGMA)
|
||||
value = color.rgb2hsv(COLOR_IMAGE)[:, :, 2]
|
||||
assert_allclose(color.rgb2hsv(filtered)[:, :, 2], smooth(value))
|
||||
|
||||
|
||||
def test_hsv_value_with_non_float_output():
|
||||
# Since `rgb2hsv` returns a float image and the result of the filtered
|
||||
# result is inserted into the HSV image, we want to make sure there isn't
|
||||
# a dtype mismatch.
|
||||
filtered = edges_hsv_uint(COLOR_IMAGE)
|
||||
filtered_value = color.rgb2hsv(filtered)[:, :, 2]
|
||||
value = color.rgb2hsv(COLOR_IMAGE)[:, :, 2]
|
||||
# Reduce tolerance because dtype conversion.
|
||||
assert_allclose(filtered_value, filters.sobel(value), rtol=1e-5, atol=1e-5)
|
778
venv/Lib/site-packages/skimage/color/tests/test_colorconv.py
Normal file
|
@ -0,0 +1,778 @@
|
|||
"""Tests for color conversion functions.
|
||||
|
||||
Authors
|
||||
-------
|
||||
- the rgb2hsv test was written by Nicolas Pinto, 2009
|
||||
- other tests written by Ralf Gommers, 2009
|
||||
|
||||
:license: modified BSD
|
||||
"""
|
||||
|
||||
import numpy as np
|
||||
import pytest
|
||||
from skimage._shared.testing import assert_equal, assert_almost_equal
|
||||
from skimage._shared.testing import assert_array_almost_equal, fetch
|
||||
from skimage._shared.testing import TestCase
|
||||
|
||||
from skimage.util import img_as_float, img_as_ubyte, img_as_float32
|
||||
from skimage.color import (rgb2hsv, hsv2rgb,
|
||||
rgb2xyz, xyz2rgb,
|
||||
rgb2hed, hed2rgb,
|
||||
separate_stains,
|
||||
combine_stains,
|
||||
rgb2rgbcie, rgbcie2rgb,
|
||||
convert_colorspace,
|
||||
rgb2gray, gray2rgb,
|
||||
xyz2lab, lab2xyz,
|
||||
lab2rgb, rgb2lab,
|
||||
xyz2luv, luv2xyz,
|
||||
luv2rgb, rgb2luv,
|
||||
lab2lch, lch2lab,
|
||||
rgb2yuv, yuv2rgb,
|
||||
rgb2yiq, yiq2rgb,
|
||||
rgb2ypbpr, ypbpr2rgb,
|
||||
rgb2ycbcr, ycbcr2rgb,
|
||||
rgb2ydbdr, ydbdr2rgb,
|
||||
rgba2rgb, gray2rgba)
|
||||
|
||||
from skimage._shared._warnings import expected_warnings
|
||||
from skimage import data
|
||||
import colorsys
|
||||
|
||||
|
||||
class TestColorconv(TestCase):
|
||||
|
||||
img_rgb = data.colorwheel()
|
||||
img_grayscale = data.camera()
|
||||
img_rgba = np.array([[[0, 0.5, 1, 0],
|
||||
[0, 0.5, 1, 1],
|
||||
[0, 0.5, 1, 0.5]]]).astype(np.float)
|
||||
|
||||
colbars = np.array([[1, 1, 0, 0, 1, 1, 0, 0],
|
||||
[1, 1, 1, 1, 0, 0, 0, 0],
|
||||
[1, 0, 1, 0, 1, 0, 1, 0]]).astype(np.float)
|
||||
colbars_array = np.swapaxes(colbars.reshape(3, 4, 2), 0, 2)
|
||||
colbars_point75 = colbars * 0.75
|
||||
colbars_point75_array = np.swapaxes(colbars_point75.reshape(3, 4, 2), 0, 2)
|
||||
|
||||
xyz_array = np.array([[[0.4124, 0.21260, 0.01930]], # red
|
||||
[[0, 0, 0]], # black
|
||||
[[.9505, 1., 1.089]], # white
|
||||
[[.1805, .0722, .9505]], # blue
|
||||
[[.07719, .15438, .02573]], # green
|
||||
])
|
||||
lab_array = np.array([[[53.233, 80.109, 67.220]], # red
|
||||
[[0., 0., 0.]], # black
|
||||
[[100.0, 0.005, -0.010]], # white
|
||||
[[32.303, 79.197, -107.864]], # blue
|
||||
[[46.229, -51.7, 49.898]], # green
|
||||
])
|
||||
|
||||
luv_array = np.array([[[53.233, 175.053, 37.751]], # red
|
||||
[[0., 0., 0.]], # black
|
||||
[[100., 0.001, -0.017]], # white
|
||||
[[32.303, -9.400, -130.358]], # blue
|
||||
[[46.228, -43.774, 56.589]], # green
|
||||
])
|
||||
|
||||
# RGBA to RGB
|
||||
def test_rgba2rgb_conversion(self):
|
||||
rgba = self.img_rgba
|
||||
rgb = rgba2rgb(rgba)
|
||||
expected = np.array([[[1, 1, 1],
|
||||
[0, 0.5, 1],
|
||||
[0.5, 0.75, 1]]]).astype(np.float)
|
||||
self.assertEqual(rgb.shape, expected.shape)
|
||||
assert_almost_equal(rgb, expected)
|
||||
|
||||
def test_rgba2rgb_error_grayscale(self):
|
||||
self.assertRaises(ValueError, rgba2rgb, self.img_grayscale)
|
||||
|
||||
def test_rgba2rgb_error_rgb(self):
|
||||
self.assertRaises(ValueError, rgba2rgb, self.img_rgb)
|
||||
|
||||
def test_rgba2rgb_dtype(self):
|
||||
rgba = self.img_rgba.astype('float64')
|
||||
rgba32 = img_as_float32(rgba)
|
||||
|
||||
assert rgba2rgb(rgba).dtype == rgba.dtype
|
||||
assert rgba2rgb(rgba32).dtype == rgba32.dtype
|
||||
|
||||
# RGB to HSV
|
||||
def test_rgb2hsv_conversion(self):
|
||||
rgb = img_as_float(self.img_rgb)[::16, ::16]
|
||||
hsv = rgb2hsv(rgb).reshape(-1, 3)
|
||||
# ground truth from colorsys
|
||||
gt = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2])
|
||||
for pt in rgb.reshape(-1, 3)]
|
||||
)
|
||||
assert_almost_equal(hsv, gt)
|
||||
|
||||
def test_rgb2hsv_error_grayscale(self):
|
||||
self.assertRaises(ValueError, rgb2hsv, self.img_grayscale)
|
||||
|
||||
def test_rgb2hsv_dtype(self):
|
||||
rgb = img_as_float(self.img_rgb)
|
||||
rgb32 = img_as_float32(self.img_rgb)
|
||||
|
||||
assert rgb2hsv(rgb).dtype == rgb.dtype
|
||||
assert rgb2hsv(rgb32).dtype == rgb32.dtype
|
||||
|
||||
# HSV to RGB
|
||||
def test_hsv2rgb_conversion(self):
|
||||
rgb = self.img_rgb.astype("float32")[::16, ::16]
|
||||
# create HSV image with colorsys
|
||||
hsv = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2])
|
||||
for pt in rgb.reshape(-1, 3)]).reshape(rgb.shape)
|
||||
# convert back to RGB and compare with original.
|
||||
# relative precision for RGB -> HSV roundtrip is about 1e-6
|
||||
assert_almost_equal(rgb, hsv2rgb(hsv), decimal=4)
|
||||
|
||||
def test_hsv2rgb_error_grayscale(self):
|
||||
self.assertRaises(ValueError, hsv2rgb, self.img_grayscale)
|
||||
|
||||
def test_hsv2rgb_dtype(self):
|
||||
rgb = self.img_rgb.astype("float32")[::16, ::16]
|
||||
# create HSV image with colorsys
|
||||
hsv = np.array([colorsys.rgb_to_hsv(pt[0], pt[1], pt[2])
|
||||
for pt in rgb.reshape(-1, 3)],
|
||||
dtype='float64').reshape(rgb.shape)
|
||||
hsv32 = hsv.astype('float32')
|
||||
|
||||
assert hsv2rgb(hsv).dtype == hsv.dtype
|
||||
assert hsv2rgb(hsv32).dtype == hsv32.dtype
|
||||
|
||||
# RGB to XYZ
|
||||
def test_rgb2xyz_conversion(self):
|
||||
gt = np.array([[[0.950456, 1. , 1.088754],
|
||||
[0.538003, 0.787329, 1.06942 ],
|
||||
[0.592876, 0.28484 , 0.969561],
|
||||
[0.180423, 0.072169, 0.950227]],
|
||||
[[0.770033, 0.927831, 0.138527],
|
||||
[0.35758 , 0.71516 , 0.119193],
|
||||
[0.412453, 0.212671, 0.019334],
|
||||
[0. , 0. , 0. ]]])
|
||||
assert_almost_equal(rgb2xyz(self.colbars_array), gt)
|
||||
|
||||
# stop repeating the "raises" checks for all other functions that are
|
||||
# implemented with color._convert()
|
||||
def test_rgb2xyz_error_grayscale(self):
|
||||
self.assertRaises(ValueError, rgb2xyz, self.img_grayscale)
|
||||
|
||||
def test_rgb2xyz_dtype(self):
|
||||
img = self.colbars_array
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2xyz(img).dtype == img.dtype
|
||||
assert rgb2xyz(img32).dtype == img32.dtype
|
||||
|
||||
# XYZ to RGB
|
||||
def test_xyz2rgb_conversion(self):
|
||||
assert_almost_equal(xyz2rgb(rgb2xyz(self.colbars_array)),
|
||||
self.colbars_array)
|
||||
|
||||
def test_xyz2rgb_dtype(self):
|
||||
img = rgb2xyz(self.colbars_array)
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert xyz2rgb(img).dtype == img.dtype
|
||||
assert xyz2rgb(img32).dtype == img32.dtype
|
||||
|
||||
# RGB<->XYZ roundtrip on another image
|
||||
def test_xyz_rgb_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)
|
||||
assert_array_almost_equal(xyz2rgb(rgb2xyz(img_rgb)), img_rgb)
|
||||
|
||||
# RGB<->HED roundtrip with ubyte image
|
||||
def test_hed_rgb_roundtrip(self):
|
||||
img_rgb = img_as_ubyte(self.img_rgb)
|
||||
new = img_as_ubyte(hed2rgb(rgb2hed(img_rgb)))
|
||||
assert_equal(new, img_rgb)
|
||||
|
||||
# RGB<->HED roundtrip with float image
|
||||
def test_hed_rgb_float_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)
|
||||
assert_array_almost_equal(hed2rgb(rgb2hed(img_rgb)), img_rgb)
|
||||
|
||||
# RGB<->HDX roundtrip with ubyte image
|
||||
def test_hdx_rgb_roundtrip(self):
|
||||
from skimage.color.colorconv import hdx_from_rgb, rgb_from_hdx
|
||||
img_rgb = self.img_rgb
|
||||
conv = combine_stains(separate_stains(img_rgb, hdx_from_rgb),
|
||||
rgb_from_hdx)
|
||||
assert_equal(img_as_ubyte(conv), img_rgb)
|
||||
|
||||
# RGB<->HDX roundtrip with float image
|
||||
def test_hdx_rgb_roundtrip_float(self):
|
||||
from skimage.color.colorconv import hdx_from_rgb, rgb_from_hdx
|
||||
img_rgb = img_as_float(self.img_rgb)
|
||||
conv = combine_stains(separate_stains(img_rgb, hdx_from_rgb),
|
||||
rgb_from_hdx)
|
||||
assert_array_almost_equal(conv, img_rgb)
|
||||
|
||||
# RGB to RGB CIE
|
||||
def test_rgb2rgbcie_conversion(self):
|
||||
gt = np.array([[[ 0.1488856 , 0.18288098, 0.19277574],
|
||||
[ 0.01163224, 0.16649536, 0.18948516],
|
||||
[ 0.12259182, 0.03308008, 0.17298223],
|
||||
[-0.01466154, 0.01669446, 0.16969164]],
|
||||
[[ 0.16354714, 0.16618652, 0.0230841 ],
|
||||
[ 0.02629378, 0.1498009 , 0.01979351],
|
||||
[ 0.13725336, 0.01638562, 0.00329059],
|
||||
[ 0. , 0. , 0. ]]])
|
||||
assert_almost_equal(rgb2rgbcie(self.colbars_array), gt)
|
||||
|
||||
def test_rgb2rgbcie_dtype(self):
|
||||
img = self.colbars_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2rgbcie(img).dtype == img.dtype
|
||||
assert rgb2rgbcie(img32).dtype == img32.dtype
|
||||
|
||||
# RGB CIE to RGB
|
||||
def test_rgbcie2rgb_conversion(self):
|
||||
# only roundtrip test, we checked rgb2rgbcie above already
|
||||
assert_almost_equal(rgbcie2rgb(rgb2rgbcie(self.colbars_array)),
|
||||
self.colbars_array)
|
||||
|
||||
def test_rgbcie2rgb_dtype(self):
|
||||
img = rgb2rgbcie(self.colbars_array).astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgbcie2rgb(img).dtype == img.dtype
|
||||
assert rgbcie2rgb(img32).dtype == img32.dtype
|
||||
|
||||
def test_convert_colorspace(self):
|
||||
colspaces = ['HSV', 'RGB CIE', 'XYZ', 'YCbCr', 'YPbPr', 'YDbDr']
|
||||
colfuncs_from = [
|
||||
hsv2rgb, rgbcie2rgb, xyz2rgb,
|
||||
ycbcr2rgb, ypbpr2rgb, ydbdr2rgb
|
||||
]
|
||||
colfuncs_to = [
|
||||
rgb2hsv, rgb2rgbcie, rgb2xyz,
|
||||
rgb2ycbcr, rgb2ypbpr, rgb2ydbdr
|
||||
]
|
||||
|
||||
assert_almost_equal(
|
||||
convert_colorspace(self.colbars_array, 'RGB', 'RGB'),
|
||||
self.colbars_array)
|
||||
|
||||
for i, space in enumerate(colspaces):
|
||||
gt = colfuncs_from[i](self.colbars_array)
|
||||
assert_almost_equal(
|
||||
convert_colorspace(self.colbars_array, space, 'RGB'), gt)
|
||||
gt = colfuncs_to[i](self.colbars_array)
|
||||
assert_almost_equal(
|
||||
convert_colorspace(self.colbars_array, 'RGB', space), gt)
|
||||
|
||||
self.assertRaises(ValueError, convert_colorspace,
|
||||
self.colbars_array, 'nokey', 'XYZ')
|
||||
self.assertRaises(ValueError, convert_colorspace,
|
||||
self.colbars_array, 'RGB', 'nokey')
|
||||
|
||||
def test_rgb2gray(self):
|
||||
x = np.array([1, 1, 1]).reshape((1, 1, 3)).astype(np.float)
|
||||
g = rgb2gray(x)
|
||||
assert_array_almost_equal(g, 1)
|
||||
|
||||
assert_equal(g.shape, (1, 1))
|
||||
|
||||
def test_rgb2gray_contiguous(self):
|
||||
x = np.random.rand(10, 10, 3)
|
||||
assert rgb2gray(x).flags["C_CONTIGUOUS"]
|
||||
assert rgb2gray(x[:5, :5]).flags["C_CONTIGUOUS"]
|
||||
|
||||
def test_rgb2gray_alpha(self):
|
||||
x = np.random.rand(10, 10, 4)
|
||||
with expected_warnings(['Non RGB image conversion']):
|
||||
assert rgb2gray(x).ndim == 2
|
||||
|
||||
def test_rgb2gray_on_gray(self):
|
||||
with expected_warnings(['The behavior of rgb2gray will change']):
|
||||
rgb2gray(np.random.rand(5, 5))
|
||||
|
||||
def test_rgb2gray_dtype(self):
|
||||
img = np.random.rand(10, 10, 3).astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2gray(img).dtype == img.dtype
|
||||
assert rgb2gray(img32).dtype == img32.dtype
|
||||
|
||||
# test matrices for xyz2lab and lab2xyz generated using
|
||||
# http://www.easyrgb.com/index.php?X=CALC
|
||||
# Note: easyrgb website displays xyz*100
|
||||
def test_xyz2lab(self):
|
||||
assert_array_almost_equal(xyz2lab(self.xyz_array),
|
||||
self.lab_array, decimal=3)
|
||||
|
||||
# Test the conversion with the rest of the illuminants.
|
||||
for I in ["d50", "d55", "d65", "d75"]:
|
||||
for obs in ["2", "10"]:
|
||||
fname = "color/tests/data/lab_array_{0}_{1}.npy".format(I, obs)
|
||||
lab_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(lab_array_I_obs,
|
||||
xyz2lab(self.xyz_array, I, obs),
|
||||
decimal=2)
|
||||
for I in ["a", "e"]:
|
||||
fname = "color/tests/data/lab_array_{0}_2.npy".format(I)
|
||||
lab_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(lab_array_I_obs,
|
||||
xyz2lab(self.xyz_array, I, "2"),
|
||||
decimal=2)
|
||||
|
||||
def test_xyz2lab_dtype(self):
|
||||
img = self.xyz_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert xyz2lab(img).dtype == img.dtype
|
||||
assert xyz2lab(img32).dtype == img32.dtype
|
||||
|
||||
def test_lab2xyz(self):
|
||||
assert_array_almost_equal(lab2xyz(self.lab_array),
|
||||
self.xyz_array, decimal=3)
|
||||
|
||||
# Test the conversion with the rest of the illuminants.
|
||||
for I in ["d50", "d55", "d65", "d75"]:
|
||||
for obs in ["2", "10"]:
|
||||
fname = "color/tests/data/lab_array_{0}_{1}.npy".format(I, obs)
|
||||
lab_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(lab2xyz(lab_array_I_obs, I, obs),
|
||||
self.xyz_array, decimal=3)
|
||||
for I in ["a", "e"]:
|
||||
fname = "lab_array_{0}_2.npy".format(I, obs)
|
||||
lab_array_I_obs = np.load(fetch('color/tests/data/' + fname))
|
||||
assert_array_almost_equal(lab2xyz(lab_array_I_obs, I, "2"),
|
||||
self.xyz_array, decimal=3)
|
||||
|
||||
# And we include a call to test the exception handling in the code.
|
||||
try:
|
||||
xs = lab2xyz(lab_array_I_obs, "NaI", "2") # Not an illuminant
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
try:
|
||||
xs = lab2xyz(lab_array_I_obs, "d50", "42") # Not a degree
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
def test_lab2xyz_dtype(self):
|
||||
img = self.lab_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert lab2xyz(img).dtype == img.dtype
|
||||
assert lab2xyz(img32).dtype == img32.dtype
|
||||
|
||||
def test_rgb2lab_brucelindbloom(self):
|
||||
"""
|
||||
Test the RGB->Lab conversion by comparing to the calculator on the
|
||||
authoritative Bruce Lindbloom
|
||||
[website](http://brucelindbloom.com/index.html?ColorCalculator.html).
|
||||
"""
|
||||
# Obtained with D65 white point, sRGB model and gamma
|
||||
gt_for_colbars = np.array([
|
||||
[100,0,0],
|
||||
[97.1393, -21.5537, 94.4780],
|
||||
[91.1132, -48.0875, -14.1312],
|
||||
[87.7347, -86.1827, 83.1793],
|
||||
[60.3242, 98.2343, -60.8249],
|
||||
[53.2408, 80.0925, 67.2032],
|
||||
[32.2970, 79.1875, -107.8602],
|
||||
[0,0,0]]).T
|
||||
gt_array = np.swapaxes(gt_for_colbars.reshape(3, 4, 2), 0, 2)
|
||||
assert_array_almost_equal(rgb2lab(self.colbars_array), gt_array, decimal=2)
|
||||
|
||||
def test_lab_rgb_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)
|
||||
assert_array_almost_equal(lab2rgb(rgb2lab(img_rgb)), img_rgb)
|
||||
|
||||
def test_rgb2lab_dtype(self):
|
||||
img = self.colbars_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2lab(img).dtype == img.dtype
|
||||
assert rgb2lab(img32).dtype == img32.dtype
|
||||
|
||||
def test_lab2rgb_dtype(self):
|
||||
img = self.lab_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert lab2rgb(img).dtype == img.dtype
|
||||
assert lab2rgb(img32).dtype == img32.dtype
|
||||
|
||||
# test matrices for xyz2luv and luv2xyz generated using
|
||||
# http://www.easyrgb.com/index.php?X=CALC
|
||||
# Note: easyrgb website displays xyz*100
|
||||
def test_xyz2luv(self):
|
||||
assert_array_almost_equal(xyz2luv(self.xyz_array),
|
||||
self.luv_array, decimal=3)
|
||||
|
||||
# Test the conversion with the rest of the illuminants.
|
||||
for I in ["d50", "d55", "d65", "d75"]:
|
||||
for obs in ["2", "10"]:
|
||||
fname = "color/tests/data/luv_array_{0}_{1}.npy".format(I, obs)
|
||||
luv_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(luv_array_I_obs,
|
||||
xyz2luv(self.xyz_array, I, obs),
|
||||
decimal=2)
|
||||
for I in ["a", "e"]:
|
||||
fname = "color/tests/data/luv_array_{0}_2.npy".format(I)
|
||||
luv_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(luv_array_I_obs,
|
||||
xyz2luv(self.xyz_array, I, "2"),
|
||||
decimal=2)
|
||||
|
||||
def test_xyz2luv_dtype(self):
|
||||
img = self.xyz_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert xyz2luv(img).dtype == img.dtype
|
||||
assert xyz2luv(img32).dtype == img32.dtype
|
||||
|
||||
def test_luv2xyz(self):
|
||||
assert_array_almost_equal(luv2xyz(self.luv_array),
|
||||
self.xyz_array, decimal=3)
|
||||
|
||||
# Test the conversion with the rest of the illuminants.
|
||||
for I in ["d50", "d55", "d65", "d75"]:
|
||||
for obs in ["2", "10"]:
|
||||
fname = "color/tests/data/luv_array_{0}_{1}.npy".format(I, obs)
|
||||
luv_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(luv2xyz(luv_array_I_obs, I, obs),
|
||||
self.xyz_array, decimal=3)
|
||||
for I in ["a", "e"]:
|
||||
fname = "color/tests/data/luv_array_{0}_2.npy".format(I, obs)
|
||||
luv_array_I_obs = np.load(fetch(fname))
|
||||
assert_array_almost_equal(luv2xyz(luv_array_I_obs, I, "2"),
|
||||
self.xyz_array, decimal=3)
|
||||
|
||||
def test_luv2xyz_dtype(self):
|
||||
img = self.luv_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert luv2xyz(img).dtype == img.dtype
|
||||
assert luv2xyz(img32).dtype == img32.dtype
|
||||
|
||||
def test_rgb2luv_brucelindbloom(self):
|
||||
"""
|
||||
Test the RGB->Lab conversion by comparing to the calculator on the
|
||||
authoritative Bruce Lindbloom
|
||||
[website](http://brucelindbloom.com/index.html?ColorCalculator.html).
|
||||
"""
|
||||
# Obtained with D65 white point, sRGB model and gamma
|
||||
gt_for_colbars = np.array([
|
||||
[100, 0, 0],
|
||||
[97.1393, 7.7056, 106.7866],
|
||||
[91.1132, -70.4773, -15.2042],
|
||||
[87.7347, -83.0776, 107.3985],
|
||||
[60.3242, 84.0714, -108.6834],
|
||||
[53.2408, 175.0151, 37.7564],
|
||||
[32.2970, -9.4054, -130.3423],
|
||||
[0, 0, 0]]).T
|
||||
gt_array = np.swapaxes(gt_for_colbars.reshape(3, 4, 2), 0, 2)
|
||||
assert_array_almost_equal(rgb2luv(self.colbars_array),
|
||||
gt_array, decimal=2)
|
||||
|
||||
def test_rgb2luv_dtype(self):
|
||||
img = self.colbars_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2luv(img).dtype == img.dtype
|
||||
assert rgb2luv(img32).dtype == img32.dtype
|
||||
|
||||
def test_luv2rgb_dtype(self):
|
||||
img = self.luv_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert luv2rgb(img).dtype == img.dtype
|
||||
assert luv2rgb(img32).dtype == img32.dtype
|
||||
|
||||
def test_luv_rgb_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)
|
||||
assert_array_almost_equal(luv2rgb(rgb2luv(img_rgb)), img_rgb)
|
||||
|
||||
def test_lab_rgb_outlier(self):
|
||||
lab_array = np.ones((3, 1, 3))
|
||||
lab_array[0] = [50, -12, 85]
|
||||
lab_array[1] = [50, 12, -85]
|
||||
lab_array[2] = [90, -4, -47]
|
||||
rgb_array = np.array([[[0.501, 0.481, 0]],
|
||||
[[0, 0.482, 1.]],
|
||||
[[0.578, 0.914, 1.]],
|
||||
])
|
||||
assert_almost_equal(lab2rgb(lab_array), rgb_array, decimal=3)
|
||||
|
||||
def test_lab_full_gamut(self):
|
||||
a, b = np.meshgrid(np.arange(-100, 100), np.arange(-100, 100))
|
||||
L = np.ones(a.shape)
|
||||
lab = np.dstack((L, a, b))
|
||||
for value in [0, 10, 20]:
|
||||
lab[:, :, 0] = value
|
||||
with expected_warnings(['Color data out of range']):
|
||||
lab2xyz(lab)
|
||||
|
||||
def test_lab_lch_roundtrip(self):
|
||||
rgb = img_as_float(self.img_rgb)
|
||||
lab = rgb2lab(rgb)
|
||||
lab2 = lch2lab(lab2lch(lab))
|
||||
assert_array_almost_equal(lab2, lab)
|
||||
|
||||
def test_rgb_lch_roundtrip(self):
|
||||
rgb = img_as_float(self.img_rgb)
|
||||
lab = rgb2lab(rgb)
|
||||
lch = lab2lch(lab)
|
||||
lab2 = lch2lab(lch)
|
||||
rgb2 = lab2rgb(lab2)
|
||||
assert_array_almost_equal(rgb, rgb2)
|
||||
|
||||
def test_lab_lch_0d(self):
|
||||
lab0 = self._get_lab0()
|
||||
lch0 = lab2lch(lab0)
|
||||
lch2 = lab2lch(lab0[None, None, :])
|
||||
assert_array_almost_equal(lch0, lch2[0, 0, :])
|
||||
|
||||
def test_lab_lch_1d(self):
|
||||
lab0 = self._get_lab0()
|
||||
lch0 = lab2lch(lab0)
|
||||
lch1 = lab2lch(lab0[None, :])
|
||||
assert_array_almost_equal(lch0, lch1[0, :])
|
||||
|
||||
def test_lab_lch_3d(self):
|
||||
lab0 = self._get_lab0()
|
||||
lch0 = lab2lch(lab0)
|
||||
lch3 = lab2lch(lab0[None, None, None, :])
|
||||
assert_array_almost_equal(lch0, lch3[0, 0, 0, :])
|
||||
|
||||
def _get_lab0(self):
|
||||
rgb = img_as_float(self.img_rgb[:1, :1, :])
|
||||
return rgb2lab(rgb)[0, 0, :]
|
||||
|
||||
def test_yuv(self):
|
||||
rgb = np.array([[[1.0, 1.0, 1.0]]])
|
||||
assert_array_almost_equal(rgb2yuv(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2yiq(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[1, 0, 0]]]))
|
||||
assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[235, 128, 128]]]))
|
||||
assert_array_almost_equal(rgb2ydbdr(rgb), np.array([[[1, 0, 0]]]))
|
||||
rgb = np.array([[[0.0, 1.0, 0.0]]])
|
||||
assert_array_almost_equal(rgb2yuv(rgb), np.array([[[0.587, -0.28886916, -0.51496512]]]))
|
||||
assert_array_almost_equal(rgb2yiq(rgb), np.array([[[0.587, -0.27455667, -0.52273617]]]))
|
||||
assert_array_almost_equal(rgb2ypbpr(rgb), np.array([[[0.587, -0.331264, -0.418688]]]))
|
||||
assert_array_almost_equal(rgb2ycbcr(rgb), np.array([[[144.553, 53.797, 34.214]]]))
|
||||
assert_array_almost_equal(rgb2ydbdr(rgb), np.array([[[0.587, -0.883, 1.116]]]))
|
||||
|
||||
def test_yuv_roundtrip(self):
|
||||
img_rgb = img_as_float(self.img_rgb)[::16, ::16]
|
||||
assert_array_almost_equal(yuv2rgb(rgb2yuv(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(yiq2rgb(rgb2yiq(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(ypbpr2rgb(rgb2ypbpr(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(ycbcr2rgb(rgb2ycbcr(img_rgb)), img_rgb)
|
||||
assert_array_almost_equal(ydbdr2rgb(rgb2ydbdr(img_rgb)), img_rgb)
|
||||
|
||||
def test_rgb2yuv_dtype(self):
|
||||
img = self.colbars_array.astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert rgb2yuv(img).dtype == img.dtype
|
||||
assert rgb2yuv(img32).dtype == img32.dtype
|
||||
|
||||
def test_yuv2rgb_dtype(self):
|
||||
img = rgb2yuv(self.colbars_array).astype('float64')
|
||||
img32 = img.astype('float32')
|
||||
|
||||
assert yuv2rgb(img).dtype == img.dtype
|
||||
assert yuv2rgb(img32).dtype == img32.dtype
|
||||
|
||||
def test_rgb2yiq_conversion(self):
|
||||
rgb = img_as_float(self.img_rgb)[::16, ::16]
|
||||
yiq = rgb2yiq(rgb).reshape(-1, 3)
|
||||
gt = np.array([colorsys.rgb_to_yiq(pt[0], pt[1], pt[2])
|
||||
for pt in rgb.reshape(-1, 3)]
|
||||
)
|
||||
assert_almost_equal(yiq, gt, decimal=2)
|
||||
|
||||
|
||||
def test_gray2rgb():
|
||||
x = np.array([0, 0.5, 1])
|
||||
w = gray2rgb(x)
|
||||
expected_output = np.array([[ 0, 0, 0 ],
|
||||
[ 0.5, 0.5, 0.5, ],
|
||||
[ 1, 1, 1 ]])
|
||||
|
||||
assert_equal(w, expected_output)
|
||||
|
||||
x = x.reshape((3, 1))
|
||||
y = gray2rgb(x)
|
||||
|
||||
assert_equal(y.shape, (3, 1, 3))
|
||||
assert_equal(y.dtype, x.dtype)
|
||||
assert_equal(y[..., 0], x)
|
||||
assert_equal(y[0, 0, :], [0, 0, 0])
|
||||
|
||||
x = np.array([[0, 128, 255]], dtype=np.uint8)
|
||||
z = gray2rgb(x)
|
||||
|
||||
assert_equal(z.shape, (1, 3, 3))
|
||||
assert_equal(z[..., 0], x)
|
||||
assert_equal(z[0, 1, :], [128, 128, 128])
|
||||
|
||||
|
||||
def test_gray2rgb_rgb():
|
||||
x = np.random.rand(5, 5, 4)
|
||||
with expected_warnings(['Pass-through of possibly RGB images']):
|
||||
y = gray2rgb(x)
|
||||
assert_equal(x, y)
|
||||
|
||||
|
||||
def test_gray2rgb_alpha():
|
||||
x = np.random.random((5, 5, 4))
|
||||
with expected_warnings(['Pass-through of possibly RGB images']):
|
||||
assert_equal(gray2rgb(x, alpha=None).shape, (5, 5, 4))
|
||||
with expected_warnings(['Pass-through of possibly RGB images',
|
||||
'alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(x, alpha=False).shape, (5, 5, 3))
|
||||
with expected_warnings(['Pass-through of possibly RGB images',
|
||||
'alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(x, alpha=True).shape, (5, 5, 4))
|
||||
|
||||
x = np.random.random((5, 5, 3))
|
||||
with expected_warnings(['Pass-through of possibly RGB images']):
|
||||
assert_equal(gray2rgb(x, alpha=None).shape, (5, 5, 3))
|
||||
with expected_warnings(['Pass-through of possibly RGB images',
|
||||
'alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(x, alpha=False).shape, (5, 5, 3))
|
||||
with expected_warnings(['Pass-through of possibly RGB images',
|
||||
'alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(x, alpha=True).shape, (5, 5, 4))
|
||||
|
||||
with expected_warnings(['alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(np.array([[1, 2], [3, 4.]]),
|
||||
alpha=True)[0, 0, 3], 1)
|
||||
with expected_warnings(['alpha argument is deprecated']):
|
||||
assert_equal(gray2rgb(np.array([[1, 2], [3, 4]], dtype=np.uint8),
|
||||
alpha=True)[0, 0, 3], 255)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("shape", [(5, 5), (5, 5, 4), (5, 4, 5, 4)])
|
||||
def test_gray2rgba(shape):
|
||||
# nD case
|
||||
img = np.random.random(shape)
|
||||
rgba = gray2rgba(img)
|
||||
|
||||
# Shape check
|
||||
assert_equal(rgba.shape, shape + (4, ))
|
||||
|
||||
# dtype check
|
||||
assert rgba.dtype == img.dtype
|
||||
|
||||
# RGB channels check
|
||||
for channel in range(3):
|
||||
assert_equal(rgba[..., channel], img)
|
||||
|
||||
# Alpha channel check
|
||||
assert_equal(rgba[..., 3], 1.0)
|
||||
|
||||
|
||||
def test_gray2rgba_dtype():
|
||||
img_f64 = np.random.random((5, 5))
|
||||
img_f32 = img_f64.astype('float32')
|
||||
img_u8 = img_as_ubyte(img_f64)
|
||||
img_int = img_u8.astype(int)
|
||||
|
||||
for img in [img_f64, img_f32, img_u8, img_int]:
|
||||
assert gray2rgba(img).dtype == img.dtype
|
||||
|
||||
|
||||
def test_gray2rgba_alpha():
|
||||
img = np.random.random((5, 5))
|
||||
img_u8 = img_as_ubyte(img)
|
||||
|
||||
# Default
|
||||
alpha = None
|
||||
rgba = gray2rgba(img, alpha)
|
||||
|
||||
assert_equal(rgba[..., :3], gray2rgb(img))
|
||||
assert_equal(rgba[..., 3], 1.0)
|
||||
|
||||
# Scalar
|
||||
alpha = 0.5
|
||||
rgba = gray2rgba(img, alpha)
|
||||
|
||||
assert_equal(rgba[..., :3], gray2rgb(img))
|
||||
assert_equal(rgba[..., 3], alpha)
|
||||
|
||||
# Array
|
||||
alpha = np.random.random((5, 5))
|
||||
rgba = gray2rgba(img, alpha)
|
||||
|
||||
assert_equal(rgba[..., :3], gray2rgb(img))
|
||||
assert_equal(rgba[..., 3], alpha)
|
||||
|
||||
# Warning about alpha cast
|
||||
alpha = 0.5
|
||||
with expected_warnings(["alpha can't be safely cast to image dtype"]):
|
||||
rgba = gray2rgba(img_u8, alpha)
|
||||
assert_equal(rgba[..., :3], gray2rgb(img_u8))
|
||||
|
||||
# Invalid shape
|
||||
alpha = np.random.random((5, 5, 1))
|
||||
expected_err_msg = ("could not broadcast input array from shape (5,5,1) "
|
||||
"into shape (5,5)")
|
||||
|
||||
with pytest.raises(ValueError) as err:
|
||||
rgba = gray2rgba(img, alpha)
|
||||
assert expected_err_msg == str(err.value)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("func", [rgb2gray, gray2rgb, gray2rgba])
|
||||
@pytest.mark.parametrize("shape", ([(3, ), (2, 3), (4, 5, 3), (5, 4, 5, 3),
|
||||
(4, 5, 4, 5, 3)]))
|
||||
def test_nD_gray_conversion(func, shape):
|
||||
img = np.random.rand(*shape)
|
||||
out = func(img)
|
||||
|
||||
msg_list = []
|
||||
if img.ndim == 3 and func == gray2rgb:
|
||||
msg_list.append('Pass-through of possibly RGB images in gray2rgb')
|
||||
elif img.ndim == 2 and func == rgb2gray:
|
||||
msg_list.append('The behavior of rgb2gray will change')
|
||||
|
||||
with expected_warnings(msg_list):
|
||||
out = func(img)
|
||||
|
||||
common_ndim = min(out.ndim, len(shape))
|
||||
|
||||
assert out.shape[:common_ndim] == shape[:common_ndim]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("func", [rgb2hsv, hsv2rgb,
|
||||
rgb2xyz, xyz2rgb,
|
||||
rgb2hed, hed2rgb,
|
||||
rgb2rgbcie, rgbcie2rgb,
|
||||
xyz2lab, lab2xyz,
|
||||
lab2rgb, rgb2lab,
|
||||
xyz2luv, luv2xyz,
|
||||
luv2rgb, rgb2luv,
|
||||
lab2lch, lch2lab,
|
||||
rgb2yuv, yuv2rgb,
|
||||
rgb2yiq, yiq2rgb,
|
||||
rgb2ypbpr, ypbpr2rgb,
|
||||
rgb2ycbcr, ycbcr2rgb,
|
||||
rgb2ydbdr, ydbdr2rgb])
|
||||
@pytest.mark.parametrize("shape", ([(3, ), (2, 3), (4, 5, 3), (5, 4, 5, 3),
|
||||
(4, 5, 4, 5, 3)]))
|
||||
def test_nD_color_conversion(func, shape):
|
||||
img = np.random.rand(*shape)
|
||||
out = func(img)
|
||||
|
||||
assert out.shape == img.shape
|
||||
|
||||
|
||||
@pytest.mark.parametrize("shape", ([(4, ), (2, 4), (4, 5, 4), (5, 4, 5, 4),
|
||||
(4, 5, 4, 5, 4)]))
|
||||
def test_rgba2rgb_nD(shape):
|
||||
img = np.random.rand(*shape)
|
||||
out = rgba2rgb(img)
|
||||
|
||||
expected_shape = shape[:-1] + (3, )
|
||||
|
||||
assert out.shape == expected_shape
|
200
venv/Lib/site-packages/skimage/color/tests/test_colorlabel.py
Normal file
|
@ -0,0 +1,200 @@
|
|||
import itertools
|
||||
import pytest
|
||||
|
||||
import numpy as np
|
||||
from skimage.color.colorlabel import label2rgb
|
||||
|
||||
from skimage._shared import testing
|
||||
from skimage._shared.testing import (assert_array_almost_equal,
|
||||
assert_array_equal, assert_warns)
|
||||
|
||||
|
||||
def test_deprecation_warning():
|
||||
|
||||
image = np.ones((3, 3))
|
||||
label = np.ones((3, 3))
|
||||
|
||||
with pytest.warns(FutureWarning) as record:
|
||||
label2rgb(image, label)
|
||||
|
||||
expected_msg = "The new recommended value"
|
||||
|
||||
assert str(record[0].message).startswith(expected_msg)
|
||||
|
||||
|
||||
def test_shape_mismatch():
|
||||
image = np.ones((3, 3))
|
||||
label = np.ones((2, 2))
|
||||
with testing.raises(ValueError):
|
||||
label2rgb(image, label, bg_label=-1)
|
||||
|
||||
|
||||
def test_wrong_kind():
|
||||
label = np.ones((3, 3))
|
||||
# Must not raise an error.
|
||||
label2rgb(label, bg_label=-1)
|
||||
# kind='foo' is wrong.
|
||||
with testing.raises(ValueError):
|
||||
label2rgb(label, kind='foo', bg_label=-1)
|
||||
|
||||
|
||||
def test_uint_image():
|
||||
img = np.random.randint(0, 255, (10, 10), dtype=np.uint8)
|
||||
labels = np.zeros((10, 10), dtype=np.int64)
|
||||
labels[1:3, 1:3]=1
|
||||
labels[6:9, 6:9] = 2
|
||||
output = label2rgb(labels, image=img, bg_label=0)
|
||||
# Make sure that the output is made of floats and in the correct range
|
||||
assert np.issubdtype(output.dtype, np.floating)
|
||||
assert output.max() <= 1
|
||||
|
||||
|
||||
def test_rgb():
|
||||
image = np.ones((1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# Set alphas just in case the defaults change
|
||||
rgb = label2rgb(label, image=image, colors=colors, alpha=1,
|
||||
image_alpha=1, bg_label=-1)
|
||||
assert_array_almost_equal(rgb, [colors])
|
||||
|
||||
|
||||
def test_alpha():
|
||||
image = np.random.uniform(size=(3, 3))
|
||||
label = np.random.randint(0, 9, size=(3, 3))
|
||||
# If we set `alpha = 0`, then rgb should match image exactly.
|
||||
rgb = label2rgb(label, image=image, alpha=0, image_alpha=1,
|
||||
bg_label=-1)
|
||||
assert_array_almost_equal(rgb[..., 0], image)
|
||||
assert_array_almost_equal(rgb[..., 1], image)
|
||||
assert_array_almost_equal(rgb[..., 2], image)
|
||||
|
||||
|
||||
def test_no_input_image():
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
rgb = label2rgb(label, colors=colors, bg_label=-1)
|
||||
assert_array_almost_equal(rgb, [colors])
|
||||
|
||||
|
||||
def test_image_alpha():
|
||||
image = np.random.uniform(size=(1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# If we set `image_alpha = 0`, then rgb should match label colors exactly.
|
||||
rgb = label2rgb(label, image=image, colors=colors, alpha=1,
|
||||
image_alpha=0, bg_label=-1)
|
||||
assert_array_almost_equal(rgb, [colors])
|
||||
|
||||
|
||||
def test_color_names():
|
||||
image = np.ones((1, 3))
|
||||
label = np.arange(3).reshape(1, -1)
|
||||
cnames = ['red', 'lime', 'blue']
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
|
||||
# Set alphas just in case the defaults change
|
||||
rgb = label2rgb(label, image=image, colors=cnames, alpha=1,
|
||||
image_alpha=1, bg_label=-1)
|
||||
assert_array_almost_equal(rgb, [colors])
|
||||
|
||||
|
||||
def test_bg_and_color_cycle():
|
||||
image = np.zeros((1, 10)) # dummy image
|
||||
label = np.arange(10).reshape(1, -1)
|
||||
colors = [(1, 0, 0), (0, 0, 1)]
|
||||
bg_color = (0, 0, 0)
|
||||
rgb = label2rgb(label, image=image, bg_label=0, bg_color=bg_color,
|
||||
colors=colors, alpha=1)
|
||||
assert_array_almost_equal(rgb[0, 0], bg_color)
|
||||
for pixel, color in zip(rgb[0, 1:], itertools.cycle(colors)):
|
||||
assert_array_almost_equal(pixel, color)
|
||||
|
||||
|
||||
def test_negative_labels():
|
||||
labels = np.array([0, -1, -2, 0])
|
||||
rout = np.array([(0., 0., 0.), (0., 0., 1.), (1., 0., 0.), (0., 0., 0.)])
|
||||
assert_array_almost_equal(
|
||||
rout, label2rgb(labels, bg_label=0, alpha=1, image_alpha=1))
|
||||
|
||||
|
||||
def test_nonconsecutive():
|
||||
labels = np.array([0, 2, 4, 0])
|
||||
colors = [(1, 0, 0), (0, 0, 1)]
|
||||
rout = np.array([(1., 0., 0.), (0., 0., 1.), (1., 0., 0.), (1., 0., 0.)])
|
||||
assert_array_almost_equal(
|
||||
rout, label2rgb(labels, colors=colors, alpha=1,
|
||||
image_alpha=1, bg_label=-1))
|
||||
|
||||
|
||||
def test_label_consistency():
|
||||
"""Assert that the same labels map to the same colors."""
|
||||
label_1 = np.arange(5).reshape(1, -1)
|
||||
label_2 = np.array([0, 1])
|
||||
colors = [(1, 0, 0), (0, 1, 0), (0, 0, 1), (1, 1, 0), (1, 0, 1)]
|
||||
# Set alphas just in case the defaults change
|
||||
rgb_1 = label2rgb(label_1, colors=colors, bg_label=-1)
|
||||
rgb_2 = label2rgb(label_2, colors=colors, bg_label=-1)
|
||||
for label_id in label_2.flat:
|
||||
assert_array_almost_equal(rgb_1[label_1 == label_id],
|
||||
rgb_2[label_2 == label_id])
|
||||
|
||||
|
||||
def test_leave_labels_alone():
|
||||
labels = np.array([-1, 0, 1])
|
||||
labels_saved = labels.copy()
|
||||
|
||||
label2rgb(labels, bg_label=-1)
|
||||
label2rgb(labels, bg_label=1)
|
||||
assert_array_equal(labels, labels_saved)
|
||||
|
||||
|
||||
def test_avg():
|
||||
# label image
|
||||
label_field = np.array([[1, 1, 1, 2],
|
||||
[1, 2, 2, 2],
|
||||
[3, 3, 4, 4]], dtype=np.uint8)
|
||||
|
||||
# color image
|
||||
r = np.array([[1., 1., 0., 0.],
|
||||
[0., 0., 1., 1.],
|
||||
[0., 0., 0., 0.]])
|
||||
g = np.array([[0., 0., 0., 1.],
|
||||
[1., 1., 1., 0.],
|
||||
[0., 0., 0., 0.]])
|
||||
b = np.array([[0., 0., 0., 1.],
|
||||
[0., 1., 1., 1.],
|
||||
[0., 0., 1., 1.]])
|
||||
image = np.dstack((r, g, b))
|
||||
|
||||
# reference label-colored image
|
||||
rout = np.array([[0.5, 0.5, 0.5, 0.5],
|
||||
[0.5, 0.5, 0.5, 0.5],
|
||||
[0. , 0. , 0. , 0. ]])
|
||||
gout = np.array([[0.25, 0.25, 0.25, 0.75],
|
||||
[0.25, 0.75, 0.75, 0.75],
|
||||
[0. , 0. , 0. , 0. ]])
|
||||
bout = np.array([[0. , 0. , 0. , 1. ],
|
||||
[0. , 1. , 1. , 1. ],
|
||||
[0.0, 0.0, 1.0, 1.0]])
|
||||
expected_out = np.dstack((rout, gout, bout))
|
||||
|
||||
# test standard averaging
|
||||
out = label2rgb(label_field, image, kind='avg', bg_label=-1)
|
||||
assert_array_equal(out, expected_out)
|
||||
|
||||
# test averaging with custom background value
|
||||
out_bg = label2rgb(label_field, image, bg_label=2, bg_color=(0, 0, 0),
|
||||
kind='avg')
|
||||
expected_out_bg = expected_out.copy()
|
||||
expected_out_bg[label_field == 2] = 0
|
||||
assert_array_equal(out_bg, expected_out_bg)
|
||||
|
||||
# test default background color
|
||||
out_bg = label2rgb(label_field, image, bg_label=2, kind='avg')
|
||||
assert_array_equal(out_bg, expected_out_bg)
|
||||
|
||||
|
||||
def test_negative_intensity():
|
||||
labels = np.arange(100).reshape(10, 10)
|
||||
image = np.full((10, 10), -1, dtype='float64')
|
||||
assert_warns(UserWarning, label2rgb, labels, image, bg_label=-1)
|
179
venv/Lib/site-packages/skimage/color/tests/test_delta_e.py
Normal file
|
@ -0,0 +1,179 @@
|
|||
"""Test for correctness of color distance functions"""
|
||||
from os.path import abspath, dirname, join as pjoin
|
||||
|
||||
import numpy as np
|
||||
from skimage._shared.testing import (
|
||||
assert_allclose, assert_equal, assert_almost_equal, fetch
|
||||
)
|
||||
from skimage.color.delta_e import (
|
||||
deltaE_cie76, deltaE_ciede94, deltaE_ciede2000, deltaE_cmc
|
||||
)
|
||||
|
||||
|
||||
def test_ciede2000_dE():
|
||||
data = load_ciede2000_data()
|
||||
N = len(data)
|
||||
lab1 = np.zeros((N, 3))
|
||||
lab1[:, 0] = data['L1']
|
||||
lab1[:, 1] = data['a1']
|
||||
lab1[:, 2] = data['b1']
|
||||
|
||||
lab2 = np.zeros((N, 3))
|
||||
lab2[:, 0] = data['L2']
|
||||
lab2[:, 1] = data['a2']
|
||||
lab2[:, 2] = data['b2']
|
||||
|
||||
dE2 = deltaE_ciede2000(lab1, lab2)
|
||||
|
||||
assert_allclose(dE2, data['dE'], rtol=1.e-4)
|
||||
|
||||
|
||||
def load_ciede2000_data():
|
||||
dtype = [('pair', int),
|
||||
('1', int),
|
||||
('L1', float),
|
||||
('a1', float),
|
||||
('b1', float),
|
||||
('a1_prime', float),
|
||||
('C1_prime', float),
|
||||
('h1_prime', float),
|
||||
('hbar_prime', float),
|
||||
('G', float),
|
||||
('T', float),
|
||||
('SL', float),
|
||||
('SC', float),
|
||||
('SH', float),
|
||||
('RT', float),
|
||||
('dE', float),
|
||||
('2', int),
|
||||
('L2', float),
|
||||
('a2', float),
|
||||
('b2', float),
|
||||
('a2_prime', float),
|
||||
('C2_prime', float),
|
||||
('h2_prime', float),
|
||||
]
|
||||
|
||||
# note: ciede_test_data.txt contains several intermediate quantities
|
||||
path = fetch('color/tests/ciede2000_test_data.txt')
|
||||
return np.loadtxt(path, dtype=dtype)
|
||||
|
||||
|
||||
def test_cie76():
|
||||
data = load_ciede2000_data()
|
||||
N = len(data)
|
||||
lab1 = np.zeros((N, 3))
|
||||
lab1[:, 0] = data['L1']
|
||||
lab1[:, 1] = data['a1']
|
||||
lab1[:, 2] = data['b1']
|
||||
|
||||
lab2 = np.zeros((N, 3))
|
||||
lab2[:, 0] = data['L2']
|
||||
lab2[:, 1] = data['a2']
|
||||
lab2[:, 2] = data['b2']
|
||||
|
||||
dE2 = deltaE_cie76(lab1, lab2)
|
||||
oracle = np.array([
|
||||
4.00106328, 6.31415011, 9.1776999, 2.06270077, 2.36957073,
|
||||
2.91529271, 2.23606798, 2.23606798, 4.98000036, 4.9800004,
|
||||
4.98000044, 4.98000049, 4.98000036, 4.9800004, 4.98000044,
|
||||
3.53553391, 36.86800781, 31.91002977, 30.25309901, 27.40894015,
|
||||
0.89242934, 0.7972, 0.8583065, 0.82982507, 3.1819238,
|
||||
2.21334297, 1.53890382, 4.60630929, 6.58467989, 3.88641412,
|
||||
1.50514845, 2.3237848, 0.94413208, 1.31910843
|
||||
])
|
||||
assert_allclose(dE2, oracle, rtol=1.e-8)
|
||||
|
||||
|
||||
def test_ciede94():
|
||||
data = load_ciede2000_data()
|
||||
N = len(data)
|
||||
lab1 = np.zeros((N, 3))
|
||||
lab1[:, 0] = data['L1']
|
||||
lab1[:, 1] = data['a1']
|
||||
lab1[:, 2] = data['b1']
|
||||
|
||||
lab2 = np.zeros((N, 3))
|
||||
lab2[:, 0] = data['L2']
|
||||
lab2[:, 1] = data['a2']
|
||||
lab2[:, 2] = data['b2']
|
||||
|
||||
dE2 = deltaE_ciede94(lab1, lab2)
|
||||
oracle = np.array([
|
||||
1.39503887, 1.93410055, 2.45433566, 0.68449187, 0.6695627,
|
||||
0.69194527, 2.23606798, 2.03163832, 4.80069441, 4.80069445,
|
||||
4.80069449, 4.80069453, 4.80069441, 4.80069445, 4.80069449,
|
||||
3.40774352, 34.6891632, 29.44137328, 27.91408781, 24.93766082,
|
||||
0.82213163, 0.71658427, 0.8048753, 0.75284394, 1.39099471,
|
||||
1.24808929, 1.29795787, 1.82045088, 2.55613309, 1.42491303,
|
||||
1.41945261, 2.3225685, 0.93853308, 1.30654464
|
||||
])
|
||||
assert_allclose(dE2, oracle, rtol=1.e-8)
|
||||
|
||||
|
||||
def test_cmc():
|
||||
data = load_ciede2000_data()
|
||||
N = len(data)
|
||||
lab1 = np.zeros((N, 3))
|
||||
lab1[:, 0] = data['L1']
|
||||
lab1[:, 1] = data['a1']
|
||||
lab1[:, 2] = data['b1']
|
||||
|
||||
lab2 = np.zeros((N, 3))
|
||||
lab2[:, 0] = data['L2']
|
||||
lab2[:, 1] = data['a2']
|
||||
lab2[:, 2] = data['b2']
|
||||
|
||||
dE2 = deltaE_cmc(lab1, lab2)
|
||||
oracle = np.array([
|
||||
1.73873611, 2.49660844, 3.30494501, 0.85735576, 0.88332927,
|
||||
0.97822692, 3.50480874, 2.87930032, 6.5783807, 6.57838075,
|
||||
6.5783808, 6.57838086, 6.67492321, 6.67492326, 6.67492331,
|
||||
4.66852997, 42.10875485, 39.45889064, 38.36005919, 33.93663807,
|
||||
1.14400168, 1.00600419, 1.11302547, 1.05335328, 1.42822951,
|
||||
1.2548143, 1.76838061, 2.02583367, 3.08695508, 1.74893533,
|
||||
1.90095165, 1.70258148, 1.80317207, 2.44934417
|
||||
])
|
||||
|
||||
assert_allclose(dE2, oracle, rtol=1.e-8)
|
||||
|
||||
# Equal or close colors make `delta_e.get_dH2` function to return
|
||||
# negative values resulting in NaNs when passed to sqrt (see #1908
|
||||
# issue on Github):
|
||||
lab1 = lab2
|
||||
expected = np.zeros_like(oracle)
|
||||
assert_almost_equal(deltaE_cmc(lab1, lab2), expected, decimal=6)
|
||||
|
||||
lab2[0, 0] += np.finfo(float).eps
|
||||
assert_almost_equal(deltaE_cmc(lab1, lab2), expected, decimal=6)
|
||||
|
||||
# Single item case:
|
||||
lab1 = lab2 = np.array([0., 1.59607713, 0.87755709])
|
||||
assert_equal(deltaE_cmc(lab1, lab2), 0)
|
||||
|
||||
lab2[0] += np.finfo(float).eps
|
||||
assert_equal(deltaE_cmc(lab1, lab2), 0)
|
||||
|
||||
|
||||
def test_single_color_cie76():
|
||||
lab1 = (0.5, 0.5, 0.5)
|
||||
lab2 = (0.4, 0.4, 0.4)
|
||||
deltaE_cie76(lab1, lab2)
|
||||
|
||||
|
||||
def test_single_color_ciede94():
|
||||
lab1 = (0.5, 0.5, 0.5)
|
||||
lab2 = (0.4, 0.4, 0.4)
|
||||
deltaE_ciede94(lab1, lab2)
|
||||
|
||||
|
||||
def test_single_color_ciede2000():
|
||||
lab1 = (0.5, 0.5, 0.5)
|
||||
lab2 = (0.4, 0.4, 0.4)
|
||||
deltaE_ciede2000(lab1, lab2)
|
||||
|
||||
|
||||
def test_single_color_cmc():
|
||||
lab1 = (0.5, 0.5, 0.5)
|
||||
lab2 = (0.4, 0.4, 0.4)
|
||||
deltaE_cmc(lab1, lab2)
|
6
venv/Lib/site-packages/skimage/conftest.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
# List of files that pytest should ignore
|
||||
collect_ignore = ["io/_plugins",]
|
||||
try:
|
||||
import visvis
|
||||
except ImportError:
|
||||
collect_ignore.append("measure/mc_meta/visual_test.py")
|
9
venv/Lib/site-packages/skimage/data/README.txt
Normal file
|
@ -0,0 +1,9 @@
|
|||
This directory contains sample data from scikit-image.
|
||||
|
||||
By default, it only contains a small subset of the entire dataset.
|
||||
|
||||
The full detaset can be downloaded by using the following commands from
|
||||
a python console.
|
||||
|
||||
>>> from skimage.data import download_all
|
||||
>>> download_all()
|
1010
venv/Lib/site-packages/skimage/data/__init__.py
Normal file
57
venv/Lib/site-packages/skimage/data/_binary_blobs.py
Normal file
|
@ -0,0 +1,57 @@
|
|||
import numpy as np
|
||||
|
||||
|
||||
def binary_blobs(length=512, blob_size_fraction=0.1, n_dim=2,
|
||||
volume_fraction=0.5, seed=None):
|
||||
"""
|
||||
Generate synthetic binary image with several rounded blob-like objects.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
length : int, optional
|
||||
Linear size of output image.
|
||||
blob_size_fraction : float, optional
|
||||
Typical linear size of blob, as a fraction of ``length``, should be
|
||||
smaller than 1.
|
||||
n_dim : int, optional
|
||||
Number of dimensions of output image.
|
||||
volume_fraction : float, default 0.5
|
||||
Fraction of image pixels covered by the blobs (where the output is 1).
|
||||
Should be in [0, 1].
|
||||
seed : int, optional
|
||||
Seed to initialize the random number generator.
|
||||
If `None`, a random seed from the operating system is used.
|
||||
|
||||
Returns
|
||||
-------
|
||||
blobs : ndarray of bools
|
||||
Output binary image
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> from skimage import data
|
||||
>>> data.binary_blobs(length=5, blob_size_fraction=0.2, seed=1)
|
||||
array([[ True, False, True, True, True],
|
||||
[ True, True, True, False, True],
|
||||
[False, True, False, True, True],
|
||||
[ True, False, False, True, True],
|
||||
[ True, False, False, False, True]])
|
||||
>>> blobs = data.binary_blobs(length=256, blob_size_fraction=0.1)
|
||||
>>> # Finer structures
|
||||
>>> blobs = data.binary_blobs(length=256, blob_size_fraction=0.05)
|
||||
>>> # Blobs cover a smaller volume fraction of the image
|
||||
>>> blobs = data.binary_blobs(length=256, volume_fraction=0.3)
|
||||
"""
|
||||
# filters is quite an expensive import since it imports all of scipy.signal
|
||||
# We lazy import here
|
||||
from ..filters import gaussian
|
||||
|
||||
rs = np.random.RandomState(seed)
|
||||
shape = tuple([length] * n_dim)
|
||||
mask = np.zeros(shape)
|
||||
n_pts = max(int(1. / blob_size_fraction) ** n_dim, 1)
|
||||
points = (length * rs.rand(n_dim, n_pts)).astype(np.int)
|
||||
mask[tuple(indices for indices in points)] = 1
|
||||
mask = gaussian(mask, sigma=0.25 * length * blob_size_fraction)
|
||||
threshold = np.percentile(mask, 100 * (1 - volume_fraction))
|
||||
return np.logical_not(mask < threshold)
|
139
venv/Lib/site-packages/skimage/data/_registry.py
Normal file
|
@ -0,0 +1,139 @@
|
|||
# flake8: noqa
|
||||
|
||||
# This minimal dataset was available as part of
|
||||
# scikit-image 0.15 and will be retained until
|
||||
# further notice.
|
||||
# Testing data and additional datasets should only
|
||||
# be made available by pooch
|
||||
legacy_datasets = [
|
||||
'astronaut.png',
|
||||
'brick.png',
|
||||
'camera.png',
|
||||
'chessboard_GRAY.png',
|
||||
'chessboard_RGB.png',
|
||||
'chelsea.png',
|
||||
'clock_motion.png',
|
||||
'coffee.png',
|
||||
'coins.png',
|
||||
'color.png',
|
||||
'cell.png',
|
||||
'grass.png',
|
||||
'gravel.png',
|
||||
'horse.png',
|
||||
'hubble_deep_field.jpg',
|
||||
'ihc.png',
|
||||
'lbpcascade_frontalface_opencv.xml',
|
||||
'lfw_subset.npy',
|
||||
'logo.png',
|
||||
'microaneurysms.png',
|
||||
'moon.png',
|
||||
'page.png',
|
||||
'text.png',
|
||||
'retina.jpg',
|
||||
'rocket.jpg',
|
||||
'phantom.png',
|
||||
'motorcycle_disp.npz',
|
||||
'motorcycle_left.png',
|
||||
'motorcycle_right.png',
|
||||
]
|
||||
|
||||
# Registry of datafiles that can be downloaded along with their SHA256 hashes
|
||||
# To generate the SHA256 hash, use the command
|
||||
# openssl sha256 filename
|
||||
registry = {
|
||||
"color/tests/data/lab_array_a_2.npy": "793d5981cbffceb14b5fb589f998a2b1acdb5ff9c14d364c8e9e8bd45a80b275",
|
||||
"color/tests/data/lab_array_d50_10.npy": "42e2ff26cb10e2a98fcf1bc06c2483302ff4fabf971fe8d49b530f490b5d24c7",
|
||||
"color/tests/data/lab_array_d50_2.npy": "4aa03b7018ff7276643d3c082123cf07304f9d8d898ae92a5756a86955de4faf",
|
||||
"color/tests/data/lab_array_d55_10.npy": "ab4f21368b6d8351578ab093381c44b49ae87a6b7f25c11aa094b07f215eed7d",
|
||||
"color/tests/data/lab_array_d55_2.npy": "0319723de4632a252bae828b7c96d038fb075a7df05beadfbad653da05efe372",
|
||||
"color/tests/data/lab_array_d65_10.npy": "5cb9e9c384d2577aaf8b7d2d21ff5b505708b80605a2f59d10e89d22c3d308d2",
|
||||
"color/tests/data/lab_array_d65_2.npy": "16e847160f7ba4f19806d8194ed44a6654c9367e5a2cb240aa6e7eece44a6649",
|
||||
"color/tests/data/lab_array_d75_10.npy": "c2d3de5422c785c925926b0c6223aeaf50b9393619d1c30830190d433606cbe1",
|
||||
"color/tests/data/lab_array_d75_2.npy": "c94d53da398d36e076471ff7e0dafcaffc64ce4ba33b4d04849c32d19c87494a",
|
||||
"color/tests/data/lab_array_e_2.npy": "ac05f17a83961b020ceccbdd46bddc86943d43e678dabcc898caf4a1e4be6165",
|
||||
"color/tests/data/luv_array_a_2.npy": "eaf05dc61f4a70ece367d5e751a14d42b7c397c7b1c2df4cfecec9ddf26e1c1a",
|
||||
"color/tests/data/luv_array_d50_10.npy": "fe223db556222ce3a59198bed3a3324c2c719b8083fb84dc5b00f214b4773b16",
|
||||
"color/tests/data/luv_array_d50_2.npy": "48e8989048904bdf2c3c1ada265c1c29c5eff60f02f848a25cde622982c84901",
|
||||
"color/tests/data/luv_array_d55_10.npy": "d88d53d2bad230c2331442187712ec52ffdee62bf0f60b200c33411bfed76c60",
|
||||
"color/tests/data/luv_array_d55_2.npy": "c761b40475df591ae9c0475d54ef712d067190ca4652efc6308b69080a652061",
|
||||
"color/tests/data/luv_array_d65_10.npy": "41a5452ffac4d31dd579d9528e725432c60d77b5f505d801898d9401429c89bf",
|
||||
"color/tests/data/luv_array_d65_2.npy": "962ce180132c6c11798cbc423b2b204d1d10187670f6eb5dec1058eaad301e0e",
|
||||
"color/tests/data/luv_array_d75_10.npy": "e1cc70d56eb6789633d4c2a4059b9533f616a7c8592c9bd342403e41d72f45e4",
|
||||
"color/tests/data/luv_array_d75_2.npy": "07db3bd59bd89de8e5ff62dad786fe5f4b299133495ba9bea30495b375133a98",
|
||||
"color/tests/data/luv_array_e_2.npy": "41b1037d81b267305ffe9e8e97e0affa9fa54b18e60413b01b8f11861cb32213",
|
||||
"color/tests/ciede2000_test_data.txt": "2e005c6f76ddfb7bbcc8f68490f1f7b4b4a2a4b06b36a80c985677a2799c0e40",
|
||||
"data/astronaut.png": "88431cd9653ccd539741b555fb0a46b61558b301d4110412b5bc28b5e3ea6cb5",
|
||||
"data/brick.png": "7966caf324f6ba843118d98f7a07746d22f6a343430add0233eca5f6eaaa8fcf",
|
||||
"data/cell.png": "8d23a7fb81f7cc877cd09f330357fc7f595651306e84e17252f6e0a1b3f61515",
|
||||
"data/camera.png": "361a6d56d22ee52289cd308d5461d090e06a56cb36007d8dfc3226cbe8aaa5db",
|
||||
"data/chessboard_GRAY.png": "3e51870774515af4d07d820bd8827364c70839bf9b573c746e485095e893df90",
|
||||
"data/chessboard_RGB.png": "1ac01eff2d4e50f4eda55a2ddecdc28a6576623a58d7a7ef84513c5cc19a0331",
|
||||
"data/chelsea.png": "596aa1e7cb875eb79f437e310381d26b338a81c2da23439704a73c4651e8c4bb",
|
||||
"data/clock_motion.png": "f029226b28b642e80113d86622e9b215ee067a0966feaf5e60604a1e05733955",
|
||||
"data/coffee.png": "cc02f8ca188b167c775a7101b5d767d1e71792cf762c33d6fa15a4599b5a8de7",
|
||||
"data/coins.png": "f8d773fc9cfa6f4d8e5942dc34d0a0788fcaed2a4fefbbed0aef5398d7ef4cba",
|
||||
"data/color.png": "7d2df993de2b4fa2a78e04e5df8050f49a9c511aa75e59ab3bd56ac9c98aef7e",
|
||||
"data/horse.png": "c7fb60789fe394c485f842291ea3b21e50d140f39d6dcb5fb9917cc178225455",
|
||||
"data/grass.png": "b6b6022426b38936c43a4ac09635cd78af074e90f42ffa8227ac8b7452d39f89",
|
||||
"data/hubble_deep_field.jpg": "3a19c5dd8a927a9334bb1229a6d63711b1c0c767fb27e2286e7c84a3e2c2f5f4",
|
||||
"data/ihc.png": "f8dd1aa387ddd1f49d8ad13b50921b237df8e9b262606d258770687b0ef93cef",
|
||||
"data/logo.png": "f2c57fe8af089f08b5ba523d95573c26e62904ac5967f4c8851b27d033690168",
|
||||
"data/lfw_subset.npy": "9560ec2f5edfac01973f63a8a99d00053fecd11e21877e18038fbe500f8e872c",
|
||||
"data/microaneurysms.png": "a1e1be59aa447f8ce082f7fa809997ab369a2b137cb6c4202abc647c7ccf6456",
|
||||
"data/moon.png": "78739619d11f7eb9c165bb5d2efd4772cee557812ec847532dbb1d92ef71f577",
|
||||
"data/motorcycle_left.png": "db18e9c4157617403c3537a6ba355dfeafe9a7eabb6b9b94cb33f6525dd49179",
|
||||
"data/motorcycle_right.png": "5fc913ae870e42a4b662314bc904d1786bcad8e2f0b9b67dba5a229406357797",
|
||||
"data/motorcycle_disp.npz": "2e49c8cebff3fa20359a0cc6880c82e1c03bbb106da81a177218281bc2f113d7",
|
||||
"data/mssim_matlab_output.npz": "cc11a14bfa040c75b02db32282439f2e2e3e96779196c171498afaa70528ed7a",
|
||||
"data/page.png": "341a6f0a61557662b02734a9b6e56ec33a915b2c41886b97509dedf2a43b47a3",
|
||||
"data/phantom.png": "552ff698167aa402cceb17981130607a228a0a0aa7c519299eaa4d5f301ba36c",
|
||||
"data/retina.jpg": "38a07f36f27f095e818aea7b96d34202c05176d30253c66733f2e00379e9e0e6",
|
||||
"data/rocket.jpg": "c2dd0de7c538df8d111e479619b129464d0269d0ae5fd18ca91d33a7fdfea95c",
|
||||
"data/gravel.png": "c48615b451bf1e606fbd72c0aa9f8cc0f068ab7111ef7d93bb9b0f2586440c12",
|
||||
"data/text.png": "bd84aa3a6e3c9887850d45d606c96b2e59433fbef50338570b63c319e668e6d1",
|
||||
"data/chessboard_GRAY_U16.tif": "9fd3392c5b6cbc5f686d8ff83eb57ef91d038ee0852ac26817e5ac99df4c7f45",
|
||||
"data/chessboard_GRAY_U16B.tif": "b0a9270751f0fc340c90b8b615b62b88187b9ab5995942717566735d523cddb2",
|
||||
"data/chessboard_GRAY_U8.npy": "71f394694b721e8a33760a355b3666c9b7d7fc1188ff96b3cd23c2a1d73a38d8",
|
||||
"data/lbpcascade_frontalface_opencv.xml": "03097789a3dcbb0e40d20b9ef82537dbc3b670b6a7f2268d735470f22e003a91",
|
||||
"data/astronaut_GRAY_hog_L1.npy": "5d8ab22b166d1dd49c12caeff9d178ed28132efea3852b952e9d75f7f7f94954",
|
||||
"data/astronaut_GRAY_hog_L2-Hys.npy": "c4dd6e50d1129aada358311cf8880ce8c775f31e0e550fc322c16e43a96d56fe",
|
||||
"data/rank_filter_tests.npz": "efaf5699630f4a53255e91681dc72a965acd4a8aa1f84671c686fb93e7df046d",
|
||||
"data/multi.fits": "5c71a83436762a52b1925f2f0d83881af7765ed50aede155af2800e54bbd5040",
|
||||
"data/simple.fits": "cd36087fdbb909b6ba506bbff6bcd4c5f4da3a41862608fbac5e8555ef53d40f",
|
||||
"data/palette_color.png": "c4e817035fb9f7730fe95cff1da3866dea01728efc72b6e703d78f7ab9717bdd",
|
||||
"data/palette_gray.png": "bace7f73783bf3ab3b7fdaf701707e4fa09f0dbd0ea72cf5b12ddc73d50b02a9",
|
||||
"data/green_palette.png": "42d49d94be8f9bc76e50639d3701ed0484258721f6b0bd7f50bb1b9274a010f0",
|
||||
"data/truncated.jpg": "4c226038acc78012d335efba29c6119a24444a886842182b7e18db378f4a557d",
|
||||
"data/multipage.tif": "4da0ad0d3df4807a9847247d1b5e565b50d46481f643afb5c37c14802c78130f",
|
||||
"data/multipage_rgb.tif": "1d23b844fd38dce0e2d06f30432817cdb85e52070d8f5460a2ba58aebf34a0de",
|
||||
"data/no_time_for_that_tiny.gif": "20abe94ba9e45f18de416c5fbef8d1f57a499600be40f9a200fae246010eefce",
|
||||
"data/foo3x5x4indexed.png": "48a64c25c6da000ffdb5fcc34ebafe9ba3b1c9b61d7984ea7ca6dc54f9312dfa",
|
||||
"data/mssim_matlab_output.npz": "cc11a14bfa040c75b02db32282439f2e2e3e96779196c171498afaa70528ed7a",
|
||||
"data/gray_morph_output.npz": "3012eb994e864e1dca1f66fada6b4375f84eac63658d049886b710488c2394d1",
|
||||
"data/disk-matlab-output.npz": "8a39d5c866f6216d6a9c9166312aa4bbf4d18fab3d0dcd963c024985bde5856b",
|
||||
"data/diamond-matlab-output.npz": "02fca68907e2b252b501dfe977eef71ae39fadaaa3702ebdc855195422ae1cc2",
|
||||
"data/bw_text.png": "308c2b09f8975a69b212e103b18520e8cbb7a4eccfce0f757836cd371f1b9094",
|
||||
"data/bw_text_skeleton.npy": "9ff4fc23c6a01497d7987f14e3a97cbcc39cce54b2b3b7ee33b84c1b661d0ae1",
|
||||
"data/_blobs_3d_fiji_skeleton.tif": "5182a2a94f240528985b8d15ec2aebbd5ca3c6b9214beff1eb6099c431e12b7b",
|
||||
"data/checker_bilevel.png": "2e207e486545874a2a3e69ba653b28fdef923157be9017559540e65d1bcb8e28",
|
||||
"restoration/tests/camera_rl.npy": "d219834415dc7094580abd975abb28bc7a6fb5ab83366e92c61ccffa66ca54fd",
|
||||
"restoration/tests/camera_unsup.npy": "6d911fd0028ee78add8c416553097f15c6c4e59723ea32bd828f71269b6ea240",
|
||||
"restoration/tests/camera_unsup2.npy": "30e81718f3cac0fc00d84518ca75a3c0fb9b246bb7748a9e20ec0b44da33734d",
|
||||
"restoration/tests/camera_wiener.npy": "71e7cab739d6d145a288ec85dd235a62ff34442ccd1488b08139bc809850772b",
|
||||
"registration/tests/data/OriginalX-130Y130.png": "bf24a06d99ae131c97e582ef5e1cd0c648a8dad0caab31281f3564045492811f",
|
||||
"registration/tests/data/OriginalX130Y130.png": "7fdd4c06d504fec35ee0703bd7ed2c08830b075a74c8506bae4a70d682f5a2db",
|
||||
"registration/tests/data/OriginalX75Y75.png": "c5cd58893c93140df02896df80b13ecf432f5c86eeaaf8fb311aec52a65c7016",
|
||||
"registration/tests/data/TransformedX-130Y130.png": "1cda90ed69c921eb7605b73b76d141cf4ea03fb8ce3336445ca08080e40d7375",
|
||||
"registration/tests/data/TransformedX130Y130.png": "bb10c6ae3f91a313b0ac543efdb7ca69c4b95e55674c65a88472a6c4f4692a25",
|
||||
"registration/tests/data/TransformedX75Y75.png": "a1e9ead5f8e4a0f604271e1f9c50e89baf53f068f1d19fab2876af4938e695ea",
|
||||
"data/cells.tif": "2120cfe08e0396324793a10a905c9bbcb64b117215eb63b2c24b643e1600c8c9",
|
||||
}
|
||||
|
||||
registry_urls = {
|
||||
"data/cells.tif": "https://github.com/scikit-image/skimage-tutorials/raw/master/images/cells.tif",
|
||||
}
|
||||
|
||||
legacy_registry = {
|
||||
('data/' + filename): registry['data/' + filename]
|
||||
for filename in legacy_datasets
|
||||
}
|
BIN
venv/Lib/site-packages/skimage/data/astronaut.png
Normal file
After Width: | Height: | Size: 773 KiB |
BIN
venv/Lib/site-packages/skimage/data/brick.png
Normal file
After Width: | Height: | Size: 104 KiB |
BIN
venv/Lib/site-packages/skimage/data/camera.png
Normal file
After Width: | Height: | Size: 112 KiB |
BIN
venv/Lib/site-packages/skimage/data/cell.png
Normal file
After Width: | Height: | Size: 72 KiB |
BIN
venv/Lib/site-packages/skimage/data/chelsea.png
Normal file
After Width: | Height: | Size: 235 KiB |
BIN
venv/Lib/site-packages/skimage/data/chessboard_GRAY.png
Normal file
After Width: | Height: | Size: 418 B |
BIN
venv/Lib/site-packages/skimage/data/chessboard_RGB.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
venv/Lib/site-packages/skimage/data/clock_motion.png
Normal file
After Width: | Height: | Size: 57 KiB |
BIN
venv/Lib/site-packages/skimage/data/coffee.png
Normal file
After Width: | Height: | Size: 456 KiB |
BIN
venv/Lib/site-packages/skimage/data/coins.png
Normal file
After Width: | Height: | Size: 74 KiB |
BIN
venv/Lib/site-packages/skimage/data/color.png
Normal file
After Width: | Height: | Size: 84 KiB |
BIN
venv/Lib/site-packages/skimage/data/grass.png
Normal file
After Width: | Height: | Size: 213 KiB |
BIN
venv/Lib/site-packages/skimage/data/gravel.png
Normal file
After Width: | Height: | Size: 190 KiB |
BIN
venv/Lib/site-packages/skimage/data/horse.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
venv/Lib/site-packages/skimage/data/hubble_deep_field.jpg
Normal file
After Width: | Height: | Size: 516 KiB |
BIN
venv/Lib/site-packages/skimage/data/ihc.png
Normal file
After Width: | Height: | Size: 467 KiB |
BIN
venv/Lib/site-packages/skimage/data/lfw_subset.npy
Normal file
BIN
venv/Lib/site-packages/skimage/data/logo.png
Normal file
After Width: | Height: | Size: 176 KiB |
BIN
venv/Lib/site-packages/skimage/data/microaneurysms.png
Normal file
After Width: | Height: | Size: 4.8 KiB |
BIN
venv/Lib/site-packages/skimage/data/moon.png
Normal file
After Width: | Height: | Size: 49 KiB |
BIN
venv/Lib/site-packages/skimage/data/motorcycle_disp.npz
Normal file
BIN
venv/Lib/site-packages/skimage/data/motorcycle_left.png
Normal file
After Width: | Height: | Size: 630 KiB |