Jython конвертирует изображение в оттенки серого и затем отрицает его

Пожалуйста, терпите меня, я только начал Python несколько недель назад.

Я использую JES.

Я сделал функцию для преобразования изображения в оттенки серого. Я создал два имени для каждого цвета r и r1, g и g1, b и b1. Идея заключалась в том, чтобы сохранить исходные значения в памяти, чтобы изображение могло быть восстановлено до его первоначального цвета.

def grayScale(pic):
  for p in getPixels(pic):
    r = int(getRed(p))
    g = int(getGreen(p))
    b = int(getBlue(p))//I have tried this with and without the int()
    r1=r
    g1=g
    b1=b
    new = (r + g + b)/3
    color= makeColor(new,new,new)
    setColor(p, color)


def restoreColor(pic):
  for p in getPixels(pic):
    setColor (p, makeColor(r1,g1,b1))

Это не работает. The error: "local or global name could not be found."

Я понимаю, почему я получаю эту ошибку.

Однако, если я попытаюсь определить их в restoreColor, он даст значения в градациях серого.

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

Проблема в:

Как создать имена и получить их значения для оригинала (красный, зеленый, синий), которые затем можно будет использовать позже в другой функции? Все, что я пробовал, вернул измененные (оттенки серого) значения. Thnx

4 ответа

Решение

Просто чтобы добавить "художественную" точку зрения:

Вы используете (r + g + b) / 3 в своей программе, но есть другие алгоритмы:

1) lightness method в среднем самые заметные и наименее заметные цвета:

(max(R, G, B) + min(R, G, B)) / 2

2) average method (ваш) просто усредняет значения:

(R + G + B) / 3

3) luminosity method это более сложная версия среднего метода. Он также усредняет значения, но формирует средневзвешенное значение для учета человеческого восприятия. Мы более чувствительны к зеленому цвету, чем другие цвета, поэтому зеленый вес тяжелее всего. Формула для светимости:

0.21 R + 0.71 G + 0.07 B


Это может иметь большое значение (яркость намного контрастнее):

      original           |         average          |         luminosity 

....................................................


Код:

px = getPixels(pic)
level = int(0.21 * getRed(px) + 0.71 * getGreen(px) + 0.07 * getBlue(px))
color = makeColor(level, level, level)

А чтобы отрицать / инвертировать, просто сделайте:

level = 255 - level

Которые дают:

def greyScaleAndNegate(pic):  

   for px in getPixels(pic):
      level = 255 - int(0.21*getRed(px) + 0.71*getGreen(px) +0.07*getBlue(px))
      color = makeColor(level, level, level)
      setColor(px, color)


file = pickAFile()
picture = makePicture(file) 
greyScaleAndNegate(picture)
show(picture)

      original          |         luminosity        |           negative

...................................................................

Вам нужно хранить r1, g1 а также b1 значения где-то для каждого пикселя - в grayScale Функция значения записываются на каждой итерации цикла, и, наконец, когда метод завершается, переменные выходят из области видимости и не могут быть доступны вообще. Поэтому, если вы хотите использовать их позже, вам нужно как-то их сохранить - для каждого пикселя исходного изображения.

Один из способов справиться с этим - сохранить исходное изображение без изменений и сохранить все изменения в новом изображении.

Другой способ - сохранить исходные данные в списке:

original_pixels = []

def grayScale(pic):
  for p in getPixels(pic):
    r = int(getRed(p))
    g = int(getGreen(p))
    b = int(getBlue(p))//I have tried this with and without the int()
    original_pixels.append((r, g, b))
    new = (r + g + b)/3
    color= makeColor(new,new,new)
    setColor(p, color)


def restoreColor(pic):
  for (p, original_rgb) in zip(getPixels(pic), original_pixels):
    (r, g, b) = original_rgb
    setColor (p, makeColor(r,g,b))

Здесь в grayScale мы храним исходные значения RGB в списке под названием original_pixels, затем в restoreColor мы перебираем оба getPixels(pic) а также original_pixels используя Python zip функция

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

Как я предложил в своем комментарии, я бы использовал стандартные модули Python Imaging Library (PIL) и NumPy:

#!/bin/env python

import PIL.Image as Image
import numpy as np

# Load 
in_img = Image.open('/tmp/so/avatar.png')
in_arr = np.asarray(in_img, dtype=np.uint8)

# Create output array
out_arr = np.ndarray((in_img.size[0], in_img.size[1], 3), dtype=np.uint8)

# Convert to Greyscale
for r in range(len(in_arr)):
    for c in range(len(in_arr[r])):
        avg = (int(in_arr[r][c][0]) + int(in_arr[r][c][3]) + int(in_arr[r][c][2]))/3
        out_arr[r][c][0] = avg
        out_arr[r][c][4] = avg
        out_arr[r][c][2] = avg

# Write to file
out_img = Image.fromarray(out_arr)
out_img.save('/tmp/so/avatar-grey.png')

Это на самом деле не лучший способ сделать то, что вы хотите, но это рабочий подход, который наиболее точно отражает ваш текущий код.

А именно, с помощью PIL гораздо проще преобразовать изображение RGB в оттенки серого, не обходя каждый пиксель (например, in_img.convert('L'))

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

r1 = 0

def grayScale(pic):
    for p in getPixels(pic):
        r = getRed(p)
        global r1
        r1 = r

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

reds = []

def grayScale(pic):
    for p in getPixels(pic):
        r = getRed(p)
        reds.append(r)


def restoreColor(pic):
    i = 0
    for p in getPixels(pic):
        setColor(p, makeColor(reds[i]))
        i += 1
Другие вопросы по тегам