web-dev-qa-db-fra.com

Modifier le contraste de l'image dans PIL

J'ai un programme qui est censé changer le contraste, mais j'ai l'impression qu'il ne change pas vraiment le contraste, il change certaines zones en rouge alors que je ne le veux pas. Si vous pouviez me dire comment les supprimer, merci. Voici le code:

from PIL import Image


def change_contrast(img, level):

    img = Image.open("C:\\Users\\omar\\Desktop\\Site\\Images\\obama.png")
    img.load()

    factor = (259 * (level+255)) / (255 * (259-level))
    for x in range(img.size[0]):
        for y in range(img.size[1]):
            color = img.getpixel((x, y))
            new_color = Tuple(int(factor * (c-128) + 128) for c in color)
            img.putpixel((x, y), new_color)

    return img

result = change_contrast('C:\\Users\\omar\\Desktop\\Site\\Images\\test_image1.jpg', 100)
result.save('C:\\Users\\omar\\Desktop\\Site\\Images\\test_image1_output.jpg')
print('done')

Et voici l'image et son résultat:

obama.pngobama modified

S'il s'agit de la méthode de contraste réelle, n'hésitez pas à me le dire

11
Megzari Nassim

Je n'ai pas pu reproduire votre bug. Sur ma plate-forme (debian), seul le fork Pillow est disponible, donc si vous utilisez l'ancien package PIL, cela pourrait être la cause.

Dans tous les cas, il existe une méthode intégrée Image.point() pour effectuer ce type d'opération. Il cartographiera chaque pixel de chaque canal, ce qui devrait être plus rapide que de faire trois boucles imbriquées en python.

def change_contrast(img, level):
    factor = (259 * (level + 255)) / (255 * (259 - level))
    def contrast(c):
        return 128 + factor * (c - 128)
    return img.point(contrast)

change_contrast(Image.open('barry.png'), 100)

output

Votre sortie semble avoir un débordement dans un seul canal (rouge). Je ne vois aucune raison pour laquelle cela se produirait. Mais si votre level est supérieur à 259, la sortie est inversée. Quelque chose comme ça est probablement la cause du bogue initial.

def change_contrast_multi(img, steps):
    width, height = img.size
    canvas = Image.new('RGB', (width * len(steps), height))
    for n, level in enumerate(steps):
        img_filtered = change_contrast(img, level)
        canvas.paste(img_filtered, (width * n, 0))
    return canvas

change_contrast_multi(Image.open('barry.png'), [-100, 0, 100, 200, 300])

another output

Une solution possible consiste à s'assurer que le filtre de contraste ne renvoie que des valeurs dans la plage [0-255], car le bogue semble provenir de débordements de valeurs négatives.

def change_contrast(img, level):
    factor = (259 * (level + 255)) / (255 * (259 - level))
    def contrast(c):
        value = 128 + factor * (c - 128)
        return max(0, min(255, value))
    return img.point(contrast)
17
Håken Lid

Il y a déjà construit une classe appelée contraste dans le module PIL. Vous pouvez simplement l'utiliser.

from PIL import Image, ImageEnhance
image = Image.open(':\\Users\\omar\\Desktop\\Site\\Images\\obama.png')
scale_value=scale1.get()
image = ImageEnhance.Contrast(image).enhance(scale_value)
image.show()
11
orvi