【问题标题】:Intensity normalization of image using Python+PIL - Speed issues使用 Python+PIL 对图像进行强度归一化 - 速度问题
【发布时间】:2011-11-17 08:14:08
【问题描述】:

我在业余时间处理一个小问题,包括分析通过显微镜获得的一些图像。它是一个到处都有一些东西的晶圆,最终我想制作一个程序来检测某些材料何时出现。

无论如何,第一步是标准化整个图像的强度,因为镜头不会产生均匀的闪电。目前我使用一张没有任何东西的图像,只有基板作为背景或参考图像。我找到了 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)

代码的第一部分逐像素确定背景图像的红色、绿色和蓝色通道的最大强度,但只需执行一次。

第二部分采用“真实”图像(上面有东西),并根据背景逐像素标准化红色、绿色和蓝色通道。这需要一些时间,一张 1280x960 的图像需要 5-10 秒,如果我需要对多张图像执行此操作,这太慢了。

我能做些什么来提高速度?我想过将所有图像移动到 numpy 数组中,但我似乎无法为 RGB 图像找到快速的方法。 我宁愿不要离开 python,因为我的 C++ 是相当低级的,并且获得一个工作的 FORTRAN 代码可能需要比我在速度方面节省的时间更长:P

【问题讨论】:

  • 这可能比这里更属于codereview.stackexchange.com
  • @S.Lott,我认为这是一个灰色地带。问题毕竟是关于特定技术的。
  • @Mark Ransom:“特定技术”是如何让它变灰的?是代码。待审核。
  • @S.Lott,也许你是对的,毕竟它不是灰色的。我刚刚重新阅读了常见问题解答,我看不出这个问题有任何问题。
  • @Bjarke:你考虑过 OpenCV 吗?它是一个带有 Python 绑定的强大图像处理库。它的读写速度很快,并且具有例如自适应阈值算法。

标签: python normalization python-imaging-library


【解决方案1】:
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')

【讨论】:

  • 当我在灰度图像上执行此操作时(将转换并保存为“L”),与仅转换为灰度图像相比,我无法分辨出任何区别(除了文件大小大约大 3 倍)。颜色也更大,但我可以直观地分辨出差异。文件大小增加从何而来?我是否应该能够注意到灰度标准化的差异,如果是这样,如果有的话,我还需要在这里更改什么?我注意到 wiki 给出了灰度相同公式的示例。
  • 如果您有灰度图像,那么arr 的形状将是(H, W) 而不是(H, W, 4)。因此,您不需要标准化每个通道 arr[..., i]。相反,你会规范化 arr 本身。所以删除for-loop并将arr[..., i]更改为arr
【解决方案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)

该代码未经测试,但只要稍作修改即可工作。

【讨论】:

  • 虽然与我的 (w)hack 相比,这确实相当(!)快,但 scipy 函数似乎有些问题。例如。使用像farm1.static.flickr.com/58/165782919_38f15d585a.jpg 这样的图像,下面的代码应该显示图像的红色通道,但情况似乎并非如此:scipy.misc.toimage(databack[:,:,0]).show()
  • Unutbu 提供了另一种解决方案,它不使用 scipy 来双向转换图像和 numpy 数据。也许你应该尝试类似 arr=np.array(np.asarray(img).astype('float')) new_img = Image.fromarray(normalize(arr).astype('uint8'),'RGBA')跨度>
猜你喜欢
  • 2011-05-07
  • 2022-11-05
  • 2011-10-30
  • 2013-04-15
  • 2013-12-17
  • 2012-02-24
  • 2011-10-11
  • 1970-01-01
  • 2017-08-29
相关资源
最近更新 更多