Last active
October 4, 2019 11:14
-
-
Save Syncrossus/0546222a3c00b6fc953cad732f4fba6e to your computer and use it in GitHub Desktop.
Finds the dominant color in an image. Requires files from https://gist.github.com/Syncrossus/38e2886205602443620c871957ddfdd6
This file contains 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 sys | |
from math import ceil | |
from hsv_to_rgb import hsv_to_rgb | |
from rgb_to_hsv import rgb_to_hsv | |
def compress_color(pixel, level=16): | |
""" Compresses color by a specified factor. | |
Compressed colors are rounded up. | |
Args: | |
pixel<int, int, int>: an RGB triple to compress | |
level<int>: the desired amount of compression | |
Returns: | |
r, g, b: compressed RGB values | |
""" | |
r, g, b = pixel | |
# Using the ceil function here rounds up the colors in order | |
# for the compressed colors to always be at least as vibrant | |
# as in the original. Otherwise, vibrancy is easily lost. | |
r = min(ceil(r / level) * level, 255) | |
g = min(ceil(g / level) * level, 255) | |
b = min(ceil(b / level) * level, 255) | |
return r, g, b | |
def histogram(img): | |
""" Creates a histogram of an image. | |
This is a dict of the form {pixel_value: number} | |
Args: | |
img<list<list<?>>>: an image represented as a list | |
of rows with each row a list of pixels | |
Return: | |
histogram<dict<?:int>>: the histogram of the image | |
""" | |
histogram = {} | |
for row in img: | |
for px in row: | |
if px in histogram.keys(): | |
histogram[px] += 1 | |
else: | |
histogram[px] = 1 | |
return histogram | |
def get_dom_color(histogram): | |
""" Finds the dominant color in a histogram of HSV pixels | |
Args: | |
histogram<dict<([0-360],[0-1],[0-1]):int>>: | |
an HSV histogram as returned by _histogram() | |
Return: | |
dom_color<[0-360],[0-1],[0-1]>: the dominant color, an HSV triple | |
""" | |
counts = [v for k, v in histogram.items()] | |
total_px = sum(counts) | |
# eliminating colors that are less than 1% of the image | |
min_number_cutoff = 0.01 * total_px | |
histogram = {k: v for k, v in histogram.items() if v >= min_number_cutoff} | |
counts = [v for k, v in histogram.items()] | |
colors = list(histogram.keys()) | |
scores = {} | |
for i in range(len(colors)): | |
_, s, v = colors[i] | |
score = s + v + (counts[i] / total_px) | |
scores[score] = colors[i] | |
dom_color = scores[max(scores.keys())] | |
return dom_color | |
def read_img(f): | |
""" Reads the image. This returns a tuple of the form | |
(height, width, raw_image_data, other_metadata_dict) | |
""" | |
img = png.Reader(file=f).read() | |
raw_img = img[2] | |
step = 4 if img[3]['alpha'] else 3 | |
processed_img = [] | |
for row in raw_img: | |
new_row = [] | |
for i in range(0, len(row), step): | |
r, g, b = row[i], row[i + 1], row[i + 2] | |
new_row.append((r, g, b)) | |
processed_img.append(new_row) | |
return processed_img | |
def convert_image(img, fun, args=()): | |
""" Applies a pixel-wise function to an entire image. | |
Args: | |
img <list<list<tuple>>>: an image represented as a list of rows | |
with each row a list of pixels with each pixel a tuple | |
fun <func>: the function to apply | |
args <tuple>: arguments to pass on to the pixel-wise function | |
Return: | |
new_img: a new image (same representation as argument) after | |
the pixel-wise function has been applied | |
""" | |
new_img = [] | |
for row in img: | |
new_row = [] | |
for px in row: | |
new_row.append(fun(px, *args)) | |
new_img.append(new_row) | |
return new_img | |
if __name__ == '__main__': | |
# Getting file name | |
cmd_args = sys.argv[1:] | |
if len(cmd_args) == 1: | |
fname = cmd_args[0] | |
else: | |
fname = input('Filename : ') | |
# Processing the image | |
with open(fname, 'rb') as f: | |
img = read_img(f) | |
img = convert_image(img, compress_color, (32,)) | |
img = convert_image(img, rgb_to_hsv) | |
# Extracting the dominant color and converting it to RGB | |
dom_color = get_dom_color(histogram(img)) | |
dom_color = hsv_to_rgb(dom_color) | |
print(dom_color) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This code is released under the .