Получение списка значений пикселей из PIL - PullRequest
27 голосов
/ 10 июля 2009

Ребята, я ищу немного помощи. Я начинающий программист, и одна из проблем, с которыми я сталкиваюсь сейчас, - это попытка преобразовать черно-белое .jpg изображение в список, который затем можно смоделировать в звуковой сигнал. Это часть лагерного проекта по созданию программы Python SSTV.

Я импортировал модуль PIL и пытаюсь вызвать встроенную функцию: list(im.getdata()). Когда я звоню, Python падает. Есть ли какой-нибудь способ разбить изображение (всегда 320х240) на 240 строк, чтобы облегчить вычисления? Или я просто вызываю неправильную функцию.

Если у кого-нибудь есть какие-либо предложения, прошу уйти. Если у кого-то есть опыт генерации модулированных звуковых сигналов с использованием Python, я с радостью приму любые «жемчужины мудрости», которые они готовы передать. Заранее спасибо

Ответы [ 8 ]

54 голосов
/ 10 июля 2009

Python не должен падать при вызове getdata (). Образ может быть поврежден или что-то не так с вашей установкой PIL. Попробуйте это с другим изображением или опубликуйте изображение, которое вы используете.

Это должно сломать изображение так, как вы хотите:

from PIL import Image
im = Image.open('um_000000.png')

pixels = list(im.getdata())
width, height = im.size
pixels = [pixels[i * width:(i + 1) * width] for i in xrange(height)]
32 голосов
/ 10 июля 2009

Если у вас установлено numpy , вы можете попробовать:

data = numpy.asarray(im)

(я говорю «попробуй» здесь, потому что неясно, почему getdata() не работает для вас, и я не знаю, использует ли asarray getdata, но это стоит проверить.)

14 голосов
/ 11 июля 2009

Я полагаю, вы получаете сообщение об ошибке типа TypeError: 'PixelAccess' object is not iterable ...?

См. Image.load документацию о том, как получить доступ к пикселям ..

По сути, чтобы получить список пикселей на изображении, используйте PIL:

from PIL import Image
i = Image.open("myfile.png")

pixels = i.load() # this is not a list, nor is it list()'able
width, height = i.size

all_pixels = []
for x in range(width):
    for y in range(height):
        cpixel = pixels[x, y]
        all_pixels.append(cpixel)

Это добавляет каждый пиксель к all_pixels - если файл является изображением RGB (даже если он содержит только черно-белое изображение), это будет кортеж, например:

(255, 255, 255)

Чтобы преобразовать изображение в монохромное, вы просто усредняете три значения - так, последние три строки кода станут ..

cpixel = pixels[x, y]
bw_value = int(round(sum(cpixel) / float(len(cpixel))))
# the above could probably be bw_value = sum(cpixel)/len(cpixel)
all_pixels.append(bw_value)

Или, чтобы получить яркость (средневзвешенное значение):

cpixel = pixels[x, y]
luma = (0.3 * cpixel[0]) + (0.59 * cpixel[1]) + (0.11 * cpixel[2])
all_pixels.append(luma)

Или чистый 1-битный черно-белый вид:

cpixel = pixels[x, y]
if round(sum(cpixel)) / float(len(cpixel)) > 127:
    all_pixels.append(255)
else:
    all_pixels.append(0)

Возможно, в PIL есть методы, позволяющие сделать такие преобразования RGB -> BW быстрее, но это работает и не особенно медленно.

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

from PIL import Image
i = Image.open("myfile.png")

pixels = i.load() # this is not a list
width, height = i.size
row_averages = []
for y in range(height):
    cur_row_ttl = 0
    for x in range(width):
        cur_pixel = pixels[x, y]
        cur_pixel_mono = sum(cur_pixel) / len(cur_pixel)
        cur_row_ttl += cur_pixel_mono

    cur_row_avg = cur_row_ttl / width
    row_averages.append(cur_row_avg)

print "Brighest row:",
print max(row_averages)
3 голосов
/ 16 ноября 2013

Или, если вы хотите считать белые или черные пиксели

Это тоже решение:

from PIL import Image
import operator

img = Image.open("your_file.png").convert('1')
black, white = img.getcolors()

print black[0]
print white[0]
2 голосов
/ 24 июля 2016

Не PIL, но scipy.misc.imread все еще может быть интересно:

import scipy.misc
im = scipy.misc.imread('um_000000.png', flatten=False, mode='RGB')
print(im.shape)

дает

(480, 640, 3)

так оно и есть (высота, ширина, каналы). Таким образом, вы можете перебрать его по

for y in range(im.shape[0]):
    for x in range(im.shape[1]):
        color = tuple(im[y][x])
        r, g, b = color
1 голос
/ 13 июня 2017
data = numpy.asarray(im)

Примечание: в PIL img - RGBA. В cv2 img - BGRA.

Мое надежное решение:

def cv_from_pil_img(pil_img):
    assert pil_img.mode=="RGBA"
    return cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGBA2BGRA)
1 голос
/ 15 марта 2017

Похоже, что PILlow мог изменить tostring() на tobytes(). При попытке извлечь пиксели RGBA, чтобы получить их в текстуру OpenGL, у меня сработало следующее (в рамках вызова glTexImage2D, который я опускаю для краткости).

from PIL import Image
img = Image.open("mandrill.png").rotate(180).transpose(Image.FLIP_LEFT_RIGHT)

# use img.convert("RGBA").tobytes() as texels
1 голос
/ 19 марта 2014

Как я уже говорил выше, проблема, похоже, заключается в преобразовании внутреннего формата списка PIL в стандартный тип списка Python. Я обнаружил, что Image.tostring () намного быстрее, и, в зависимости от ваших потребностей, этого может быть достаточно. В моем случае мне нужно было вычислить дайджест данных изображения CRC32, и он отлично подошел.

Если вам нужно выполнить более сложные вычисления, вам может понадобиться ответ tom10 с участием numpy.

...