PIL putpixel ничего не делает - PullRequest
0 голосов
/ 11 ноября 2018

В старших классах мы начинаем с Python, и нас просят запрограммировать небольшой процессор изображений с помощью модуля Pillow. Цель состоит в том, чтобы открыть файл, а затем выбрать фильтр.

Первый фильтр, который я попытался запрограммировать, - это изменение цветовой температуры. Но есть также минималистский интерфейс с tkinter, который показывает некоторые кнопки и работает без проблем.

Вот функция, которая открывает файл

def Ouvrir():
    fichier = askopenfilename(title="Ouvrir une image",filetypes=[('jpg files','.jpg'),('all files','.*')])
    global img
    img =Image.open(fichier)
    l, h = img.size
    img.show()   #visualisation de l'image

    global img2
    img2 = img #img2 est une copie de img

Создает глобальный img объект изображения, который загружается из файла. Затем l и h загружаются с шириной и высотой изображения.

Еще одно глобальное изображение объекта img2 создано для выходного изображения и является копией img.

Тогда вот функция, которая обрабатывает изображение

def filtreTC(): #Filtre permettant de changer la température de couleur
    coef = sliderTC.get() / 100 #On récupère le coefficient à partir de l'échelle. Le coefficient compris entre -1 et 1: -1 = froid (image bleu-vert), 0 = neutre, 1 = chaud (image orangée)
    fenTC.destroy() #On ferme la fenêtre
    if(coef <= 0): #Calcul des coefficients rouges, verte et bleus
        coefR = 1 + coef
        coefV = 1 + (coef / 2)
        coefB = 1
    else:
        coefR = 1
        coefV = 1 - (coef / 2)
        coefB = 1 - coef
    for y in range(0, h, 1):
        for x in range(0, l, 1):
            r, v, b = img.getpixel((x, y))
            r = int(float(r * coefR))
            v = int(float(v * coefV))
            b = int(float(b * coefB))
            img2.putpixel((x, y), (r, v, b))
    img2.show()

Это цикл, который просматривает все изображение и берет пиксель из img, умножает его значения rgb на соответствующие им коэффициенты, а затем помещает этот пиксель в img2

Проблема в том, что это не работает. Он не выдает никаких ошибок, но когда он показывает img2, это то же самое, что и img1, как если бы функция putpixel ничего не делала.

Я много чего проверил, поэтому знаю, что проблема не в значениях rgb и не в координатах x / y.

  • Я попытался заменить img2 = img на img2 = Image.new("RGB", (l, h)) и получаю черное изображение.
  • Затем я попытался заменить img2.putpixel((x, y), (r, v, b)) на img2.putpixel((100, 100), (127, 127, 127)), чтобы получить серый пиксель в верхнем левом углу. Но я все еще получил черное изображение.

Затем я попытался удалить

global img2
img2 = img

из функции, которая открывает файл и ставит

img2 = Image.new("RGB", (l, h))

сразу после fenTC.destroy() и я получил это:

Exception in Tkinter callback
Traceback (most recent call last):
  File "e:\xxxx\programmes\anaconda\lib\tkinter\__init__.py", line 1702, in __call__
    return self.func(*args)
  File "H:\ISN\Programmes\TP-image\projet.py", line 62, in filtreTC
    img2.show()
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2016, in show
    _show(self, title=title, command=command)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2876, in _show
    _showxv(image, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 2881, in _showxv
    ImageShow.show(image, title, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 51, in show
    if viewer.show(image, title=title, **options):
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 75, in show
    return self.show_image(image, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 95, in show_image
    return self.show_file(self.save_image(image), **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageShow.py", line 91, in save_image
    return image._dump(format=self.get_format(image), **self.options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 639, in _dump
    self.save(filename, format, **options)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\Image.py", line 1969, in save
    save_handler(self, fp, filename)
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\BmpImagePlugin.py", line 319, in _save
    (rawmode, stride, -1))])
  File "e:\xxxx\programmes\anaconda\lib\site-packages\PIL\ImageFile.py", line 512, in _save
    e.setimage(im.im, b)
SystemError: tile cannot extend outside image

В основном много вещей, я понятия не имею, что это значит, кроме:

SystemError: tile cannot extend outside image

Я проверил координаты x и y, и они никогда не выходили за границы, поэтому я не понимаю, что это за ошибка.

Я потратил несколько часов, чтобы попытаться выяснить, в чем проблема, и перепробовал много разных вещей, но ни одна из них не сработала. Поэтому я подумал, что лучше обратиться за помощью

1 Ответ

0 голосов
/ 11 ноября 2018

Ваша проблема в том, что вы не создали копию .img2 = img создает другую ссылку на тот же объект, а не новое отдельное изображение.

Чтобы создать фактическую копию, используйте метод image.copy() :

img2 = img.copy()

Далее я бы не использовал петли и комбинации getpixel() / putpixel().Вы выполняете двойную работу для значений RGB, которые появляются более одного раза.Если вы используете метод image.point(), тогда вы сможете использовать свою формулу для каждого уникального значения в каждой полосе на изображении и оставить цикл по всем пикселям в библиотеке (намного быстрее).Это также делает копию изображения для вас!

Вам необходимо создать таблицу;для значений от 0 до 255 для значений R, G и B рассчитайте возможный результат и поместите эти результаты 3 * 256 в длинный список:

coefG = [i * (1 - (coef / 2)) for i in range(256)]
if coef <= 0:
    coefR = [i * (1 + coef) for i in range(256)]
    coefB = list(range(256))
else:
    coefR = list(range(256))
    coefB = [i * (1 - coef) for i in range(256)]
img2 = img1.point(coefR + coefG + coefB)

Результирующая таблица используется для каждого уникального значения цветав изображении.

Вы также можете разделить изображение RGB на отдельные полосы, применить различные формулы коэффициентов к каждой отдельной полосе как функцию, а затем повторно объединить полосы в новое изображение:

r, g, b = img.split()
g = g.point(lambda i: i * (1 - (coef / 2)))
if coef <= 0:
    r = r.point(lambda i: i * (1 + coef))
else:
    b = b.point(lambda i: i * (1 - coef))
img = Image.merge('RGB', (r, g, b))

При создании фильтра изображения вы действительно хотите передать входное изображение в качестве аргумента функции , а не использовать глобальные переменные.Также передайте коэффициент:

def filtreTC(source_image, coef):
    coefG = [i * (1 - (coef / 2)) for i in range(256)]
    if coef <= 0:
        coefR = [i * (1 + coef) for i in range(256)]
        coefB = list(range(256))
    else:
        coefR = list(range(256))
        coefB = [i * (1 - coef) for i in range(256)]
    return source_image.point(coefR + coefG + coefB)

Вы можете сохранить результат вызова в глобальном формате, если необходимо, но теперь функция может стоять сама по себе и может использоваться повторно везде, гдеимеет объект изображения RGB PIL.Вы бы вызвали функцию со значением ползунка:

coef = sliderTC.get() / 100
fenTC.destroy()
img2 = filtreTC(img, coef)

Используя вышеупомянутое изображение вашего профиля

question-asker profile image, a chip

сКоэффициент 0,75 дает нам:

same profile image, but turned orange

, а -0,75 приводит к:

same profile image, but now blue

...