使用Python+PIL进行图像强度归一化 - 速度问题

12 投票
3 回答
39862 浏览
提问于 2025-04-17 02:18

我在闲暇时间做一个小项目,涉及到通过显微镜分析一些图像。这些图像是一个晶圆,上面有一些东西,最终我想做一个程序来检测某些材料的出现。

首先的步骤是要让图像的亮度均匀,因为镜头的光线并不均匀。目前我使用一张没有任何东西的图像,只有底材,作为背景图像或参考图像。我会找出这张背景图像中红、绿、蓝三种颜色的最大亮度值。

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)

代码的第一部分是逐个像素地确定背景图像中红、绿、蓝通道的最大亮度值,这个步骤只需要做一次。

第二部分则是处理“真实”的图像(上面有东西的),逐个像素地根据背景来调整红、绿、蓝通道的亮度。这一步需要一些时间,对于一张1280x960的图像,大约需要5到10秒,如果我需要处理多张图像,这速度就太慢了。

我该如何提高速度呢?我想过把所有图像转换成numpy数组,但似乎找不到一个快速的方法来处理RGB图像。我不想离开Python,因为我的C++水平比较低,写出一个能用的FORTRAN代码可能比我节省的时间还要久 :P

3 个回答

1

这部分内容来自于FolksTalk网页

from PIL import Image
import numpy as np

# Read image file
in_file = "my_image.png"
# convert('RGB') for PNG file type
image = Image.open(in_file).convert('RGB')
pixels = np.asarray(image)

# Convert from integers to floats
pixels = pixels.astype('float32')

# Normalize to the range 0-1
pixels /= 255.0
2

请查看这个链接: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)

这段代码没有经过测试,但经过一些小修改应该能正常工作。

18
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')

当然可以!请把你想要翻译的内容发给我,我会帮你把它变得简单易懂。

撰写回答