PIL转换numpy数组格式RGB图像为PNG时输出结果异常
问题根源
你遇到的灰度、内容重复问题由两个核心错误导致:
- 数组维度顺序处理错误:
rasterio的read()方法返回的数组默认维度排列为(波段数, 图像高度, 图像宽度),对你的文件来说读取后的shape是(3, 10800, 21600)。直接调用reshape(10800, 21600, 3)只会强行修改数组的形状属性,不会调整像素在内存中的排列顺序,最终会把不同波段、不同位置的像素打乱拼接,直接造成内容重复、色彩错位显示为灰度。 - 未做像素值范围适配:很多TIFF文件(尤其是遥感类GeoTIFF)的像素存储位深不是8位,可能是16位、32位,数值范围也不是PNG要求的0-255区间,直接强转
np.uint8会出现数值截断、色彩异常。
修正代码
import rasterio import numpy as np from PIL import Image with rasterio.open("world.tif") as dataset: window = rasterio.windows.Window(0, 0, 21600, 10800) # 读取窗口内数据,输出维度为(波段, 高度, 宽度) raster_data = dataset.read(window=window) # 调整维度顺序为PIL要求的(高度, 宽度, 波段) rgb_data = np.transpose(raster_data, (1, 2, 0)) # 适配非8位源数据,将像素值线性拉伸到0-255区间 if rgb_data.dtype != np.uint8: val_min, val_max = rgb_data.min(), rgb_data.max() rgb_data = ((rgb_data - val_min) / (val_max - val_min) * 255).astype(np.uint8) # 导出PNG output_img = Image.fromarray(rgb_data, "RGB") output_img.save("out.png")
补充说明
- 如果你的TIFF包含4个波段(带Alpha透明通道),可以在转置前先截取前3个RGB波段:
raster_data = raster_data[:3, :, :],避免通道数不匹配报错。 - 21600×10800属于超大幅面图像,如果保存时出现内存不足,可以在
save方法中添加参数compress_level=6启用压缩降低内存占用,也可以根据需求分块导出。 - 不要用
reshape直接调整带通道维度的数组形状,这类维度顺序调换操作必须用np.transpose或者np.swapaxes完成。
内容的提问来源于stack exchange,提问作者Sean Mabli
相关产品推荐
相关产品推荐

