手机拍的合照放大后糊成一团,老照片泛黄模糊不忍直视,供应商发来的商品图右下角印着大水印——这些场景我都遇到过。以前全靠 PS 手动修,一张图修半小时;现在用 Python + 开源工具,超分辨率放大、AI 去水印、风格迁移三件事都能自动化,再配一个批量处理脚本,100 张图一键搞定。全部工具零成本,代码复制就能跑。
三个核心技术,先弄懂原理
超分辨率(Super Resolution)
简单说就是:AI 猜出图片"应该"长什么样,然后帮你补上细节。
Real-ESRGAN 是目前最好用的开源超分模型之一。它用了一种叫"对抗训练"的策略——一个生成器负责放大图片,一个判别器负责判断"这图是不是真的",两个网络互相对抗,最后生成器练出来的放大效果就非常逼真。
支持 2x、4x 放大,不只是拉伸像素,而是真正"脑补"出纹理细节。
Inpainting(图像修复)
传统去水印的做法是"周围像素糊过来",效果生硬。AI inpainting 的思路不一样——它理解整张图的语义,知道这里是"背景"、那里是"衣服纹理",修复的时候不是简单糊弄,而是根据上下文生成合理的内容。
今天用两个方案:
- OpenCV 的
inpaint:轻量快速,适合简单去瑕疵 - LaMa(Large Mask Inpainting):效果更好,适合复杂场景去水印
风格迁移(Style Transfer)
把一张照片变成梵高星空风格、水彩画风、素描风……原理不复杂:用卷积神经网络分别提取"内容图"的内容特征和"风格图"的纹理特征,然后把两者融合。
先用 PIL 的滤镜做轻量级的素描/油画效果(零依赖、秒出结果),再介绍怎么用预训练模型做更炫的风格迁移。
环境准备
pipinstallopencv-python-headless numpy Pillow realesrgan basicsr tqdmReal-ESRGAN 依赖 PyTorch,如果没装过,先
pip install torch torchvision(有 GPU 的话装 CUDA 版本,没有就装 CPU 版本)。
超分辨率:模糊图变清晰
importcv2importosfromrealesrgan.archs.srvgg_archimportSRVGGNetCompactfromrealesrganimportRealESRGANerfrombasicsr.utils.download_utilimportload_file_from_urldefupscale_image(input_path,output_path,scale=2):"""Real-ESRGAN 超分辨率放大(scale: 2 或 4)"""# 模型首次自动下载,之后走本地缓存model_url=("https://github.com/xinntao/Real-ESRGAN/releases/download/"f"v0.2.5.0/realesr-general-x4v3.pth")model_path=load_file_from_url(url=model_url,model_dir="models",progress=True)model=SRVGGNetCompact(num_in_ch=3,num_out_ch=3,num_feat=64,num_conv=32,upscale=4,act_type="prelu")# 有 GPU 用 GPU,没有就用 CPUdevice="cuda"ifcv2.cuda.getCudaEnabledDeviceCount()>0else"cpu"upsampler=RealESRGANer(scale=4,model_path=model_path,model=model,tile=0,tile_pad=10,pre_pad=0,half=(device=="cuda"),device=device)img=cv2.imread(input_path,cv2.IMREAD_UNCHANGED)output,_=upsampler.enhance(img,outscale=scale)os.makedirs(os.path.dirname(output_path)or".",exist_ok=True)cv2.imwrite(output_path,output)关键参数说明:
| 参数 | 含义 | 调参建议 |
|---|---|---|
scale | 放大倍数 | 2x 够用且快,4x 细节更丰富但慢 |
tile | 分块大小 | 内存 < 8GB 设 256,> 8GB 设 0(不分块) |
half | 半精度推理 | GPU 必开,速度快一倍,效果几乎无差 |
模型首次运行会从 Real-ESRGAN 官方仓库 的 releases 页面 自动下载,之后走本地缓存。
运行效果(本机实测):拿一张 900×600 的图先缩小 4 倍再放大回原尺寸,模拟出"糊成一团"的废片,再用 Real-ESRGAN 4x 超分——模糊的 900×600 直接变成清晰的 3600×2400:
!在这里插入图片描述
!在这里插入图片描述
两张图对比着看,超分后文字边缘、纹理细节明显变实了,这就是对抗训练练出来的放大效果。CPU 跑这一张大约十几秒,有 GPU 会快一个量级。
📐 原图尺寸: 900x600 ✅ 超分完成: super.jpg(4x 放大 -> 3600x2400)去水印 / 去瑕疵
方案 A:OpenCV inpaint(轻量级,秒出结果)
importcv2importnumpyasnpdefremove_watermark_opencv(input_path,mask_path,output_path,method="telea"):""" 用 OpenCV 的 inpaint 去除水印/瑕疵 :param input_path: 原图路径 :param mask_path: 水印区域的 mask 图片路径(白色=要去除的区域) :param output_path: 输出路径 :param method: 'telea' 或 'ns'(两种修复算法) """img=cv2.imread(input_path)mask=cv2.imread(mask_path,cv2.IMREAD_GRAYSCALE)ifimgisNoneormaskisNone:raiseFileNotFoundError("图片或 mask 文件不存在")# 二值化 mask:确保是黑白分明_,mask=cv2.threshold(mask,127,255,cv2.THRESH_BINARY)# 选择修复算法ifmethod=="telea":result=cv2.inpaint(img,mask,inpaintRadius=5,flags=cv2.INPAINT_TELEA)else:result=cv2.inpaint(img,mask,inpaintRadius=5,flags=cv2.INPAINT_NS)cv2.imwrite(output_path,result)print(f"✅ OpenCV inpaint 完成:{output_path}")mask 怎么搞?用画图工具把水印区域涂白,其他地方涂黑,保存为 PNG 就行。下面给一个自动生成 mask 的偷懒方案。
方案 B:没有 mask?用颜色阈值自动生成
defauto_mask_by_color(input_path,output_path,lower_color=(200,200,200),upper_color=(255,255,255)):""" 自动检测白色/浅色水印区域并生成 mask,然后修复 适合半透明白色水印场景 """img=cv2.imread(input_path)# 转换到 HSV 色彩空间,更容易区分水印hsv=cv2.cvtColor(img,cv2.COLOR_BGR2HSV)# 根据颜色范围生成 masklower=np.array([0,0,lower_color[0]],dtype=np.uint8)upper=np.array([180,40,upper_color[0]],dtype=np.uint8)mask=cv2.inRange(hsv,lower,upper)# 形态学操作:膨胀 mask,让修复范围稍微大一点kernel=np.ones((5,5),np.uint8)mask=cv2.dilate(mask,kernel,iterations=2)# inpaint 修复result=cv2.inpaint(img,mask,inpaintRadius=7,flags=cv2.INPAINT_TELEA)cv2.imwrite(output_path,result)print(f"✅ 自动去水印完成:{output_path}")# 使用示例# auto_mask_by_color("photo_with_watermark.jpg", "photo_clean.jpg")用自动阈值方案处理的效果(左为带白色水印的原图,右为修复后):
!在这里插入图片描述
!在这里插入图片描述
OpenCV 的 Inpaint 文档在 OpenCV 官方文档(Inpainting) ,想用效果更强的 LaMa 模型可以参考 GitHub 仓库 advimman/lama 。
风格迁移:照片变油画 / 素描 / 水彩
先来个零门槛版本——用 PIL 滤镜,不需要任何模型下载:
fromPILimportImage,ImageFilter,ImageOps,ImageEnhancedefapply_artistic_style(input_path,output_path,style="sketch"):"""PIL 滤镜实现艺术风格:sketch 素描 / oil 油画 / edge 线稿(watercolor、emboss 同套路)"""img=Image.open(input_path)ifstyle=="sketch":# 素描:灰度 + 反色 + 高斯模糊 + 颜色减淡混合gray=ImageOps.grayscale(img)blurred=ImageOps.invert(gray).filter(ImageFilter.GaussianBlur(radius=12))result=ImageOps.grayscale(Image.composite(gray,blurred,blurred))elifstyle=="oil":# 油画:平滑 + 锐化 + 增强饱和度result=ImageEnhance.Color(img.filter(ImageFilter.SMOOTH_MORE).filter(ImageFilter.SHARPEN)).enhance(1.5)elifstyle=="edge":# 线稿:白底黑线result=ImageOps.invert(ImageOps.grayscale(img.filter(ImageFilter.FIND_EDGES)))else:raiseValueError(f"不支持的风格:{style}")result.save(output_path)PIL / Pillow 文档:Pillow 官方文档
用同一张测试图跑这五种风格的效果:
!在这里插入图片描述
!在这里插入图片描述
!在这里插入图片描述
!在这里插入图片描述
!在这里插入图片描述
批量处理:一次 100 张,带进度条
前面都是单张处理,实际工作中谁一张张搞?下面这个脚本一次处理 100 张图,带进度条:
importosimportglobfromtqdmimporttqdmfromPILimportImagedefbatch_process_images(input_dir,output_dir,style="oil"):"""批量处理目录下所有图片风格(完整代码见配套 day02.py)"""os.makedirs(output_dir,exist_ok=True)patterns=["*.jpg","*.jpeg","*.png","*.bmp","*.webp"]image_files=[fforpinpatternsforfinglob.glob(os.path.join(input_dir,p))]forimg_pathintqdm(image_files,desc=f"处理中({style})",ncols=80):name,ext=os.path.splitext(os.path.basename(img_path))apply_artistic_style(img_path,os.path.join(output_dir,f"{name}_{style}{ext}"),style=style)defbatch_upscale(input_dir,output_dir,scale=2):"""批量超分辨率放大"""os.makedirs(output_dir,exist_ok=True)patterns=["*.jpg","*.jpeg","*.png","*.bmp"]image_files=[fforpinpatternsforfinglob.glob(os.path.join(input_dir,p))]forimg_pathintqdm(image_files,desc=f"超分({scale}x)",ncols=80):name,ext=os.path.splitext(os.path.basename(img_path))upscale_image(img_path,os.path.join(output_dir,f"{name}_{scale}x{ext}"),scale=scale)# 示例:batch_process_images("./raw_photos", "./output_oil", style="oil")# 示例:batch_upscale("./blurry_photos", "./clear_photos", scale=2)配套脚本day02_image_enhance.py里还多提供了batch_auto_watermark()(批量去水印)和old_photo_restore()(老照片修复流水线)两个函数,tqdm 进度条来自 GitHub 仓库 tqdm/tqdm 。
演示运行日志(含风格迁移、自动去水印与批量处理输出):
!在这里插入图片描述
GPU 加速提示:
| 场景 | CPU 耗时(单张) | GPU 耗时(单张) | 建议 |
|---|---|---|---|
| Real-ESRGAN 4x | 30-60 秒 | 3-8 秒 | 必须用 GPU |
| OpenCV inpaint | 0.1-0.5 秒 | 0.05 秒 | CPU 就够 |
| PIL 风格滤镜 | 0.2-1 秒 | — | CPU 就够 |
费用
本篇用到的工具全部开源免费:Real-ESRGAN(Apache 2.0)、OpenCV(Apache 2.0)、PIL/Pillow(HPND 许可)、LaMa(Apache 2.0)、tqdm(MIT),总成本 ¥0。
唯一可能的成本:如果用 GPU 云服务器跑超分,按量计费大概几毛钱处理 1000 张;本地有显卡的话,完全免费。
自己动手改
三个由易到难的改造方向:
入门题:给批量处理脚本加一个"输入分辨率限制"功能——如果原图已经大于 1920x1080,就跳过超分,避免浪费算力。
进阶题:写一个"老照片修复流水线"——先超分放大 → 再自动去黄(调整白平衡)→ 最后锐化,三步串起来处理一张图。配套脚本的
old_photo_restore()就是这个思路的参考答案。挑战题:实现一个"智能去水印"——先用颜色检测找到水印区域,再用形态学操作优化 mask 边缘,最后用 inpaint 修复。对比不同
inpaintRadius值的效果差异。
注:因家人住院,在手机上存稿没把图片保存下来,回家后会把图片重新上传修改后再发表一次的