Нормализация интенсивности изображения с использованием Python+Pil-Speed
Я работаю над небольшой проблемой в свободное время, связанной с анализом некоторых изображений, полученных через микроскоп. Это облатка с некоторыми вещами здесь и там, и в конечном счете я хочу сделать программу для обнаружения, когда появляются определенные материалы.
в любом случае, первый шаг-нормализовать интенсивность по всему изображению, так как объектив не дает равномерной молнии. В настоящее время я использую изображение, без материала, только подложку, в качестве фона или эталонного изображения. Я считаю максимум трех значений (интенсивности) для 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, что слишком медленно, если я нужно сделать это с несколькими изображениями.
что я могу сделать, чтобы улучшить скорость? Я думал о перемещении всех изображений в массивы numpy, но я не могу найти быстрый способ сделать это для изображений RGB. Я бы предпочел не отходить от python, так как мой C++ довольно низкоуровневый, и получение рабочего кода FORTRAN, вероятно, займет больше времени, чем я мог бы сэкономить с точки зрения скорости :P
2 ответов
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')
см 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)
код не тестируется, но должен работать как-то с незначительными изменениями.