mirror of
https://github.com/wassname/scikit-image.git
synced 2026-08-12 12:30:16 +08:00
Change API for equalize_hist and cumulative_distribution.
`equalize_hist`: "max_intensity" parameter no longer exists---img_as_float normalizes intensity range `cumulative_distribution`: Return centers of bins instead of the edges. Move `histogram` function from filter subpackage. Add test of equalize_hist Add example of histogram equalization.
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
"""
|
||||
======================
|
||||
Histogram Equalization
|
||||
======================
|
||||
|
||||
This examples takes an image with low contrast and enhances its contrast using
|
||||
histogram equalization. Histogram equalization enhances contrast by "spreading
|
||||
out the most frequent intensity values" in an image [1]. The equalized image
|
||||
has a roughly linear cumulative distribution function, as shown in this example.
|
||||
|
||||
.. [1] http://en.wikipedia.org/wiki/Histogram_equalization
|
||||
|
||||
"""
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from skimage import data
|
||||
from skimage.util.dtype import dtype_range
|
||||
from skimage import exposure
|
||||
|
||||
|
||||
def plot_hist(img, bins=256, ax=None):
|
||||
"""Plot histogram and cumulative histogram for image"""
|
||||
ax = ax if ax is not None else plt.gca()
|
||||
img_cdf, bins = exposure.cumulative_distribution(img, bins)
|
||||
ax.hist(img.ravel(), bins=bins)
|
||||
ax_right = ax.twinx()
|
||||
ax_right.plot(bins, img_cdf, 'r')
|
||||
xmin, xmax = dtype_range[img.dtype.type]
|
||||
ax.set_xlim(xmin, xmax)
|
||||
|
||||
ax.set_ylabel('# pixels')
|
||||
ax.set_xlabel('pixel intensiy')
|
||||
ax_right.set_ylabel('fraction of total intensity')
|
||||
|
||||
|
||||
img_orig = data.camera()
|
||||
# squeeze image intensities to lower image contrast
|
||||
img = img_orig / 5 + 100
|
||||
img_eq = exposure.equalize_hist(img)
|
||||
|
||||
plt.subplot(2, 2, 1)
|
||||
plt.imshow(img, cmap=plt.cm.gray, vmin=0, vmax=255)
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 2)
|
||||
plot_hist(img)
|
||||
|
||||
plt.subplot(2, 2, 3)
|
||||
plt.imshow(img_eq, cmap=plt.cm.gray, vmin=0, vmax=1)
|
||||
plt.axis('off')
|
||||
plt.subplot(2, 2, 4)
|
||||
plot_hist(img_eq)
|
||||
|
||||
plt.subplots_adjust(left=0.05, hspace=0.25, wspace=0.3, top=0.95, bottom=0.1)
|
||||
plt.show()
|
||||
|
||||
@@ -1 +1 @@
|
||||
from exposure import equalize_hist, cumulative_distribution
|
||||
from exposure import histogram, equalize_hist, cumulative_distribution
|
||||
|
||||
@@ -1,15 +1,63 @@
|
||||
import numpy as np
|
||||
|
||||
|
||||
__all__ = ['cumulative_distribution', 'equalize_hist']
|
||||
import skimage
|
||||
|
||||
|
||||
def cumulative_distribution(img, nbins=256):
|
||||
__all__ = ['histogram', 'cumulative_distribution', 'equalize_hist']
|
||||
|
||||
|
||||
def histogram(image, nbins, density=True):
|
||||
"""Return histogram of image.
|
||||
|
||||
Unlike `numpy.histogram`, this function returns the centers of bins and
|
||||
does not rebin integer arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
Input image.
|
||||
nbins : int
|
||||
Number of bins used to calculate histogram. This value is ignored for
|
||||
integer arrays.
|
||||
density : {True | False}
|
||||
If True, values represent the probability density function.
|
||||
If False, values represent the number of pixels in bins.
|
||||
See numpy.histogram for details.
|
||||
|
||||
Returns
|
||||
-------
|
||||
hist : array
|
||||
The values of the histogram.
|
||||
bin_centers : array
|
||||
The values at the center of the bins.
|
||||
"""
|
||||
if np.issubdtype(image.dtype, np.integer):
|
||||
offset = 0
|
||||
if np.min(image) < 0:
|
||||
offset = np.min(image)
|
||||
hist = np.bincount(image.ravel() - offset)
|
||||
bin_centers = np.arange(len(hist)) + offset
|
||||
|
||||
# clip histogram to start with a non-zero bin
|
||||
idx = np.nonzero(hist)[0][0]
|
||||
return hist[idx:], bin_centers[idx:]
|
||||
else:
|
||||
|
||||
if np.version.version >= '1.6':
|
||||
hist, bin_edges = np.histogram(image.flat, nbins, density=density)
|
||||
else:
|
||||
hist, bin_edges = np.histogram(image.flat, nbins, normed=density)
|
||||
|
||||
bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2.
|
||||
return hist, bin_centers
|
||||
|
||||
|
||||
def cumulative_distribution(image, nbins=256):
|
||||
"""Return cumulative distribution function (cdf) for the given image.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img : array
|
||||
image : array
|
||||
Image array.
|
||||
nbins : int
|
||||
Number of bins for image histogram.
|
||||
@@ -18,34 +66,33 @@ def cumulative_distribution(img, nbins=256):
|
||||
-------
|
||||
img_cdf : array
|
||||
Values of cumulative distribution function.
|
||||
bin_edges : array
|
||||
Bin edges for cdf. Length is ``len(img_cdf) + 1``.
|
||||
bin_centers : array
|
||||
Centers of bins.
|
||||
|
||||
References
|
||||
----------
|
||||
.. [1] http://en.wikipedia.org/wiki/Cumulative_distribution_function
|
||||
|
||||
"""
|
||||
hist, bin_edges = np.histogram(img.flat, nbins, density=True)
|
||||
hist, bin_centers = histogram(image, nbins)
|
||||
img_cdf = hist.cumsum()
|
||||
return img_cdf, bin_edges
|
||||
img_cdf = img_cdf / float(img_cdf[-1])
|
||||
return img_cdf, bin_centers
|
||||
|
||||
|
||||
def equalize_hist(img, nbins=256, max_intensity=255):
|
||||
def equalize_hist(image, nbins=256):
|
||||
"""Return image after histogram equalization.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
img : array
|
||||
image : array
|
||||
Image array.
|
||||
nbins : int
|
||||
Number of bins for image histogram.
|
||||
max_intensity : int
|
||||
Maximum intensity of the returned image.
|
||||
|
||||
Returns
|
||||
-------
|
||||
out : array
|
||||
out : float array
|
||||
Image array after histogram equalization.
|
||||
|
||||
Notes
|
||||
@@ -58,8 +105,8 @@ def equalize_hist(img, nbins=256, max_intensity=255):
|
||||
.. [2] http://en.wikipedia.org/wiki/Histogram_equalization
|
||||
|
||||
"""
|
||||
cdf, bin_edges = cumulative_distribution(img, nbins)
|
||||
cdf = max_intensity * cdf / cdf[-1]
|
||||
out = np.interp(img.flat, bin_edges[:-1], cdf)
|
||||
return out.reshape(img.shape)
|
||||
image = skimage.img_as_float(image)
|
||||
cdf, bin_centers = cumulative_distribution(image, nbins)
|
||||
out = np.interp(image.flat, bin_centers, cdf)
|
||||
return out.reshape(image.shape)
|
||||
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
import numpy as np
|
||||
|
||||
import skimage
|
||||
from skimage import data
|
||||
from skimage import exposure
|
||||
|
||||
|
||||
# squeeze image intensities to lower image contrast
|
||||
test_img = data.camera() / 5 + 100
|
||||
|
||||
|
||||
def test_equalize_hist_ubyte():
|
||||
img_eq = exposure.equalize_hist(test_img)
|
||||
|
||||
cdf, bin_edges = exposure.cumulative_distribution(img_eq)
|
||||
check_cdf_slope(cdf)
|
||||
|
||||
|
||||
def test_equalize_hist_float():
|
||||
img = skimage.img_as_float(test_img)
|
||||
img_eq = exposure.equalize_hist(img)
|
||||
|
||||
cdf, bin_edges = exposure.cumulative_distribution(img_eq)
|
||||
check_cdf_slope(cdf)
|
||||
|
||||
|
||||
def check_cdf_slope(cdf):
|
||||
"""Slope of cdf which should equal 1 for an equalized histogram."""
|
||||
norm_intensity = np.linspace(0, 1, len(cdf))
|
||||
slope, intercept = np.polyfit(norm_intensity, cdf, 1)
|
||||
assert 0.9 < slope < 1.1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from numpy import testing
|
||||
testing.run_module_suite()
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import numpy as np
|
||||
|
||||
from skimage.exposure import histogram
|
||||
|
||||
|
||||
__all__ = ['threshold_otsu']
|
||||
|
||||
@@ -50,40 +52,3 @@ def threshold_otsu(image, nbins=256):
|
||||
threshold = bin_centers[:-1][idx]
|
||||
return threshold
|
||||
|
||||
|
||||
def histogram(image, nbins):
|
||||
"""Return histogram of image.
|
||||
|
||||
Unlike `numpy.histogram`, this function returns the centers of bins and
|
||||
does not rebin integer arrays.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
image : array
|
||||
Input image.
|
||||
nbins : int
|
||||
Number of bins used to calculate histogram. This value is ignored for
|
||||
integer arrays.
|
||||
|
||||
Returns
|
||||
-------
|
||||
hist : array
|
||||
The values of the histogram.
|
||||
bin_centers : array
|
||||
The values at the center of the bins.
|
||||
"""
|
||||
if np.issubdtype(image.dtype, np.integer):
|
||||
offset = 0
|
||||
if np.min(image) < 0:
|
||||
offset = np.min(image)
|
||||
hist = np.bincount(image.ravel() - offset)
|
||||
bin_centers = np.arange(len(hist)) + offset
|
||||
|
||||
# clip histogram to return only non-zero bins
|
||||
idx = np.nonzero(hist)[0][0]
|
||||
return hist[idx:], bin_centers[idx:]
|
||||
else:
|
||||
hist, bin_edges = np.histogram(image, bins=nbins)
|
||||
bin_centers = (bin_edges[:-1] + bin_edges[1:]) / 2.
|
||||
return hist, bin_centers
|
||||
|
||||
|
||||
Reference in New Issue
Block a user