图像专家:优化我的Python PNG透明函数
我需要把PNG图片中所有白色(或接近白色)的像素替换成透明。
我在AppEngine上使用Python,所以不能使用像PIL、imagemagick这样的库。AppEngine有一个图像库,但主要是用来调整图像大小的。
我找到一个很不错的pyPNG模块,并且写了一个小函数来实现我需要的功能:
主要循环的伪代码大概是这样的:
for each pixel:
if pixel looks "quite white":
set pixel values to transparent
otherwise:
keep existing pixel values
而(假设是8位值)“相当白”的定义是:
where each r,g,b value is greater than "240"
AND each r,g,b value is within "20" of each other
这是我第一次以这种方式处理原始像素数据,虽然能工作,但性能非常差。看起来应该有更高效的方法来处理这些数据,而不是这样逐个像素地遍历?(矩阵?)
我希望有经验的人能指出我算法中一些明显的错误或改进之处。
谢谢!
4 个回答
0
这个问题似乎跟Python中的循环有关,而不是跟图片有关。
Python的循环速度非常慢,所以最好避免使用循环,改用内置的循环操作。
在这里,如果你愿意复制图片的话,可以使用列表推导式:
def make_transparent(pixel):
if pixel looks "quite white": return transparent
else: return pixel
newImage = [make_transparent(p) for p in oldImage]
1
老实说,我能想到的唯一方法就是在你的图片上随便选几个点,然后使用一种叫做洪水填充的技术。
这种方法效果不错,前提是你的图片有大块连续的白色区域(如果你的图片是一个前面没有或只有很小孔洞的物体,那你就很幸运了——你其实有了一个选择填充点的好方法)。
(声明:我不是图像方面的专家 =/ )
1
这个方法还是会检查每一个像素,但可能会更快:
new_pixels = []
for row in pixels:
new_row = array('B', row)
i = 0
while i < len(new_row):
r = new_row[i]
g = new_row[i + 1]
b = new_row[i + 2]
if r>threshold and g>threshold and b>threshold:
m = int((r+g+b)/3)
if nearly_eq(r,m,tolerance) and nearly_eq(g,m,tolerance) and nearly_eq(b,m,tolerance):
new_row[i + 3] = 0
i += 4
new_pixels.append(new_row)
它避免了使用切片生成器,因为切片生成器会为每一个像素复制整行的像素(每次少复制一个像素)。
这个方法还通过直接复制输入行来提前分配输出行,然后只写入那些发生变化的像素的透明度值。
如果能不分配新的像素集合,直接在源图像的像素上写入,那就会更快(前提是你不需要源图像做其他事情)。