Python实现图像平均合成时为何无法向3D列表正确写入元素
问题核心原因
你的代码故障是Python列表浅拷贝导致的:你初始化comp_img时所有像素都引用同一个列表对象,修改任意一个像素的通道值,整张图所有像素的对应通道都会同步修改,最终整张图变成统一的平均色,原本的64字样自然被完全抹除。
具体出问题的初始化逻辑:
- 你定义
temp = [0,0,0,0]后,循环向comp_img追加的都是同一个temp的引用,整行的所有像素指向同一个列表 - 后续把整行模板赋值给
temp,再循环追加给新的comp_img,最终整张图的所有像素都共享最开始的那一个[0,0,0,0]列表 - 三重循环赋值时,每次操作本质上都是覆盖所有像素的对应通道值,最终所有像素的数值都等于最后一个像素的计算结果,就得到了你看到的纯色图。
修复方案
方案1:修改初始化逻辑,规避浅拷贝
初始化时每次生成新的独立列表,不要复用同一个temp对象,修改后的完整代码如下:
from PIL import Image import numpy as np from math import ceil red = Image.open("64red.png") grn = Image.open("64green.png") width, height = red.size # 初始化时每次生成新的列表,避免浅拷贝 comp_img = [] for row in range(height): row_data = [] for pxl in range(width): row_data.append([0,0,0,0]) comp_img.append(row_data) reddata = np.asarray(red).tolist() grndata = np.asarray(grn).tolist() for row, elm in enumerate(reddata): for pxl, subelm in enumerate(elm): for vlu_index, vlu in enumerate(subelm): comp_img[row][pxl][vlu_index] = ceil((reddata[row][pxl][vlu_index] + grndata[row][pxl][vlu_index])/2) output = np.array(comp_img, dtype=np.uint8) outputImg = Image.fromarray(output) outputImg.save("output.png")
方案2:直接使用numpy向量运算,性能大幅提升
你完全不需要将numpy数组转成Python列表写三重循环,numpy原生支持逐元素运算,代码更简洁,运行速度是三重循环的百倍以上:
from PIL import Image import numpy as np red = Image.open("64red.png") grn = Image.open("64green.png") red_arr = np.asarray(red) grn_arr = np.asarray(grn) # 等价于ceil((a + b)/2)的向量化实现,无需循环 comp_arr = ((red_arr + grn_arr + 1) // 2).astype(np.uint8) outputImg = Image.fromarray(comp_arr) outputImg.save("output.png")
你调试用的两张原图和错误输出如下图:


内容的提问来源于stack exchange,提问作者Zonk
相关产品推荐
相关产品推荐

