Python PIL - функция разделения двух изображений? - PullRequest
7 голосов
/ 09 апреля 2011

РЕДАКТИРОВАТЬ: Код работает сейчас, благодаря Марку и зефиру. Зефир также имеет два альтернативных рабочих раствора ниже.

Я хочу разделить смесь двух изображений с PIL. Я нашел ImageChops.multiply(image1, image2), но не смог найти похожую функцию divide(image, image2).

Объяснение режима разделения наложения (я использовал первые два изображения здесь в качестве моих тестовых источников.)

Есть ли встроенная функция разделения, которую я пропустил (PIL или иначе)?

Мой тестовый код ниже запускается и приближается к тому, что я ищу. Вывод результирующего изображения аналогичен приведенному здесь изображению примера разделения наложения: Объясненный режим разделения наложения .

Есть ли более эффективный способ выполнить эту операцию разделения на доли (меньше шагов и быстрее)? Сначала я попытался использовать лямбда-функции в Image.eval и ImageMath.eval для проверки черных пикселей и перевернуть их на белый во время процесса деления, но я не смог получить ни одного, чтобы получить правильный результат.

EDIT: исправлен код и сокращен благодаря Марку и зефиру. Вывод полученного изображения совпадает с выводом приведенных ниже решений зефира и змеи.

# PIL Divide Blend test

import Image, os, ImageMath

imgA = Image.open('01background.jpg')
imgA.load()
imgB = Image.open('02testgray.jpg')
imgB.load()

# split RGB images into 3 channels
rA, gA, bA = imgA.split()
rB, gB, bB = imgB.split()

# divide each channel (image1/image2)
rTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=rA, b=rB).convert('L')
gTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=gA, b=gB).convert('L')
bTmp = ImageMath.eval("int(a/((float(b)+1)/256))", a=bA, b=bB).convert('L')

# merge channels into RGB image
imgOut = Image.merge("RGB", (rTmp, gTmp, bTmp))

imgOut.save('PILdiv0.png', 'PNG')

os.system('start PILdiv0.png')

Ответы [ 3 ]

3 голосов
/ 09 апреля 2011

Здесь есть математическое определение для функции деления: http://www.linuxtopia.org/online_books/graphics_tools/gimp_advanced_guide/gimp_guide_node55_002.html

Вот реализация с scipy / matplotlib:

import numpy as np
import scipy.misc as mpl

a = mpl.imread('01background.jpg')
b = mpl.imread('02testgray.jpg')

c = a/((b.astype('float')+1)/256)
d = c*(c < 255)+255*np.ones(np.shape(c))*(c > 255)

e = d.astype('uint8')

mpl.imshow(e)
mpl.imsave('output.png', e)

Если вы не хотите использовать matplotlib,Вы можете сделать это так (я полагаю, у вас есть NumPy):

imgA = Image.open('01background.jpg')
imgA.load()
imgB = Image.open('02testgray.jpg')
imgB.load()

a = asarray(imgA)
b = asarray(imgB)
c = a/((b.astype('float')+1)/256)
d = c*(c &lt 255)+255*ones(shape(c))*(c &gt 255)
e = d.astype('uint8')

imgOut = Image.fromarray(e)
imgOut.save('PILdiv0.png', 'PNG')

1 голос
/ 10 ноября 2016

Вы спрашиваете:

Есть ли более эффективный способ выполнить эту операцию разделения на доли (меньше шагов и быстрее)?

Вы также можете использовать пакет python blend mode . Это написано с векторизованной математикой Numpy и вообще быстро. Установите его через pip install blend_modes. Я написал команды в более подробном виде, чтобы улучшить читаемость, было бы короче их цепочку. Используйте blend_modes, как это, чтобы разделить ваши изображения:

from PIL import Image
import numpy
import os
from blend_modes import blend_modes

# Load images
imgA = Image.open('01background.jpg')
imgA = numpy.array(imgA)
# append alpha channel
imgA = numpy.dstack((imgA, numpy.ones((imgA.shape[0], imgA.shape[1], 1))*255))
imgA = imgA.astype(float)

imgB = Image.open('02testgray.jpg')
imgB = numpy.array(imgB)
# append alpha channel
imgB = numpy.dstack((imgB, numpy.ones((imgB.shape[0], imgB.shape[1], 1))*255))
imgB = imgB.astype(float)

# Divide images
imgOut = blend_modes.divide(imgA, imgB, 1.0)

# Save images
imgOut = numpy.uint8(imgOut)
imgOut = Image.fromarray(imgOut)
imgOut.save('PILdiv0.png', 'PNG')

os.system('start PILdiv0.png')

Имейте в виду, что для того, чтобы это работало, оба изображения должны иметь одинаковые размеры, например imgA.shape == (240,320,3) и imgB.shape == (240,320,3).

1 голос
/ 09 апреля 2011

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

...