mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-08 11:26:12 +08:00
Merge pull request #1412 from blink1073/contrast-check-function
Add a function to check whether an image is low contrast for its data type.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
from .exposure import histogram, equalize_hist, \
|
||||
rescale_intensity, cumulative_distribution, \
|
||||
adjust_gamma, adjust_sigmoid, adjust_log
|
||||
adjust_gamma, adjust_sigmoid, adjust_log, \
|
||||
is_low_contrast
|
||||
|
||||
from ._adapthist import equalize_adapthist
|
||||
|
||||
@@ -12,4 +13,5 @@ __all__ = ['histogram',
|
||||
'cumulative_distribution',
|
||||
'adjust_gamma',
|
||||
'adjust_sigmoid',
|
||||
'adjust_log']
|
||||
'adjust_log',
|
||||
'is_low_contrast']
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
from __future__ import division
|
||||
import warnings
|
||||
import numpy as np
|
||||
|
||||
from .. import img_as_float
|
||||
from ..color import rgb2gray
|
||||
from ..util.dtype import dtype_range, dtype_limits
|
||||
|
||||
|
||||
@@ -463,3 +464,48 @@ def adjust_sigmoid(image, cutoff=0.5, gain=10, inv=False):
|
||||
|
||||
out = (1 / (1 + np.exp(gain * (cutoff - image / scale)))) * scale
|
||||
return dtype(out)
|
||||
|
||||
|
||||
def is_low_contrast(image, fraction_threshold=0.05, lower_percentile=1,
|
||||
upper_percentile=99, method='linear'):
|
||||
"""Detemine if an image is low contrast.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array-like
|
||||
The image under test.
|
||||
fraction_threshold : float, optional
|
||||
The low contrast fraction threshold.
|
||||
lower_bound : float, optional
|
||||
Disregard values below this percentile when computing image contrast.
|
||||
upper_bound : float, optional
|
||||
Disregard values above this percentile when computing image contrast.
|
||||
method : str, optional
|
||||
The contrast determination method. Right now the only available
|
||||
option is "linear".
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : bool
|
||||
True when the image is determined to be low contrast.
|
||||
|
||||
Examples
|
||||
--------
|
||||
>>> image = np.linspace(0, 0.04, 100)
|
||||
>>> is_low_contrast(image)
|
||||
True
|
||||
>>> image[-1] = 1
|
||||
>>> is_low_contrast(image)
|
||||
True
|
||||
>>> is_low_contrast(image, upper_percentile=100)
|
||||
False
|
||||
"""
|
||||
image = np.asanyarray(image)
|
||||
if image.ndim == 3 and image.shape[2] in [3, 4]:
|
||||
image = rgb2gray(image)
|
||||
|
||||
dlimits = dtype_limits(image)
|
||||
limits = np.percentile(image, [lower_percentile, upper_percentile])
|
||||
ratio = (limits[1] - limits[0]) / (dlimits[1] - dlimits[0])
|
||||
|
||||
return ratio < fraction_threshold
|
||||
|
||||
@@ -472,6 +472,22 @@ def test_negative():
|
||||
assert_raises(ValueError, exposure.adjust_gamma, image)
|
||||
|
||||
|
||||
def test_is_low_contrast():
|
||||
image = np.linspace(0, 0.04, 100)
|
||||
assert exposure.is_low_contrast(image)
|
||||
image[-1] = 1
|
||||
assert exposure.is_low_contrast(image)
|
||||
assert not exposure.is_low_contrast(image, upper_percentile=100)
|
||||
|
||||
image = (image * 255).astype(np.uint8)
|
||||
assert exposure.is_low_contrast(image)
|
||||
assert not exposure.is_low_contrast(image, upper_percentile=100)
|
||||
|
||||
image = (image.astype(np.uint16)) * 2**8
|
||||
assert exposure.is_low_contrast(image)
|
||||
assert not exposure.is_low_contrast(image, upper_percentile=100)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy import testing
|
||||
testing.run_module_suite()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
from io import BytesIO
|
||||
import warnings
|
||||
|
||||
import numpy as np
|
||||
import six
|
||||
@@ -6,6 +7,8 @@ import six
|
||||
from ..io.manage_plugins import call_plugin
|
||||
from ..color import rgb2grey
|
||||
from .util import file_or_url_context
|
||||
from ..exposure import is_low_contrast
|
||||
from .._shared._warnings import all_warnings
|
||||
|
||||
|
||||
__all__ = ['Image', 'imread', 'imread_collection', 'imsave', 'imshow', 'show']
|
||||
@@ -152,6 +155,8 @@ def imsave(fname, arr, plugin=None, **plugin_args):
|
||||
Passed to the given plugin.
|
||||
|
||||
"""
|
||||
if is_low_contrast(arr):
|
||||
warnings.warn('%s is a low contrast image' % fname)
|
||||
return call_plugin('imsave', fname, arr, plugin=plugin, **plugin_args)
|
||||
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@ from collections import namedtuple
|
||||
import numpy as np
|
||||
import warnings
|
||||
import matplotlib.pyplot as plt
|
||||
from skimage.util import dtype as dtypes
|
||||
from ...util import dtype as dtypes
|
||||
from ...exposure import is_low_contrast
|
||||
from ..._shared._warnings import all_warnings
|
||||
|
||||
|
||||
_default_colormap = 'gray'
|
||||
@@ -49,7 +51,7 @@ def _get_image_properties(image):
|
||||
out_of_range_float = (np.issubdtype(image.dtype, np.float) and
|
||||
(immin < lo or immax > hi))
|
||||
low_dynamic_range = (immin != immax and
|
||||
(float(immax - immin) / (hi - lo)) < (1. / 255))
|
||||
is_low_contrast(image))
|
||||
unsupported_dtype = image.dtype not in dtypes._supported_types
|
||||
|
||||
return ImageProperties(signed, out_of_range_float,
|
||||
@@ -72,8 +74,8 @@ def _raise_warnings(image_properties):
|
||||
warnings.warn("Low image dynamic range; displaying image with "
|
||||
"stretched contrast.")
|
||||
if ip.out_of_range_float:
|
||||
warnings.warn("Float image out of standard range; displaying image "
|
||||
"with stretched contrast.")
|
||||
warnings.warn("Float image out of standard range; displaying "
|
||||
"image with stretched contrast.")
|
||||
|
||||
|
||||
def _get_display_range(image):
|
||||
|
||||
@@ -87,7 +87,8 @@ def test_outside_standard_range():
|
||||
|
||||
def test_nonstandard_type():
|
||||
plt.figure()
|
||||
with expected_warnings(["Non-standard image type"]):
|
||||
with expected_warnings(["Non-standard image type",
|
||||
"Low image dynamic range"]):
|
||||
ax_im = io.imshow(im64)
|
||||
assert ax_im.get_clim() == (im64.min(), im64.max())
|
||||
assert n_subplots(ax_im) == 2
|
||||
|
||||
@@ -147,7 +147,8 @@ def test_imsave_filelike():
|
||||
s = BytesIO()
|
||||
|
||||
# save to file-like object
|
||||
with expected_warnings(['precision loss|unclosed file']):
|
||||
with expected_warnings(['precision loss|unclosed file',
|
||||
'is a low contrast image']):
|
||||
imsave(s, image)
|
||||
|
||||
# read from file-like object
|
||||
|
||||
@@ -26,7 +26,7 @@ INTENSITY_SAMPLE[1, 9:11] = 2
|
||||
def test_all_props():
|
||||
region = regionprops(SAMPLE, INTENSITY_SAMPLE)[0]
|
||||
for prop in PROPS:
|
||||
assert_equal(region[prop], getattr(region, PROPS[prop]))
|
||||
assert_almost_equal(region[prop], getattr(region, PROPS[prop]))
|
||||
|
||||
|
||||
def test_dtype():
|
||||
|
||||
@@ -11,6 +11,10 @@ dtype_range = {np.bool_: (False, True),
|
||||
np.uint16: (0, 65535),
|
||||
np.int8: (-128, 127),
|
||||
np.int16: (-32768, 32767),
|
||||
np.int64: (-2**63, 2**63 - 1),
|
||||
np.uint64: (0, 2**64 - 1),
|
||||
np.int32: (-2**31, 2**31 - 1),
|
||||
np.uint32: (0, 2**32 - 1),
|
||||
np.float32: (-1, 1),
|
||||
np.float64: (-1, 1)}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user