Lors du remplacement des couleurs par PIL / Pillow, le moyen le plus simple de trouver est d'utiliser Image.getpixel / Image.putpixel.
Cependant, Image.getpixel / Image.putpixel est si lent qu'il faut quelques secondes pour traiter une seule image, ce qui est très lent. Il existe une méthode de remplacement rapide utilisant numpy, mais il semble insensé d'augmenter le nombre de modules dépendants lors du remplacement des couleurs.
Par conséquent, j'ai pensé à une méthode pour remplacer les couleurs à grande vitesse avec uniquement PIL / Pillow.
À titre d'exemple, remplaçons la couleur des vêtements (255, 204, 0) dans l'image ci-dessous par (48, 255, 48).
L'image est RVB 24 bits sans alpha et le code est écrit en python2.
Tout d'abord, utilisez Image.split pour diviser l'image en bandes pour chaque couleur.
from __future__ import unicode_literals, print_function, absolute_import
from PIL import Image, ImageChops
img = Image.open("sample.png ")
r, g, b = img.split()
Le contenu de chaque bande RVB est le suivant.
src_color = (255, 204, 0)
_r = r.point(lambda _: 1 if _ == src_color[0] else 0, mode="1")
_g = g.point(lambda _: 1 if _ == src_color[1] else 0, mode="1")
_b = b.point(lambda _: 1 if _ == src_color[2] else 0, mode="1")
Image.point est une méthode de conversion de table. Cette fois, lambda est utilisé pour générer une image qui extrait uniquement des valeurs spécifiques pour chaque bande.
Le fait est que mode = "1" est spécifié dans l'argument, et si "1" est spécifié dans mode, une image avec une profondeur de couleur de 1 bit est générée. Il s'agit du processus requis pour la conversion dans le module ImageChops décrit plus loin.
Le contenu de chaque bande RVB est le suivant.
Le module ImageChops est un module pratique qui peut effectuer divers processus de composition tels que la composition d'addition et la composition de multiplication.
Cette fois, la composition ET est effectuée à l'aide de ImageChops.logical_and. Cette méthode n'accepte que les images avec mode = "1".
mask = ImageChops.logical_and(_r, _g)
mask = ImageChops.logical_and(mask, _b)
Vous pouvez créer un masque qui extrait les pixels de 1 dans toutes les bandes (c'est-à-dire une couleur spécifique).
Tout ce que vous avez à faire est d'utiliser ce masque pour peindre la couleur que vous souhaitez remplacer.
dst_color = (48,255,48)
img.paste(Image.new("RGB", img.size, dst_color), mask=mask)
J'ai comparé le traitement avec le cas de l'utilisation de getpixel / putpixel.
In [27]: %time replace_put_pixel(img, src_color, dst_color)
Wall time: 234 ms
In [28]: %time replace_fast(img, src_color, dst_color)
Wall time: 1.96 ms
La version getpixel / putpixel a 234 ms, tandis que cette méthode a 1,96 ms. C'est plus de 100 fois plus rapide.
Recommended Posts