You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python PIL实现图片像素矩形区域交换 嵌套循环卡顿问题

故障根因
  • 程序卡顿冻结本质是性能问题:getpixel、putpixel属于Python层逐像素调用接口,单次调用开销很高。两个高100像素、与图片等宽的区域总像素量为2 * 图片宽度 * 100,只要图片宽度超过2000像素,Python嵌套循环就要执行40万次以上的读写操作,直接阻塞主线程,表现就是程序无响应、冻结。
  • 交换逻辑失效是读写顺序错误:如果直接在原图上嵌套循环边读边写,第一个区域的原始像素还没完成暂存就被新值覆盖,最终两个区域内容会完全错乱,无法实现交换效果。
  • 之前两个独立函数可以正常运行,是因为函数仅给对应区域写入固定颜色值,不需要暂存原始像素,且单次循环的开销还没达到卡死阈值;合并为交换逻辑后,循环计算量翻倍,同时需要处理临时像素存储,性能问题和逻辑问题同时触发就会出问题。
最优实现方案

不要手写Python嵌套循环操作像素,直接调用PIL内置的区域裁剪、粘贴接口即可,这类接口底层由C实现,性能比手写Python循环高2个数量级,完全不会卡顿,逻辑也更简单不易出错。
交换逻辑仅需三步:

  1. 定义两个待交换区域的坐标范围
  2. 把两个区域从原图上裁剪下来作为独立备份(该操作不会修改原图)
  3. 把两个备份区域交叉粘贴到对方的原位置即可

可直接运行的代码如下:

from PIL import Image

im = Image.open("Jenny-RedEyes.jpg")
width, height = im.size

# 配置两个待交换区域的参数:全宽、高度100像素
y1 = 0    # 第一个区域的起始Y坐标
y2 = 166  # 第二个区域的起始Y坐标
region_height = 100

# 裁剪两个区域做临时备份
box1 = (0, y1, width, y1 + region_height)
box2 = (0, y2, width, y2 + region_height)
region1 = im.crop(box1)
region2 = im.crop(box2)

# 交叉粘贴完成交换
im.paste(region2, box1)
im.paste(region1, box2)

im.show()
手动像素操作实现(不推荐)

如果出于原理验证目的非要手写循环实现,必须先把两个区域的所有像素全部读取缓存到内存,再统一写回,绝对不能边读边写;同时用load()方法获取像素访问指针,减少逐点调用接口的开销。该写法性能远差于内置接口,高分辨率图片下依然会有明显卡顿,仅做参考:

from PIL import Image

im = Image.open("Jenny-RedEyes.jpg")
width, height = im.size
pix = im.load()
y1, y2 = 0, 166
region_height = 100

# 第一步:缓存两个区域的全部像素值
buf1 = []
buf2 = []
for x in range(width):
    col1, col2 = [], []
    for offset in range(region_height):
        col1.append(pix[x, y1 + offset])
        col2.append(pix[x, y2 + offset])
    buf1.append(col1)
    buf2.append(col2)

# 第二步:统一写入交换后的像素值
for x in range(width):
    for offset in range(region_height):
        pix[x, y1 + offset] = buf2[x][offset]
        pix[x, y2 + offset] = buf1[x][offset]

im.show()

内容的提问来源于stack exchange,提问作者Oswald

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 16:33:41