Merge branch 'tony-exposure'

This commit is contained in:
Stefan van der Walt
2011-12-26 02:03:27 -08:00
6 changed files with 206 additions and 39 deletions
+4 -2
View File
@@ -26,9 +26,11 @@
- Tony Yu
Reading of paletted images; build, bug and doc fixes.
Code to generate skimage logo.
Otsu thresholding, histogram equalisation, and more.
- Zachary Pincus
Tracing of low cost paths, FreeImage I/O plugin, iso-contours
Tracing of low cost paths, FreeImage I/O plugin, iso-contours,
and more.
- Almar Klein
Binary heap class for graph algorithms
@@ -45,7 +47,7 @@
- Emmanuelle Guillart
Total variation noise filtering, integration of CellProfiler's
mathematical morphology tools.
mathematical morphology tools, tutorials, and more.
- Maël Primet
Total variation noise filtering
+56
View File
@@ -0,0 +1,56 @@
"""
======================
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):
"""Plot histogram and cumulative histogram for image"""
img_cdf, bins = exposure.cumulative_distribution(img, bins)
plt.hist(img.ravel(), bins=bins)
plt.ylabel('Number of pixels')
plt.xlabel('Pixel intensiy')
ax_cdf = plt.twinx()
ax_cdf.plot(bins, img_cdf, 'r')
xmin, xmax = dtype_range[img.dtype.type]
plt.xlim(xmin, xmax)
ax_cdf.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(img)
plt.subplot(2, 2, 1)
plt.imshow(img, cmap=plt.cm.gray, vmin=0, vmax=255)
plt.title('Low contrast input image')
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.title('After\nhistogram equalization')
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
View File
@@ -0,0 +1 @@
from exposure import histogram, equalize, cumulative_distribution
+106
View File
@@ -0,0 +1,106 @@
import numpy as np
import skimage
__all__ = ['histogram', 'cumulative_distribution', 'equalize']
def histogram(image, nbins=256):
"""Return histogram of image.
Unlike `numpy.histogram`, this function returns the centers of bins and
does not rebin integer arrays. For integer arrays, each integer value has
its own bin, which improves speed and intensity-resolution.
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.
"""
# For integer types, histogramming with bincount is more efficient.
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:
hist, bin_edges = np.histogram(image.flat, nbins)
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
----------
image : array
Image array.
nbins : int
Number of bins for image histogram.
Returns
-------
img_cdf : array
Values of cumulative distribution function.
bin_centers : array
Centers of bins.
References
----------
.. [1] http://en.wikipedia.org/wiki/Cumulative_distribution_function
"""
hist, bin_centers = histogram(image, nbins)
img_cdf = hist.cumsum()
img_cdf = img_cdf / float(img_cdf[-1])
return img_cdf, bin_centers
def equalize(image, nbins=256):
"""Return image after histogram equalization.
Parameters
----------
image : array
Image array.
nbins : int
Number of bins for image histogram.
Returns
-------
out : float array
Image array after histogram equalization.
Notes
-----
This function is adapted from [1]_ with the author's permission.
References
----------
.. [1] http://www.janeriksolem.net/2009/06/histogram-equalization-with-python-and.html
.. [2] http://en.wikipedia.org/wiki/Histogram_equalization
"""
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)
+37
View File
@@ -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_ubyte():
img_eq = exposure.equalize(test_img)
cdf, bin_edges = exposure.cumulative_distribution(img_eq)
check_cdf_slope(cdf)
def test_equalize_float():
img = skimage.img_as_float(test_img)
img_eq = exposure.equalize(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()
+2 -37
View File
@@ -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