from skimage.exposure import match_histograms
match_histograms 的实现非常简洁有效。直方图匹配或者直方图规定化
import cv2
import numpy as np
from matplotlib import pyplot as plt
def match_histograms(image, reference, *, channel_axis=None):
"""Adjust an image so that its cumulative histogram matches that of another.
The adjustment is applied separately for each channel.
Parameters
----------
image : ndarray
Input image. Can be gray-scale or in color.
reference : ndarray
Image to match histogram of. Must have the same number of channels as
image.
channel_axis : int or None, optional
If None, the image is assumed to be a grayscale (single channel) image.
Otherwise, this parameter indicates which axis of the array corresponds
to channels.
Returns
-------
matched : ndarray
Transformed input image.
Raises
------
ValueError
Thrown when the number of channels in the input image and the reference
differ.
References
----------
.. [1] http://paulbourke.net/miscellaneous/equalisation/
"""
print(image.ndim, reference.ndim)
if image.ndim != reference.ndim:
raise ValueError('Image and reference must have the same number '
'of channels.')
if channel_axis is not None:
if image.shape[-1] != reference.shape[-1]:
raise ValueError('Number of channels in the input image and '
'reference image must match!')
matched = np.empty(image.shape, dtype=image.dtype)
for channel in range(image.shape[-1]):
matched_channel = _match_cumulative_cdf(image[..., channel],
reference[..., channel])
matched[..., channel] = matched_channel
else:
# _match_cumulative_cdf will always return float64 due to np.interp
matched = _match_cumulative_cdf(image, reference)
# if matched.dtype.kind == 'f':
# # output a float32 result when the input is float16 or float32
# out_dtype = utils._supported_float_type(image.dtype)
# matched = matched.astype(out_dtype, copy=False)
return matched
def _match_cumulative_cdf(source, template):
"""
Return modified source array so that the cumulative density function of
its values matches the cumulative density function of the template.
"""
print(source.dtype.kind)
if source.dtype.kind == 'u':
src_lookup = source.reshape(-1)
src_counts = np.bincount(src_lookup)
tmpl_counts = np.bincount(template.reshape(-1))
print(src_lookup.shape, src_lookup.dtype, src_counts.shape, src_counts.dtype, tmpl_counts.shape, tmpl_counts.dtype)
print(tmpl_counts.shape)
# omit values where the count was 0
tmpl_values = np.nonzero(tmpl_counts)[0]
tmpl_counts = tmpl_counts[tmpl_values]
print(tmpl_values.shape, tmpl_counts.shape)
else:
src_values, src_lookup, src_counts = np.unique(source.reshape(-1),
return_inverse=True,
return_counts=True)
tmpl_values, tmpl_counts = np.unique(template.reshape(-1),
return_counts=True)
# calculate normalized quantiles for each array
src_quantiles = np.cumsum(src_counts) / source.size
tmpl_quantiles = np.cumsum(tmpl_counts) / template.size
# 0-255的像素值应该变为多少
interp_a_values = np.interp(src_quantiles, tmpl_quantiles, tmpl_values)
return interp_a_values[src_lookup].reshape(source.shape)
if __name__ == "__main__":
file1 = r'D:\code\3.jpg'
file2 = r'D:\code\1.jpg'
img1 = cv2.imread(file1, 0)
img2 = cv2.imread(file2, 0)
out = match_histograms(img1, img2)
plt.figure()
#plt.imshow(np.hstack((img1, img2, out))[...,::-1]/255)
plt.imshow(np.hstack((img1, img2, out)), 'gray')
plt.show()