Нормализация интенсивности изображения с использованием Python + PIL - Проблемы со скоростью - PullRequest
7 голосов
/ 14 сентября 2011

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

В любом случае, первый шаг - это нормализация интенсивности по всему изображению, так как линза делаетне дают равномерной молнии.В настоящее время я использую изображение без каких-либо материалов, только подложку в качестве фона или эталонное изображение.Я нахожу максимальное из трех значений (интенсивности) для RGB.

from PIL import Image
from PIL import ImageDraw

rmax = 0;gmax = 0;bmax = 0;rmin = 300;gmin = 300;bmin = 300

im_old = Image.open("test_image.png")
im_back = Image.open("background.png")

maxx = im_old.size[0] #Import the size of the image
maxy = im_old.size[1]
im_new = Image.new("RGB", (maxx,maxy))


pixback = im_back.load()
for x in range(maxx):
    for y in range(maxy):
        if pixback[x,y][0] > rmax:
            rmax = pixback[x,y][0]
        if pixback[x,y][1] > gmax:
            gmax = pixback[x,y][1]
        if pixback[x,y][2] > bmax:
            bmax = pixback[x,y][2]


pixnew = im_new.load()
pixold = im_old.load()
for x in range(maxx):
    for y in range(maxy):
        r = float(pixold[x,y][0]) / ( float(pixback[x,y][0])*rmax )
        g = float(pixold[x,y][1]) / ( float(pixback[x,y][1])*gmax )
        b = float(pixold[x,y][2]) / ( float(pixback[x,y][2])*bmax )
        pixnew[x,y] = (r,g,b)

Первая часть кода определяет максимальную интенсивность фонового изображения КРАСНОГО, ЗЕЛЕНОГО и СИНЕГО, фонового изображения, но нужно сделать только один раз.

Вторая часть берет «реальное» изображение (с элементами на нем) и нормализует КРАСНЫЙ, ЗЕЛЕНЫЙ и СИНИЙ каналы, пиксель за пикселем, согласно фону.Это займет некоторое время, 5-10 секунд для изображения 1280x960, что слишком медленно, если мне нужно сделать это для нескольких изображений.

Что я могу сделать, чтобы улучшить скорость? Я думал о переносе всех изображений в массивные массивы, но я не могу найти быстрый способ сделать это для изображений RGB.Я бы не стал уходить от python, поскольку мой C ++ довольно низкоуровневый, и получение работающего кода на языке FORTRAN, вероятно, заняло бы больше времени, чем я мог бы сэкономить в плане скорости: P

Ответы [ 2 ]

9 голосов
/ 15 сентября 2011
import numpy as np
from PIL import Image

def normalize(arr):
    """
    Linear normalization
    http://en.wikipedia.org/wiki/Normalization_%28image_processing%29
    """
    arr = arr.astype('float')
    # Do not touch the alpha channel
    for i in range(3):
        minval = arr[...,i].min()
        maxval = arr[...,i].max()
        if minval != maxval:
            arr[...,i] -= minval
            arr[...,i] *= (255.0/(maxval-minval))
    return arr

def demo_normalize():
    img = Image.open(FILENAME).convert('RGBA')
    arr = np.array(img)
    new_img = Image.fromarray(normalize(arr).astype('uint8'),'RGBA')
    new_img.save('/tmp/normalized.png')
2 голосов
/ 15 сентября 2011

См. http://docs.scipy.org/doc/scipy/reference/generated/scipy.misc.fromimage.html#scipy.misc.fromimage

Вы можете сказать

databack = scipy.misc.fromimage(pixback)
rmax = numpy.max(databack[:,:,0])
gmax = numpy.max(databack[:,:,1])
bmax = numpy.max(databack[:,:,2])

, что должно быть намного быстрее, чем зацикливание по всем (r, g, b) триплетам вашего изображения.Тогда вы можете сделать

dataold = scip.misc.fromimage(pixold)
r = dataold[:,:,0] / (pixback[:,:,0] * rmax )
g = dataold[:,:,1] / (pixback[:,:,1] * gmax )
b = dataold[:,:,2] / (pixback[:,:,2] * bmax )

datanew = numpy.array((r,g,b))
imnew = scipy.misc.toimage(datanew)

Код не проверен, но должен работать как-то с небольшими изменениями.

...