mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-04 11:55:05 +08:00
Merge pull request #505 from ankit-maverick/gammaCorrect
Implementation of Pixelwise Image correction methods
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
from .exposure import histogram, equalize, equalize_hist, \
|
||||
rescale_intensity, cumulative_distribution
|
||||
rescale_intensity, cumulative_distribution, \
|
||||
adjust_gamma, adjust_sigmoid, adjust_log
|
||||
|
||||
from ._adapthist import equalize_adapthist
|
||||
|
||||
__all__ = ['histogram',
|
||||
@@ -7,4 +9,7 @@ __all__ = ['histogram',
|
||||
'equalize_hist',
|
||||
'equalize_adapthist',
|
||||
'rescale_intensity',
|
||||
'cumulative_distribution']
|
||||
'cumulative_distribution',
|
||||
'adjust_gamma',
|
||||
'adjust_sigmoid',
|
||||
'adjust_log']
|
||||
|
||||
@@ -2,14 +2,13 @@ import warnings
|
||||
import numpy as np
|
||||
|
||||
from skimage import img_as_float
|
||||
from skimage.util.dtype import dtype_range
|
||||
import skimage.color as color
|
||||
from skimage.util.dtype import convert
|
||||
from skimage.util.dtype import dtype_range, dtype_limits
|
||||
from skimage._shared.utils import deprecated
|
||||
|
||||
|
||||
__all__ = ['histogram', 'cumulative_distribution', 'equalize',
|
||||
'rescale_intensity']
|
||||
'rescale_intensity', 'adjust_gamma',
|
||||
'adjust_log', 'adjust_sigmoid']
|
||||
|
||||
|
||||
def histogram(image, nbins=256):
|
||||
@@ -216,3 +215,139 @@ def rescale_intensity(image, in_range=None, out_range=None):
|
||||
|
||||
image = (image - imin) / float(imax - imin)
|
||||
return dtype(image * (omax - omin) + omin)
|
||||
|
||||
|
||||
def _assert_non_negative(image):
|
||||
|
||||
if np.any(image < 0):
|
||||
raise ValueError('Image Correction methods work correctly only on '
|
||||
'images with non-negative values. Use '
|
||||
'skimage.exposure.rescale_intensity.')
|
||||
|
||||
|
||||
def adjust_gamma(image, gamma=1, gain=1):
|
||||
"""Performs Gamma Correction on the input image.
|
||||
|
||||
Also known as Power Law Transform.
|
||||
This function transforms the input image pixelwise according to the
|
||||
equation ``O = I**gamma`` after scaling each pixel to the range 0 to 1.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
gamma : float
|
||||
Non negative real number. Default value is 1.
|
||||
gain : float
|
||||
The constant multiplier. Default value is 1.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Gamma corrected output image.
|
||||
|
||||
Notes
|
||||
-----
|
||||
For gamma greater than 1, the histogram will shift towards left and
|
||||
the output image will be darker than the input image.
|
||||
|
||||
For gamma less than 1, the histogram will shift towards right and
|
||||
the output image will be brighter than the input image.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://en.wikipedia.org/wiki/Gamma_correction
|
||||
|
||||
"""
|
||||
_assert_non_negative(image)
|
||||
dtype = image.dtype.type
|
||||
|
||||
if gamma < 0:
|
||||
return "Gamma should be a non-negative real number"
|
||||
|
||||
scale = float(dtype_limits(image, True)[1] - dtype_limits(image, True)[0])
|
||||
|
||||
out = ((image / scale) ** gamma) * scale * gain
|
||||
return dtype(out)
|
||||
|
||||
|
||||
def adjust_log(image, gain=1, inv=False):
|
||||
"""Performs Logarithmic correction on the input image.
|
||||
|
||||
This function transforms the input image pixelwise according to the
|
||||
equation ``O = gain*log(1 + I)`` after scaling each pixel to the range 0 to 1.
|
||||
For inverse logarithmic correction, the equation is ``O = gain*(2**I - 1)``.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
gain : float
|
||||
The constant multiplier. Default value is 1.
|
||||
inv : float
|
||||
If True, it performs inverse logarithmic correction,
|
||||
else correction will be logarithmic. Defaults to False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Logarithm corrected output image.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://www.ece.ucsb.edu/Faculty/Manjunath/courses/ece178W03/EnhancePart1.pdf
|
||||
|
||||
"""
|
||||
_assert_non_negative(image)
|
||||
dtype = image.dtype.type
|
||||
scale = float(dtype_limits(image, True)[1] - dtype_limits(image, True)[0])
|
||||
|
||||
if inv:
|
||||
out = (2 ** (image / scale) - 1) * scale * gain
|
||||
return dtype(out)
|
||||
|
||||
out = np.log2(1 + image / scale) * scale * gain
|
||||
return dtype(out)
|
||||
|
||||
|
||||
def adjust_sigmoid(image, cutoff=0.5, gain=10, inv=False):
|
||||
"""Performs Sigmoid Correction on the input image.
|
||||
|
||||
Also known as Contrast Adjustment.
|
||||
This function transforms the input image pixelwise according to the
|
||||
equation ``O = 1/(1 + exp*(gain*(cutoff - I)))`` after scaling each pixel
|
||||
to the range 0 to 1.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : ndarray
|
||||
Input image.
|
||||
cutoff : float
|
||||
Cutoff of the sigmoid function that shifts the characteristic curve
|
||||
in horizontal direction. Default value is 0.5.
|
||||
gain : float
|
||||
The constant multiplier in exponential's power of sigmoid function.
|
||||
Default value is 10.
|
||||
inv : bool
|
||||
If True, returns the negative sigmoid correction. Defaults to False.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : ndarray
|
||||
Sigmoid corrected output image.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://bme.med.upatras.gr/improc/matalb_code_toc.htm#12. Adjust Contrast :
|
||||
|
||||
"""
|
||||
_assert_non_negative(image)
|
||||
dtype = image.dtype.type
|
||||
scale = float(dtype_limits(image, True)[1] - dtype_limits(image, True)[0])
|
||||
|
||||
if inv:
|
||||
out = (1 - 1 / (1 + np.exp(gain * (cutoff - image/scale)))) * scale
|
||||
return dtype(out)
|
||||
|
||||
out = (1 / (1 + np.exp(gain * (cutoff - image/scale)))) * scale
|
||||
return dtype(out)
|
||||
|
||||
@@ -2,6 +2,7 @@ import warnings
|
||||
|
||||
import numpy as np
|
||||
from numpy.testing import assert_array_almost_equal as assert_close
|
||||
from numpy.testing import assert_array_equal
|
||||
import skimage
|
||||
from skimage import data
|
||||
from skimage import exposure
|
||||
@@ -175,3 +176,163 @@ def norm_brightness_err(img1, img2):
|
||||
if __name__ == '__main__':
|
||||
from numpy import testing
|
||||
testing.run_module_suite()
|
||||
|
||||
|
||||
# Test Gamma Correction
|
||||
# =====================
|
||||
|
||||
def test_adjust_gamma_one():
|
||||
"""Same image should be returned for gamma equal to one"""
|
||||
image = np.random.uniform(0, 255, (8, 8))
|
||||
result = exposure.adjust_gamma(image, 1)
|
||||
assert_array_equal(result, image)
|
||||
|
||||
|
||||
def test_adjust_gamma_zero():
|
||||
"""White image should be returned for gamma equal to zero"""
|
||||
image = np.random.uniform(0, 255, (8, 8))
|
||||
result = exposure.adjust_gamma(image, 0)
|
||||
dtype = image.dtype.type
|
||||
assert_array_equal(result, dtype_range[dtype][1])
|
||||
|
||||
|
||||
def test_adjust_gamma_less_one():
|
||||
"""Verifying the output with expected results for gamma
|
||||
correction with gamma equal to half"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 0, 31, 45, 55, 63, 71, 78, 84],
|
||||
[ 90, 95, 100, 105, 110, 115, 119, 123],
|
||||
[127, 131, 135, 139, 142, 146, 149, 153],
|
||||
[156, 159, 162, 165, 168, 171, 174, 177],
|
||||
[180, 183, 186, 188, 191, 194, 196, 199],
|
||||
[201, 204, 206, 209, 211, 214, 216, 218],
|
||||
[221, 223, 225, 228, 230, 232, 234, 236],
|
||||
[238, 241, 243, 245, 247, 249, 251, 253]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_gamma(image, 0.5)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_adjust_gamma_greater_one():
|
||||
"""Verifying the output with expected results for gamma
|
||||
correction with gamma equal to two"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 0, 0, 0, 0, 1, 1, 2, 3],
|
||||
[ 4, 5, 6, 7, 9, 10, 12, 14],
|
||||
[ 16, 18, 20, 22, 25, 27, 30, 33],
|
||||
[ 36, 39, 42, 45, 49, 52, 56, 60],
|
||||
[ 64, 68, 72, 76, 81, 85, 90, 95],
|
||||
[100, 105, 110, 116, 121, 127, 132, 138],
|
||||
[144, 150, 156, 163, 169, 176, 182, 189],
|
||||
[196, 203, 211, 218, 225, 233, 241, 249]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_gamma(image, 2)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
# Test Logarithmic Correction
|
||||
# ===========================
|
||||
|
||||
def test_adjust_log():
|
||||
"""Verifying the output with expected results for logarithmic
|
||||
correction with multiplier constant multiplier equal to unity"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 0, 5, 11, 16, 22, 27, 33, 38],
|
||||
[ 43, 48, 53, 58, 63, 68, 73, 77],
|
||||
[ 82, 86, 91, 95, 100, 104, 109, 113],
|
||||
[117, 121, 125, 129, 133, 137, 141, 145],
|
||||
[149, 153, 157, 160, 164, 168, 172, 175],
|
||||
[179, 182, 186, 189, 193, 196, 199, 203],
|
||||
[206, 209, 213, 216, 219, 222, 225, 228],
|
||||
[231, 234, 238, 241, 244, 246, 249, 252]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_log(image, 1)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_adjust_inv_log():
|
||||
"""Verifying the output with expected results for inverse logarithmic
|
||||
correction with multiplier constant multiplier equal to unity"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 0, 2, 5, 8, 11, 14, 17, 20],
|
||||
[ 23, 26, 29, 32, 35, 38, 41, 45],
|
||||
[ 48, 51, 55, 58, 61, 65, 68, 72],
|
||||
[ 76, 79, 83, 87, 90, 94, 98, 102],
|
||||
[106, 110, 114, 118, 122, 126, 130, 134],
|
||||
[138, 143, 147, 151, 156, 160, 165, 170],
|
||||
[174, 179, 184, 188, 193, 198, 203, 208],
|
||||
[213, 218, 224, 229, 234, 239, 245, 250]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_log(image, 1, True)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
# Test Sigmoid Correction
|
||||
# =======================
|
||||
|
||||
def test_adjust_sigmoid_cutoff_one():
|
||||
"""Verifying the output with expected results for sigmoid correction
|
||||
with cutoff equal to one and gain of 5"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 1, 1, 1, 2, 2, 2, 2, 2],
|
||||
[ 3, 3, 3, 4, 4, 4, 5, 5],
|
||||
[ 5, 6, 6, 7, 7, 8, 9, 10],
|
||||
[ 10, 11, 12, 13, 14, 15, 16, 18],
|
||||
[ 19, 20, 22, 24, 25, 27, 29, 32],
|
||||
[ 34, 36, 39, 41, 44, 47, 50, 54],
|
||||
[ 57, 61, 64, 68, 72, 76, 80, 85],
|
||||
[ 89, 94, 99, 104, 108, 113, 118, 123]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_sigmoid(image, 1, 5)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_adjust_sigmoid_cutoff_zero():
|
||||
"""Verifying the output with expected results for sigmoid correction
|
||||
with cutoff equal to zero and gain of 10"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[127, 137, 147, 156, 166, 175, 183, 191],
|
||||
[198, 205, 211, 216, 221, 225, 229, 232],
|
||||
[235, 238, 240, 242, 244, 245, 247, 248],
|
||||
[249, 250, 250, 251, 251, 252, 252, 253],
|
||||
[253, 253, 253, 253, 254, 254, 254, 254],
|
||||
[254, 254, 254, 254, 254, 254, 254, 254],
|
||||
[254, 254, 254, 254, 254, 254, 254, 254],
|
||||
[254, 254, 254, 254, 254, 254, 254, 254]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_sigmoid(image, 0, 10)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_adjust_sigmoid_cutoff_half():
|
||||
"""Verifying the output with expected results for sigmoid correction
|
||||
with cutoff equal to half and gain of 10"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[ 1, 1, 2, 2, 3, 3, 4, 5],
|
||||
[ 5, 6, 7, 9, 10, 12, 14, 16],
|
||||
[ 19, 22, 25, 29, 34, 39, 44, 50],
|
||||
[ 57, 64, 72, 80, 89, 99, 108, 118],
|
||||
[128, 138, 148, 158, 167, 176, 184, 192],
|
||||
[199, 205, 211, 217, 221, 226, 229, 233],
|
||||
[236, 238, 240, 242, 244, 246, 247, 248],
|
||||
[249, 250, 250, 251, 251, 252, 252, 253]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_sigmoid(image, 0.5, 10)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
|
||||
def test_adjust_inv_sigmoid_cutoff_half():
|
||||
"""Verifying the output with expected results for inverse sigmoid
|
||||
correction with cutoff equal to half and gain of 10"""
|
||||
image = np.arange(0, 255, 4, np.uint8).reshape(8,8)
|
||||
expected = np.array([[253, 253, 252, 252, 251, 251, 250, 249],
|
||||
[249, 248, 247, 245, 244, 242, 240, 238],
|
||||
[235, 232, 229, 225, 220, 215, 210, 204],
|
||||
[197, 190, 182, 174, 165, 155, 146, 136],
|
||||
[126, 116, 106, 96, 87, 78, 70, 62],
|
||||
[ 55, 49, 43, 37, 33, 28, 25, 21],
|
||||
[ 18, 16, 14, 12, 10, 8, 7, 6],
|
||||
[ 5, 4, 4, 3, 3, 2, 2, 1]], dtype=np.uint8)
|
||||
|
||||
result = exposure.adjust_sigmoid(image, 0.5, 10, True)
|
||||
assert_array_equal(result, expected)
|
||||
|
||||
Reference in New Issue
Block a user