[Feature] Add 2 ratiometric calibration functions

own
Bobholamovic 3 years ago
parent bfd2554f98
commit 3e902929f4
  1. 63
      paddlers/transforms/functions.py

@ -20,6 +20,8 @@ import shapely.ops
from shapely.geometry import Polygon, MultiPolygon, GeometryCollection
from functools import reduce
from sklearn.decomposition import PCA
from sklearn.linear_model import LinearRegression
from skimage import exposure
def normalize(im, mean, std, min_value=[0, 0, 0], max_value=[255, 255, 255]):
@ -379,3 +381,64 @@ def pca(im, dim=3, whiten=True):
result = np.reshape(im_pca, (H, W, dim))
result = np.clip(result, 0, 1)
return (result * 255).astype("uint8")
def match_histograms(im, ref):
"""
Match the cumulative histogram of one image to another.
Args:
im (np.ndarray): The input image.
ref (np.ndarray): The reference image to match histogram of. `ref` must have the same number of channels as `im`.
Returns:
np.ndarray: The transformed input image.
Raises:
ValueError: When the number of channels of `ref` differs from that of im`.
"""
# TODO: Check the data types of the inputs to see if they are supported by skimage
return exposure.match_histograms(im, ref, channel_axis=-1 if im.ndim>2 else None)
def match_by_regression(im, ref, pif_loc=None):
"""
Match the brightness values of two images using a linear regression method.
Args:
im (np.ndarray): The input image.
ref (np.ndarray): The reference image to match. `ref` must have the same shape as `im`.
pif_loc (tuple|None, optional): The spatial locations where pseudo-invariant features (PIFs) are obtained. If
`pif_loc` is set to None, all pixels in the image will be used as training samples for the regression model.
In other cases, `pif_loc` should be a tuple of np.ndarrays. Default: None.
Returns:
np.ndarray: The transformed input image.
Raises:
ValueError: When the shape of `ref` differs from that of `im`.
"""
def _linear_regress(im, ref, loc):
regressor = LinearRegression()
if loc is not None:
x, y = im[loc], ref[loc]
else:
x, y = im, ref
x, y = x.reshape(-1,1), y.ravel()
regressor.fit(x, y)
matched = regressor.predict(im.reshape(-1,1))
return matched.reshape(im.shape)
if im.shape != ref.shape:
raise ValueError("Image and Reference must have the same shape!")
if im.ndim > 2:
# Multiple channels
matched = np.empty(im.shape, dtype=im.dtype)
for ch in range(im.shape[-1]):
matched[..., ch] = _linear_regress(im[..., ch], ref[..., ch], pif_loc)
else:
# Single channel
matched = _linear_regress(im, ref, pif_loc).astype(im.dtype)
return matched
Loading…
Cancel
Save