PIL / Pillow est une bibliothèque d'images compacte et rapide pour Python. Nous avons résumé les processus fréquemment utilisés (mis à jour de temps en temps)
Il n'y a pratiquement aucune raison d'utiliser PIL, Pillow a une correction de bogue pour le filtre de redimensionnement et est de meilleure qualité.
Pillow est réglé très rapidement et fonctionne toujours plus vite qu'une bibliothèque similaire, ImageMagick.
Cependant, getpixel
/ putpixel
est très lent, donc ne l'utilisez pas pour autre chose que la génération d'images.
Il existe également un «oreiller-simd» plus rapide. Il semble être environ 4 à 5 fois plus rapide que l'oreiller d'origine.
pillow-simd https://github.com/uploadcare/pillow-simd
https://python-pillow.org/pillow-perf/
mode | La description |
---|---|
1 | Utilisé pour le masque 1 bit, le calcul logique est possible |
L | Échelle de gris 8 bits |
P | Mode palette |
RGB | 8bit x 3 |
RGBA | Transparence 8 bits x 4(alpha)Avec |
CMYK | 8 bits x 4 couramment utilisé pour l'impression |
YCbCr | Souvent utilisé pour la vidéo 8 bits x 3 |
HSV | Oreiller 8 bits x 3 uniquement |
RGBa | Multiplier la valeur RVB par le canal alpha |
LA | Multipliez la valeur L par le canal alpha |
I | Entier 32 bits |
F | Minorité flottante 32 bits |
filtre | Réduction de la qualité | Upscaling qualité | performance |
---|---|---|---|
Image.NEAREST | ⭐⭐⭐⭐⭐ | ||
Image.BOX | ⭐ | ⭐⭐⭐⭐ | |
Image.BILINEAR | ⭐ | ⭐ | ⭐⭐⭐ |
Image.HAMMING | ⭐⭐ | ⭐⭐⭐ | |
Image.BICUBIC | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
Image.LANCZOS | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐ |
img.convert("L")
alpha.convert("LA")
→
Au fait, convert ('L')
ne considère pas la valeur alpha.
alpha.convert("L")
→
img.convert("HSV")
Seul l'oreiller peut être converti en espace colorimétrique HSV. Il est composé de trois composants: Teinte, Saturation et Valeur. Voici un exemple de décalage de la roue chromatique.
h, s, v = img.convert("HSV").split()
_h = ImageMath.eval("(h + 128) % 255", h=h).convert("L")
Image.merge("HSV", (_h, s, v)).convert("RGB")
CIE XYZ est un espace colorimétrique ajusté pour que la distance euclidienne entre les couleurs soit la même que la différence perçue par les humains.
rgb2xyz = (
0.412453, 0.357580, 0.180423, 0,
0.212671, 0.715160, 0.072169, 0,
0.019334, 0.119193, 0.950227, 0
)
img.convert("RGB", rgb2xyz)
gray = img.convert("L") #Convertir en échelle de gris
gray.point(lambda x: 0 if x < 230 else x) #Si la valeur est inférieure ou égale à 230, elle sera égale à 0.
img.point(lambda x: x * 1.5) # 1.Rendre 5 fois plus lumineux
img.point(lambda x: x * 0.5) # 1 /Assombrir à 2
Convertissez l'image en échelle de gris, puis en sépia.
gray = img.convert("L")
Image.merge(
"RGB",
(
gray.point(lambda x: x * 240 / 255),
gray.point(lambda x: x * 200 / 255),
gray.point(lambda x: x * 145 / 255)
)
)
La correction gamma peut également être convertie à une vitesse très élevée en utilisant une table de consultation. En supposant que src = couleur d'entrée, γ = valeur gamma et g = valeur de gain, la formule de correction gamma est la suivante.
dst = \biggl(\frac{src}{255}\biggr)^{1/γ} \times g \times 255
def gamma_table(gamma_r, gamma_g, gamma_b, gain_r=1.0, gain_g=1.0, gain_b=1.0):
r_tbl = [min(255, int((x / 255.) ** (1. / gamma_r) * gain_r * 255.)) for x in range(256)]
g_tbl = [min(255, int((x / 255.) ** (1. / gamma_g) * gain_g * 255.)) for x in range(256)]
b_tbl = [min(255, int((x / 255.) ** (1. / gamma_b) * gain_b * 255.)) for x in range(256)]
return r_tbl + g_tbl + b_tbl
img.point(gamma_table(1.2, 0.5, 0.5))
Il vaut mieux ne pas passer lambda
à ʻImage.point dans la boucle, il est plus rapide de l'étendre à l'avance car l'argument passé à
point` n'est qu'une table de conversion.
for ...:
img.point(lambda x: x * 100)
#Le processus inférieur est égal au processus supérieur mais plus rapide
table = [x * 100 for x in range(256)] * len(img.getbands())
for ...:
img.point(table)
getbbox
ʻImage.getbbox renvoie la plus petite valeur non nulle de l'image, une image avec toutes les valeurs 0 renvoie
None`.
alpha = Image.open("alpha.png ")
crop = alpha.split()[-1].getbbox()
alpha.crop(crop)
→
Si les deux images sont identiques, ʻImageChops.difference renvoie toutes les 0 images, donc si
getbboxvaut
None`, il peut être considéré comme identique.
ImageChops.difference(img1, img2).getbbox() is None
img.resize((128, 128), Image.LANCZOS)
Contrairement au redimensionnement, les miniatures conservent leur rapport hauteur / largeur. Notez que pour une raison quelconque, «miniature» est une méthode destructive, c'est «Image.copy» donc c'est une bonne idée de faire une copie.
img.thumbnail((128, 128), Image.LANCZOS)
img.size
# (128, 79)
Spécifier «True» pour l'argument «développer» développe l'image si elle grandit lors de la rotation.
img.rotate(90, expand=True)
Le traitement de la mosaïque peut être réduit et agrandi avec ʻImage.LINEAR`, mais si vous le réduisez après avoir appliqué un flou gaussien, ce sera une mosaïque douce.
#Mosaïque dentelée
img.resize([x // 8 for x in img.size]).resize(img.size)
#Appliquer un flou gaussien pour une mosaïque douce
gimg = img.filter(ImageFilter.GaussianBlur(4))
gimg.resize([x // 8 for x in img.size]).resize(img.size)
Image.blend(img,effect_img, 0.5)
img.quantize(4) #Réduit à 4 couleurs
Pour coller une image avec alpha, spécifiez l'image avec alpha dans l'argument'mask 'de ʻImage.paste`.
img.paste(alpha, mask=alpha)
ʻImage.getcolors`, qui compte les couleurs utilisées, ne peut pas compter plus de 255 couleurs sans argument. Pour les images qui utilisent plus de 255 couleurs, il est prudent de transmettre le nombre de pixels comme argument. [^ 1]
[^ 1]: 2017-02-07 Corrigé C'était'Image.getcount ', mais c'est correctement'Image.getcolors', je vais le réparer.
img.getcolors(img.size[0] * img.size[1])
Renvoie une liste d'histogrammes de couleurs d'image. Comme chaque bande est renvoyée successivement, 256 x 3 = 768 éléments sont renvoyés en mode RVB.
img.histogram()
Il n'y a pas de méthode pour remplacer les couleurs, si vous souhaitez remplacer les couleurs, veuillez vous référer à l'article ci-dessous.
Remplacez rapidement les couleurs de l'image par PIL / Pillow
ImageOps.invert(img)
ImageOps.mirror(img) #Retourner horizontalement
ImageOps.flip(img) #retourner à l'envers
Colore les images en niveaux de gris avec une valeur de pixel de 0 à «noir» et une valeur de pixel de 255 à «blanc».
gray = ImageOps.grayscale(img)
ImageOps.colorize(gray, black=(0, 0, 0), white=(255, 255, 0))
→
Réduit la profondeur de bits de l'image à la valeur de l'argument pour simplifier la couleur.
ImageOps.posterize(img, 2)
Inverse toutes les valeurs de pixel au-dessus du seuil. Je ne sais pas où l’utiliser.
ImageOps.solarize(img, 128)
Égalisez l'histogramme de l'image. Appliquez un mappage non linéaire à l'image d'entrée pour créer une distribution uniforme des valeurs de niveaux de gris dans l'image de sortie.
ImageOps.equalize(img)
Le module ʻImageChops` est un module de manipulation des canaux.
L'image de gauche est l'image à affecter, et l'image de droite est l'image des effets.Dans ce chapitre, nous utiliserons ces deux images comme échantillons.
ImageChops.add(img, effect_img) # img + effect_img
ImageChops.subtract(img, effect_img) # img - effect_img
ImageChops.add_modulo(img, effect_img) # img + effect_img % MAX
ImageChops.subtract_modulo(img, effect_img) # img - effect_img % MAX
ImageChops.multiply(img, effect_img)
ImageChops.screen(img, effect_img)
ImageChops.lighter(img, effect_img)
ImageChops.darker(img, effect_img)
ImageChops.difference(img, effect_img)
ImageChops.offset(img, 100, 100)
Effectue la convolution (calcul de convolution). Diverses conversions d'image sont effectuées en réorganisant la matrice appelée noyau.
Paramètres | La description |
---|---|
size | Taille du noyau |
scale | Divisez par cette valeur après l'opération de la matrice |
offset | Ajouter à cette valeur après l'opération de la matrice |
kernel | Matrice de convolution |
https://github.com/python-pillow/Pillow/blob/6e7553fb0f12025306b2819b9b842adf6b598b2e/PIL/ImageFilter.py
ImageFilter.BLUR
img.filter(ImageFilter.BLUR)
# size: (5, 5),
# scale: 16,
# offset: 0,
# kernel:(
# 1, 1, 1, 1, 1,
# 1, 0, 0, 0, 1,
# 1, 0, 0, 0, 1,
# 1, 0, 0, 0, 1,
# 1, 1, 1, 1, 1
# )
ImageFilter.DETAIL
img.filter(ImageFilter.DETAIL)
# size: (3, 3),
# scale: 6,
# offset: 0,
# kernel: (
# 0, -1, 0,
# -1, 10, -1,
# 0, -1, 0
# )
ImageFilter.SHAPEN
img.filter(ImageFilter.SHARPEN)
# size: (3, 3),
# scale: 16,
# offset: 0,
# kernel: (
# -2, -2, -2,
# -2, 32, -2,
# -2, -2, -2
# )
ImageFilter.CONTOUR
img.filter(ImageFilter.CONTOUR)
# size: (3, 3),
# scale: 1,
# offset: 255,
# kernel: (
# -1, -1, -1,
# -1, 8, -1,
# -1, -1, -1
# )
ImageFilter.EDGE_ENHANCE / ImageFilter.EDGE_ENHANCE_MORE
img.filter(ImageFilter.EDGE_ENHANCE)
# size: (3, 3),
# scale: 2,
# offset: 0,
# kernel: (
# -1, -1, -1,
# -1, 10, -1,
# -1, -1, -1
# )
img.filter(ImageFilter.EDGE_ENHANCE_MORE)
# size: (3, 3),
# scale: 1,
# offset: 0,
# kernel: (
# -1, -1, -1,
# -1, 9, -1,
# -1, -1, -1
# )
ImageFilter.EMBOSS
img.filter(ImageFilter.EMBOSS)
# size: (3, 3),
# scale: 1,
# offset: 128,
# kernel: (
# -1, 0, 0,
# 0, 1, 0,
# 0, 0, 0
# )
ImageFilter.FIND_EDGES
img.filter(ImageFilter.FIND_EDGES)
# size: (3, 3),
# scale: 1,
# offset: 0,
# kernel: (
# -1, -1, -1,
# -1, 8, -1,
# -1, -1, -1
# )
ImageFilter.SMOOTH / ImageFilter.SMOOTH_MORE
img.filter(ImageFilter.SMOOTH)
# size: (3, 3),
# scale: 13,
# offset: 0,
# kernel: (
# 1, 1, 1,
# 1, 5, 1,
# 1, 1, 1
# )
#
img.filter(ImageFilter.SMOOTH_MORE)
# size: (5, 5),
# scale: 100,
# offset: 0,
# kernel: (
# 1, 1, 1, 1, 1,
# 1, 5, 5, 5, 1,
# 1, 5, 44, 5, 1,
# 1, 5, 5, 5, 1,
# 1, 1, 1, 1, 1
# )
Flou gaussienにより画面の平滑化します。
img.filter(ImageFilter.GaussianBlur(1.0))
img.filter(ImageFilter.GaussianBlur(1.5))
img.filter(ImageFilter.GaussianBlur(3.0))
«MaxFilter» est appelé Dilation et «MinFilter» est appelé Erosion.
img.filter(ImageFilter.MinFilter())
img.filter(ImageFilter.MaxFilter())
Expansion / contraction / ouverture / fermeture
«MedianFilter» est souvent utilisé pour supprimer le bruit, et ses contours sont moins flous que les filtres gaussiens.
img.filter(ImageFilter.MedianFilter())
→
Sélectionne la valeur de pixel la plus fréquemment utilisée dans une boîte de la taille spécifiée. Les valeurs de pixel qui n'apparaissent qu'une ou deux fois sont ignorées. ~~ Je ne sais pas où l'utiliser. Voir ~~ Faire ressembler les photos à des peintures avec le filtre de mode d'oreiller.
img.filter(ImageFilter.ModeFilter(5))
enhancer = ImageEnhance.Color(img)
enhancer.enhance(0.0) #Noir et blanc
enhancer.enhance(0.5) # ↕
enhancer.enhance(1.0) #L'image originale
enhancer = ImageEnhance.Contrast(img)
enhancer.enhance(0.0) #Image grise
enhancer.enhance(0.5) # ↕
enhancer.enhance(1.0) #L'image originale
enhancer = ImageEnhance.Brightness(img)
enhancer.enhance(0.0) #Image noire
enhancer.enhance(0.5) # ↕
enhancer.enhance(1.0) #L'image originale
enhancer = ImageEnhance.Sharpness(img)
enhancer.enhance(0.0) #Image floue
enhancer.enhance(0.5) # ↕
enhancer.enhance(1.0) #L'image originale
enhancer.enhance(1.5) # ↕
enhancer.enhance(2.0) #Image nette
Le module ʻImageMath` est un module qui vous permet d'écrire des opérations entre les pixels comme s'il s'agissait d'opérations numériques. Si vous le maîtrisez, vous pourrez facilement écrire des traitements d'images complexes.
lambda
au lieu d'opérationsComme il ne peut traiter que des bandes uniques, il est gênant lors de la conversion d'images telles que RVB, c'est donc une bonne idée de préparer les fonctions d'assistance suivantes.
def _blend_f(img1, img2, func):
blend_eval = "convert(func(float(a), float(b)), 'L')"
bands = [
ImageMath.eval(
blend_eval,
a=a,
b=b,
func=func
)
for a, b in zip(img1.split(), img2.split())
]
return Image.merge(img1.mode, bands)
Implémentez des modes de dessin tels que PhotoShop à grande vitesse avec PIL / Pillow
def _over_lay(a, b):
_cl = 2 * a * b / 255
_ch = 2 * (a + b - a * b / 255) - 255
return _cl * (a < 128) + _ch * (a >= 128)
_blend_f(img, effect_img, _over_lay)
def _soft_light(a, b):
_cl = (a / 255) ** ((255 - b) / 128) * 255
_ch = (a / 255) ** (128 / b) * 255
return _cl * (b < 128) + _ch * (b >= 128)
_blend_f(img, effect_img, _soft_light)
def _hard_light(a, b):
_cl = 2 * a * b / 255
_ch = 2.0 * (a + b - a * b / 255.0) - 255.0
return _cl * (b < 128) + _ch * (b >= 128)
_blend_f(img, effect_img, _hard_light)
Je crée un module appelé "Image4Layer" qui implémente le mode dessin de Photoshop.
https://github.com/pashango2/Image4Layer
L'installation est facile avec pip, l'oreiller (PIL) doit être pré-installé pour fonctionner.
$pip install image4layer
C'est facile à utiliser, c'est un exemple de composition en mode couleur-esquive.
from PIL import Image
from image4layer import Image4Layer
source = Image.open("ducky.png ")
backdrop = Image.open("backdrop.png ")
Image4Layer.color_dodge(backdrop, source)
Vous pouvez écrire plusieurs GIF (animations GIF).
im.save(out, save_all=True, append_images=[im1, im2, ...])
Ceci est un exemple de création d'un simple GIF animé.
imgs = []
for i in range(100):
imgs.append(img.point(lambda x: x * (1.0 - (i/100))))
img.save("anime.gif", save_all=True, append_images=imgs, loop=True)
http://pillow.readthedocs.io/en/4.0.x/handbook/image-file-formats.html?highlight=seek#saving
La conversion de PyQt en QImage utilise le module ʻImageQt`.
ImageQt.ImageQt(img)
Si vous utilisez PySide, la méthode suivante est recommandée.
from PySide.QtGui import *
import io
img_buffer = io.BytesIO()
base.save(img_buffer, "BMP")
qimage = QImage()
qimage.loadFromData(img_buffer.getvalue(), "BMP")
Cela peut sembler un processus inutile, mais Pillow / PySide s'occupera des parties gênantes telles que la conversion RVB → BGR et le problème d'inversion de l'axe Y.
[Conversion mutuelle entre PIL.Image et PyQt4.QtGui.QImage](http://doloop While.hatenablog.com/entry/20100305/1267782841)
PSNR
Une valeur d'index qui compare le PSNR à deux images. Actuellement, SSIM est meilleur que PSNR, mais PSNR est également souvent utilisé. Plus la valeur est élevée, meilleure est la qualité d'image, et lors de la mesure du degré de détérioration de la compression, un PSNR compris entre 30 et 50 est la qualité standard.
La formule est la suivante: MSE est l'erreur quadratique moyenne et MAX est 255.
PSNR = 10 \times \log 10\frac{MAX^2}{MSE}
La fonction pour trouver le PSNR est la suivante: Vous pouvez trouver le PSNR à grande vitesse en utilisant le module ʻImageStat`.
def psnr(img1, img2):
diff_img = ImageChops.difference(img1, img2)
stat = ImageStat.Stat(diff_img)
mse = sum(stat.sum2) / len(stat.count) / stat.count[0]
return 10 * math.log10(255 ** 2 / mse)
Il est actuellement difficile de trouver SSIM à grande vitesse avec PIL / Pillow, il est donc préférable d'utiliser le module pyssim ou OpenCV.
[Rapport signal / bruit de crête - Wikipedia](https://ja.wikipedia.org/wiki/%E3%83%94%E3%83%BC%E3%82%AF%E4%BF%A1%E5%8F % B7% E5% AF% BE% E9% 9B% 91% E9% 9F% B3% E6% AF% 94)
gray = img.convert("L")
gray2 = gray.filter(ImageFilter.MaxFilter(5))
senga_inv = ImageChops.difference(gray, gray2)
senga = ImageOps.invert(senga_inv)
J'ai évoqué la méthode de ici, c'est très merveilleux.
Recommended Posts