在 Python 中通过循环修改字节串的最快方法?

Fastest method to modify bytestring over loop in Python?

我将图像存储为字节串 b'' 并且正在执行逐像素操作。现在我发现最快的方法是使用 struct crate 在修改期间打包和解包字节,然后将像素保存到 bytearray

# retrieve image data. Stored as bytestring
pixels = buff.get(rect, 1.0, "CIE LCH(ab) alpha double",
                  Gegl.AbyssPolicy.CLAMP)
# iterator split into 32-byte chunks for each pixel's 8-byte LCHA channels
pixels_iter = (pixels[x:x + 32] for x in range(0, len(pixels), 32))
new_pixels = bytearray()

# when using `pool.map`, the loop was placed in its own function.
for pixel in pixels_iter:
    l, c, h, a = struct.unpack('dddd', pixel)
    # simple operation for now: lower chroma if bright and saturated
    c = c - (l * c) / 100
    new_pixels += struct.pack('dddd', l, c, h, a)

# save new data. everything hereout handled by GEGL instead of myself.
shadow.set(rect, "CIE LCH(ab) alpha double", bytes(new_pixels))

问题是我工作站上的 7MP 图像大约需要 3 1/2 秒。如果经常请求更新,则公平但不理想。从我收集到的信息来看,常量数组修改和可能的 struct [un]packing 似乎是罪魁祸首。我已经重构了十几次了,我想我没有优化它的想法。

我试过:

像 Pypy 这样完全独立的解释器不在 table,因为我不是捆绑 Python 版本的人。

如果使用得当,NumPy 产生的结果应该比手动循环快得多。正确使用它意味着在整个数组上使用 NumPy 操作,而不仅仅是在 NumPy 数组上手动循环。

例如,

new_pixels = bytearray(pixels)

as_numpy = numpy.frombuffer(new_pixels, dtype=float)
as_numpy[1::4] *= 1 - as_numpy[::4] / 100

现在 new_pixels 包含调整后的值。