Last active
February 13, 2025 13:54
-
-
Save DavidYKay/9dad6c4ab0d8d7dbf3dc to your computer and use it in GitHub Desktop.
Simple color balance algorithm using Python 2.7.8 and OpenCV 2.4.10. Ported from: http://www.morethantechnical.com/2015/01/14/simplest-color-balance-with-opencv-wcode/
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
import cv2 | |
import math | |
import numpy as np | |
import sys | |
def apply_mask(matrix, mask, fill_value): | |
masked = np.ma.array(matrix, mask=mask, fill_value=fill_value) | |
return masked.filled() | |
def apply_threshold(matrix, low_value, high_value): | |
low_mask = matrix < low_value | |
matrix = apply_mask(matrix, low_mask, low_value) | |
high_mask = matrix > high_value | |
matrix = apply_mask(matrix, high_mask, high_value) | |
return matrix | |
def simplest_cb(img, percent): | |
assert img.shape[2] == 3 | |
assert percent > 0 and percent < 100 | |
half_percent = percent / 200.0 | |
channels = cv2.split(img) | |
out_channels = [] | |
for channel in channels: | |
assert len(channel.shape) == 2 | |
# find the low and high precentile values (based on the input percentile) | |
height, width = channel.shape | |
vec_size = width * height | |
flat = channel.reshape(vec_size) | |
assert len(flat.shape) == 1 | |
flat = np.sort(flat) | |
n_cols = flat.shape[0] | |
low_val = flat[math.floor(n_cols * half_percent)] | |
high_val = flat[math.ceil( n_cols * (1.0 - half_percent))] | |
print "Lowval: ", low_val | |
print "Highval: ", high_val | |
# saturate below the low percentile and above the high percentile | |
thresholded = apply_threshold(channel, low_val, high_val) | |
# scale the channel | |
normalized = cv2.normalize(thresholded, thresholded.copy(), 0, 255, cv2.NORM_MINMAX) | |
out_channels.append(normalized) | |
return cv2.merge(out_channels) | |
if __name__ == '__main__': | |
img = cv2.imread(sys.argv[1]) | |
out = simplest_cb(img, 1) | |
cv2.imshow("before", img) | |
cv2.imshow("after", out) | |
cv2.waitKey(0) |
why percent is divided by 200.
The percent parameter is expressed in natural language (number 5 means 5%) thus there is a division by 100 to express it at a fraction of 1, which is easier to work with (you do not need to normalize at each computation). The division by 2 is to get its half (half is used to cut the darks, half to cut the brights).
When you combine the two divisions, you get a division by 200.
@DavidYKay, @JackDesBwa, @jbonyun.
Thank you, guys. Excelent work. Thumb up!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
what is used of below line:
half_percent = percent / 200.0.
why percent is divided by 200.