1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
import numpy as np
from PIL import ImageFont
class ImageColorGenerator(object):
"""Color generator based on a color image.
Generates colors based on an RGB image. A word will be colored using
the mean color of the enclosing rectangle in the color image.
After construction, the object acts as a callable that can be passed as
color_func to the word cloud constructor or to the recolor method.
Parameters
----------
image : nd-array, shape (height, width, 3)
Image to use to generate word colors. Alpha channels are ignored.
This should be the same size as the canvas. for the wordcloud.
default_color : tuple or None, default=None
Fallback colour to use if the canvas is larger than the image,
in the format (r, g, b). If None, raise ValueError instead.
"""
# returns the average color of the image in that region
def __init__(self, image, default_color=None):
if image.ndim not in [2, 3]:
raise ValueError("ImageColorGenerator needs an image with ndim 2 or"
" 3, got %d" % image.ndim)
if image.ndim == 3 and image.shape[2] not in [3, 4]:
raise ValueError("A color image needs to have 3 or 4 channels, got %d"
% image.shape[2])
self.image = image
self.default_color = default_color
def __call__(self, word, font_size, font_path, position, orientation, **kwargs):
"""Generate a color for a given word using a fixed image."""
# get the font to get the box size
font = ImageFont.truetype(font_path, font_size)
transposed_font = ImageFont.TransposedFont(font,
orientation=orientation)
# get size of resulting text
box_size = transposed_font.getbbox(word)
x = position[0]
y = position[1]
# cut out patch under word box
patch = self.image[x:x + box_size[2], y:y + box_size[3]]
if patch.ndim == 3:
# drop alpha channel if any
patch = patch[:, :, :3]
if patch.ndim == 2:
raise NotImplementedError("Gray-scale images TODO")
# check if the text is within the bounds of the image
reshape = patch.reshape(-1, 3)
if not np.all(reshape.shape):
if self.default_color is None:
raise ValueError('ImageColorGenerator is smaller than the canvas')
return "rgb(%d, %d, %d)" % tuple(self.default_color)
color = np.mean(reshape, axis=0)
return "rgb(%d, %d, %d)" % tuple(color)
|