Получение списка значений пикселей из PIL
Ребята, я ищу немного помощи. Я программист новичков, и одна из проблем, с которыми я столкнулась в данный момент, пытается преобразовать черно-белое изображение .jpg
в список, который затем смогу модулировать в звуковой сигнал. Это часть проекта lager для создания программы SSTV на питоне.
Я импортировал модуль PIL и пытаюсь вызвать встроенную функцию: list(im.getdata())
. Когда я это называю, происходит сбой python. Есть ли способ разбить изображение (всегда 320x240) на 240 строк, чтобы упростить вычисления? Или я просто вызываю неправильную функцию.
Если у кого есть предложения, пожалуйста, уберите их. Если у кого-то есть опыт создания модулированных звуковых тонов с использованием питона, я с радостью принимаю любые "жемчужины мудрости", которые они готовы передать.
Спасибо заранее
Ответы
Ответ 1
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)]
Ответ 2
Если у вас установлен numpy, вы можете попробовать:
data = numpy.asarray(im)
(я говорю "попробуйте" здесь, потому что неясно, почему getdata()
не работает для вас, и я не знаю, использует ли asarray
getdata, но стоит тест.)
Ответ 3
Я предполагаю, что вы получаете ошибку, например.. 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)
Ответ 4
Не 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
Ответ 5
Или если вы хотите считать белые или черные пиксели
Это также решение:
from PIL import Image
import operator
img = Image.open("your_file.png").convert('1')
black, white = img.getcolors()
print black[0]
print white[0]
Ответ 6
Как я уже отмечал выше, проблема заключается в преобразовании из внутреннего формата списка PIL в стандартный тип списка python. Я обнаружил, что Image.tostring() работает намного быстрее, и в зависимости от ваших потребностей этого может быть достаточно. В моем случае мне нужно было вычислить дайджест CRC32 данных изображения, и он подходит отлично.
Если вам нужно выполнить более сложные вычисления, то tom10-ответ, включающий numpy, может быть тем, что вам нужно.
Ответ 7
Похоже, что 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
Ответ 8
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)
Ответ 9
pixVals = list(pilImg.getdata())
выводит список всех значений RGB с картинки:
[(248, 246, 247), (246, 248, 247), (244, 248, 247), (244, 248, 247), (246, 248, 247), (248, 246, 247), (250, 246, 247), (251, 245, 247), (253, 244, 247), (254, 243, 247)]