Расширение c функциональности PIL - PullRequest
2 голосов
/ 02 марта 2011

Я хочу создать функциональность, аналогичную Image.blend в PIL, используя другой алгоритм наложения. Для этого мне нужно: (1) напрямую изменить модули PIL и скомпилировать свой собственный PIL или (2) написать модуль Python C, который импортирует и расширяет PIL?

Я неудачно попробовал:

#include "_imaging.c"

Я также пытался просто извлечь нужные мне детали из источника PIL и поместить их в свой собственный файл. Чем дальше я попадал, тем больше вещей мне приходилось тянуть, и, похоже, это не идеальное решение.

ОБНОВЛЕНИЕ: отредактировано для добавления алгоритма наложения, реализованного в python (это эмулирует режим наложения наложения в Photoshop):

def overlay(upx, lpx):
    return (2 * upx * lpx / 255 ) if lpx < 128 else ((255-2 * (255 - upx) * (255 - lpx) / 255))

def blend_images(upper = None, lower = None):
    upixels = upper.load()
    lpixels = lower.load()
    width, height = upper.size
    pixeldata = [0] * len(upixels[0, 0])
    for x in range(width):
        for y in range(height):
            # the next for loop is to deal with images of any number of bands
            for i in range(len(upixels[x,y])):
                pixeldata[i] =  overlay(upixels[x, y][i], lpixels[x, y][i])
            upixels[x,y] = tuple(pixeldata)
    return upper

Я также безуспешно пытался реализовать это, используя scipy's weave.inline:

def blend_images(upper=None, lower=None):
    upixels = numpy.array(upper)
    lpixels = numpy.array(lower)
    width, height = upper.size
    nbands = len(upixels[0,0])
    code = """
        #line 120 "laplace.py" (This is only useful for debugging)
        int upx, lpx;
        for (int i = 0; i < width-1; ++i) {
            for (int j=0; j<height-1; ++j) {
                for (int k = 0; k < nbands-1; ++k){
                    upx = upixels[i,j][k];
                    lpx = lpixels[i,j][k];
                    upixels[i,j][k] = ((lpx < 128) ? (2 * upx * lpx / 255):(255 - 2 * (255 - upx) * (255 - lpx) / 255));
                }
            }
        }
        return_val = upixels;
        """
        # compiler keyword only needed on windows with MSVC installed
    upixels = weave.inline(code,
                           ['upixels', 'lpixels', 'width', 'height', 'nbands'],
                           type_converters=converters.blitz,
                           compiler = 'gcc')
    return Image.fromarray(upixels)

Я что-то не так делаю с массивами upixel и lpixel, но я не уверен, как их исправить. Я немного озадачен типом upixels[i,j][k], и не уверен, что могу назначить его.

1 Ответ

3 голосов
/ 02 марта 2011

Вот моя реализация в NumPy .У меня нет юнит-тестов, поэтому я не знаю, содержит ли он ошибки.Я предполагаю, что услышу от вас, если это не удастся.Объяснение того, что происходит, в комментариях.Он обрабатывает изображение RGBA 200x400 за 0,07 секунды

import Image, numpy

def blend_images(upper=None, lower=None):
    # convert to arrays
    upx = numpy.asarray(upper).astype('uint16')
    lpx = numpy.asarray(lower).astype('uint16')
    # do some error-checking
    assert upper.mode==lower.mode
    assert upx.shape==lpx.shape
    # calculate the results of the two conditions
    cond1 = 2 * upx * lpx / 255
    cond2 = 255 - 2 * (255 - upx) * (255 - lpx) / 255
    # make a new array that is defined by condition 2
    arr = cond2
    # this is a boolean array that defines where in the array lpx<128
    mask = lpx<128
    # populate the parts of the new arry that meet the critera for condition 1
    arr[mask] = cond1[mask]
    # prevent overflow (may not be necessary)
    arr.clip(0, 255, arr)
    # convert back to image
    return Image.fromarray(arr.astype('uint8'), upper.mode)
...