Преобразование большого изображения PIL в оттенках серого в черное и прозрачное - PullRequest
1 голос
/ 13 июля 2020

Я пытаюсь использовать большой 2d-массив для создания маски изображения с черными и прозрачными частями. Первоначально входным 2d-массивом был PIL.Image, загруженный в режиме оттенков серого ('L'). Таким образом, он содержит значения от 0 до 255. И теперь я хочу заменить все 0 на [0,0,0,255] (черный остается черным), и все значения> 0 должны быть [0,0,0,0] (прозрачными). Я могу сделать это просто так:

import numpy as np

# generate some random test data - normally I just read the input image, which is fast
input_data = np.array([np.array([random.choice([0,10]) for x in range(22000)]) for y in range(9000)])

# create a new img containing black and transparent pixels (r,g,b,alpha) and this takes ages
overlay_img = [[[0, 0, 0, 255] if input_data[y][x] == 0 else [0, 0, 0, 0] for x in range(len(input_data[0]))] for y in range(len(input_data))]
overlay_img = np.array(overlay_img)

Это займет довольно много времени, потому что входные данные очень большие (~ 22000x9000). Мне любопытно, можно ли как-то сделать это быстрее. Я тоже пробовал np.where, но так и не смог заставить его работать. Может быть, есть даже способ напрямую изменить изображение PIL?

fyi: В конце концов, я просто хочу построить это изображение поверх моего графика matplotlib с помощью imshow, чтобы только соответствующие области были видимый (где изображение прозрачное), а остальное скрыто / черное.

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

1 Ответ

1 голос
/ 13 июля 2020

Думаю, вам это нужно, но вы не показали свой код для imshow():

#!/usr/bin/env python3

import random
import numpy as np

# Set up dimensions and random input image
h, w = 9000, 22000
im = np.random.randint(0, 11, (h,w), dtype=np.uint8)

# Create 4-channel mask image
mask = np.zeros((h,w,4), dtype=np.uint8)
mask[...,3] = (im==0) * 255

Последняя строка занимает 800 мсек на моем MacBook Pro.

Если вам нужно немного больше производительности, вы можете использовать numexpr следующим образом, и необходимое время составит 300 мс вместо 800 мс:

import random
import numexpr as ne
import numpy as np

# Set up dimensions and random input image
h, w = 9000, 22000
im = np.random.randint(0, 11, (h,w), dtype=np.uint8)

# Create 4-channel mask image
mask = np.zeros((h,w,4), dtype=np.uint8)

# Same but with "numexpr"
mask[...,3] = ne.evaluate("(im==0)*255")
...