【发布时间】:2020-10-18 07:40:44
【问题描述】:
我正在尝试提高我的图像处理速度,因为它对于实际使用来说太慢了。
我需要做的是对图像上每个像素的颜色进行复杂的转换。操作基本上是应用矢量变换,如T(r, g, b, a) => (r * x, g * x, b * y, a) 或通俗地说,它是将红色和绿色值乘以一个常数,蓝色的不同乘法并保持 Alpha。但是,如果 RGB 颜色属于某些特定颜色,我还需要对其进行不同的操作,在这些情况下,它们必须遵循字典/转换表,其中 RGB => newRGB 再次保持 alpha。
算法是:
for each pixel in image:
if pixel[r, g, b] in special:
return special[pixel[r, g, b]] + pixel[a]
else:
return T(pixel)
这很简单,但速度一直不够理想。我相信有一些方法可以使用 numpy 向量,但我找不到方法。
关于实施的重要细节:
- 我不关心原始缓冲区/图像(操作到位)
- 我可以使用 wxPython、Pillow 和 NumPy
- 只要缓冲区保持长度,数组的顺序或维度并不重要
缓冲区是从 wxPython Bitmap 获得的,special 和 (RG|B)_pal 是转换表,最终结果也会变成 wxPython Bitmap。它们是这样获得的:
# buffer
bitmap = wx.Bitmap # it's valid wxBitmap here, this is just to let you know it exists
buff = bytearray(bitmap.GetWidth() * bitmap.GetHeight() * 4)
bitmap.CopyToBuffer(buff, wx.BitmapBufferFormat_RGBA)
self.RG_mult= 0.75
self.B_mult = 0.83
self.RG_pal = []
self.B_pal = []
for i in range(0, 256):
self.RG_pal.append(int(i * self.RG_mult))
self.B_pal.append(int(i * self.B_mult))
self.special = {
# RGB: new_RGB
# Implementation specific for the fastest access
# with buffer keys are 24bit numbers, with PIL keys are tuples
}
我尝试的实现包括直接缓冲区操作:
for x in range(0, bitmap.GetWidth() * bitmap.GetHeight()):
index = x * 4
r = buf[index]
g = buf[index + 1]
b = buf[index + 2]
rgb = buf[index:index + 3]
if rgb in self.special:
special = self.special[rgb]
buf[index] = special[0]
buf[index + 1] = special[1]
buf[index + 2] = special[2]
else:
buf[index] = self.RG_pal[r]
buf[index + 1] = self.RG_pal[g]
buf[index + 2] = self.B_pal[b]
将 Pillow 与 getdata() 一起使用:
pil = Image.frombuffer("RGBA", (bitmap.GetWidth(), bitmap.GetHeight()), buf)
pil_buf = []
for colour in pil.getdata():
colour_idx = colour[0:3]
if (colour_idx in self.special):
special = self.special[colour_idx]
pil_buf.append((
special[0],
special[1],
special[2],
colour[3],
))
else:
pil_buf.append((
self.RG_pal[colour[0]],
self.RG_pal[colour[1]],
self.B_pal[colour[2]],
colour[3],
))
pil.putdata(pil_buf)
buf = pil.tobytes()
point() 和 getdata() 的枕头(我达到的最快,比其他人快两倍以上)
pil = Image.frombuffer("RGBA", (bitmap.GetWidth(), bitmap.GetHeight()), buf)
r, g, b, a = pil.split()
r = r.point(lambda r: r * self.RG_mult)
g = g.point(lambda g: g * self.RG_mult)
b = b.point(lambda b: b * self.B_mult)
pil = Image.merge("RGBA", (r, g, b, a))
i = 0
for colour in pil.getdata():
colour_idx = colour[0:3]
if (colour_idx in self.special):
special = self.special[colour_idx]
pil.putpixel(
(i % bitmap.GetWidth(), i // bitmap.GetWidth()),
(
special[0],
special[1],
special[2],
colour[3],
)
)
i += 1
buf = pil.tobytes()
我也尝试过使用numpy.where,但后来我无法让它工作。使用numpy.apply_along_axis 它可以工作,但性能很糟糕。其他使用 numpy 的尝试我无法同时访问 RGB,只能作为单独的波段。
【问题讨论】:
标签: python numpy wxpython python-imaging-library