from __future__ import division
from .normalizer_abc import Normaliser
from ..utils import misc as mu
import numpy as np
import cv2 as cv
[docs]class ReinhardNormalizer(Normaliser):
"""
Normalize a patch stain to the target image using the method of:
E. Reinhard, M. Adhikhmin, B. Gooch, and P. Shirley, ‘Color transfer between images’, IEEE Computer Graphics and Applications, vol. 21, no. 5, pp. 34–41, Sep. 2001.
"""
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.target_means = None
self.target_stds = None
[docs] def fit(self, target):
"""
Fit to a target image
:param target: Image RGB uint8.
:return:
"""
if self.standardize:
target = mu.standardize_brightness(target)
means, stds = self.get_mean_std(target)
self.target_means = means
self.target_stds = stds
[docs] @staticmethod
def lab_split(I):
"""
Convert from RGB uint8 to LAB and split into channels.
:param I: Image RGB uint8.
:return:
"""
assert mu.is_uint8_image(I)
I = cv.cvtColor(I, cv.COLOR_RGB2LAB)
I = I.astype(np.float32)
I1, I2, I3 = cv.split(I)
I1 /= 2.55
I2 -= 128.0
I3 -= 128.0
return I1, I2, I3
[docs] @staticmethod
def merge_back(I1, I2, I3):
"""
Take seperate LAB channels and merge back to give RGB uint8.
:param I1: L
:param I2: A
:param I3: B
:return: Image RGB uint8.
"""
I1 *= 2.55
I2 += 128.0
I3 += 128.0
I = np.clip(cv.merge((I1, I2, I3)), 0, 255).astype(np.uint8)
return cv.cvtColor(I, cv.COLOR_LAB2RGB)
[docs] def get_mean_std(self, I):
"""
Get mean and standard deviation of each channel.
:param I: Image RGB uint8.
:return:
"""
I1, I2, I3 = self.lab_split(I)
m1, sd1 = cv.meanStdDev(I1)
m2, sd2 = cv.meanStdDev(I2)
m3, sd3 = cv.meanStdDev(I3)
means = m1, m2, m3
stds = sd1, sd2, sd3
return means, stds