Last active
November 30, 2019 10:27
-
-
Save Pro/5896825 to your computer and use it in GitHub Desktop.
Normalize Image using Lab channel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__author__ = 'Stefan' | |
__docformat__ = 'restructedtext en' | |
import numpy as np | |
import scipy.misc | |
import skimage.color | |
import skimage.exposure | |
def histBounds(histogram, margin=0.005): | |
""" | |
Detect lower and upper boundary of histogram. This is used to stretch it afterwards to get better contrast. | |
:param histogram: list containing the number of members for each index | |
:param margin: count value lower than max(histogram)*margin will be considered as zero | |
:return: (lowerMargin, upperMargin) indices in histogram array. | |
""" | |
# cut off full black and full white pixels and ignore them | |
lowCut = int(len(histogram) * 0.12) | |
highCut = int(len(histogram) * 0.95) | |
histCut = histogram[lowCut:highCut] | |
logMargin = np.max(histCut) * margin | |
#now search for minimum and maximum color | |
nonzero = np.where(histCut > logMargin) | |
# return the first and last index where the count is non zero | |
return lowCut + np.min(nonzero), lowCut + np.max(nonzero) | |
def normalizeChannel(channel, maxVal=255.): | |
""" | |
Normalizes the histogram of given 2D array (which is one cannel of a color image or grayscale). | |
:param channel: the image data | |
:param maxVal: maximum value which may occur in array | |
""" | |
arr = channel.astype(float) | |
hist, bounds = np.histogram(arr, maxVal) | |
min, max = histBounds(hist) | |
arr = (float(maxVal) / float(max - min)) * (arr - min) | |
return np.clip(arr, 0, maxVal).astype(channel.dtype) | |
def normalizeLab(arr): | |
""" | |
Normalizes (stretches) the histogram of given image data by the following steps: | |
1. converting the image to Lab color system | |
2. using the histogram of L channel to detect lower and upper bound | |
3. stretch L channel to increase contrast | |
4. convert data back to RGB image | |
:param arr: image data returned from e.g. scipy.misc.fromimage | |
:return: normalized image data | |
""" | |
lab = skimage.color.rgb2lab(arr / 255.) | |
lab[..., 0] = normalizeChannel(lab[..., 0], 100) | |
rgb = skimage.color.lab2rgb(lab) | |
rgb = (rgb * 255).astype(int) | |
return rgb | |
def normalizeImage(img): | |
""" | |
Normalizes the given PIL image | |
:param img: an instance of PIL image | |
:return: normalized PIL image | |
""" | |
bytes = scipy.misc.fromimage(img) | |
bytes = normalizeLab(bytes) | |
return scipy.misc.toimage(bytes) | |
def normalizeImageChannel(img): | |
""" | |
Normalizes the given PIL image | |
:param img: an instance of PIL image | |
:return: normalized PIL image | |
""" | |
bytes = scipy.misc.fromimage(img) | |
for i in xrange(3): | |
bytes[..., i] = normalizeChannel(bytes[..., i], 255) | |
return scipy.misc.toimage(bytes) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment