Basic Colour Adjustments
Preparing
First of all we should prepare Python infrastructure:
numpy
for array computing.cv2
for reading images.matplotlib.pyplot
for plotting results.histograms
it's my own code, you can find it here.
import numpy as np import cv2 import math from IPython.display import IFrame %matplotlib inline import matplotlib.pyplot as plt from histograms import * plt.style.use('seaborn-dark')
Then we read foreground and background images. As cv2.IMREAD_UNCHANGED
mode is used for reading PNG as is with its transparency. Also read image is converted here to float within a range of values [0; 1].
Then channels R and B must be swaped because OpenCV storage images in BGR mode:
img = cv2.imread("photo1.jpg", cv2.IMREAD_UNCHANGED).astype(np.float) / 255.0 img = img[...,[2, 1, 0]]
Channel value offset
Increses or decreses each channel on a specified value. The result must be clamped for the correct working of the adjustment. You should understand, that this adjustment isn't reversible because part of information will be lost after clamping.
img_offset = img.copy() img_offset[...,:] += [0.3, 0.0, -0.3] img_offset = np.clip(img_offset, 0.0, 1.0)
Result image:
Result image's histogram:
Gamma correction
Moves point of mid-tones of a channel preserving white and black points. Note, that it works only with values in the range [0; 1]
img_gamma = img.copy() img_gamma[...,:] = np.power(img_gamma[...,:], np.exp([1.0, 0.0, -1.0])) img_gamma = np.clip(img_gamma, 0.0, 1.0)
Result image:
Result image's histogram:
Channel value multiply
Works like offset but instead of sum here is used multiplication.
img_mul = img.copy() img_mul[...,:] *= [1.5, 1.0, 0.5] img_mul = np.clip(img_mul, 0.0, 1.0)
Result image:
Result image's histogram:
Normalization
Moves point of maximal and/or minimum value of a channel. These points can be moved both inside and outside source box therefore here can be cases when adjustments will be not reversible. The adjustments implement linear operations with the histogram.
This adjustment can be used for increasing or decreasing the contrast of the image, offset (with an identical offset for black and white points) or inversing (with swapping black and white points).
min_val = np.array([0.3, 0.0, 0.2]) max_val = np.array([0.7, 0.9, 0.8]) img_norm = img.copy() img_norm[...,:] = (img_norm[...,:] - min_val) / (max_val - min_val) img_norm = np.clip(img_norm, 0.0, 1.0)
Result image:
Result image's histogram:
Contrast
Of course, you can implement contrast adjustment using the previous operation. But here is some trick:
coeffs = np.tan(np.pi * 0.25 * (1.0 + np.array([-0.5, 0.0, 0.5]))) img_contrast = img.copy() img_contrast[...,:] = (img_contrast[...,:] - 0.5) * coeffs + 0.5 img_contrast = np.clip(img_contrast, 0.0, 1.0)
Result image:
Result image's histogram: