
简介基于GAN的复杂背景文字图像修复Python源码项目面向计算机视觉学习者与深度学习实践者清晰演示从数据准备、模型训练到测试验证的完整流程。压缩包共12429个文件整体约176.4MB其中包含12375个jpg训练样本、34个ttf字体、7个py脚本含trainwork.py与testwork.py、4个xml配置及2个pth预训练权重各部分分别服务于图像数据、字体渲染、训练测试与模型保存。已有445人学习下载适合作为入门参考或二次开发基础。通过trainwork.py可了解生成器与判别器的网络设计、损失计算和对抗训练细节testwork.py支持加载权重直接修复新图像大量jpg与字体文件还能帮助理解中文文字图像数据集的构造方式。压缩包以computer-vision-main目录组织覆盖模型定义、训练日志、数据预处理脚本与结果展示等模块便于按需检索和复用。1. 复杂背景文字图像修复为什么GAN是绕不开的解法一张票据扫描件上金额位数被印章压住了一本旧书的书脊上标题笔画被污渍吃掉了一半一张产品照片里包装上的生产批号拍糊了——这些场景都有个共同点背景不是单纯的白底而是纹理、阴影、反光交织的复杂背景而文字恰恰又是图像里信息密度最高、对结构最敏感的区域。这类需求在业内常被归为GAN图像修复Generative Adversarial Network based Text Image Restoration核心是用GAN网络对破损文字区域做语义级重建而不是简单模糊去噪。复杂背景里重建文字难在两点既要补出让人能认、让OCR系统能读的笔画又要让补出来的区域和周围背景在纹理、明暗、边缘上融为一体。本文我按自己的落地经验讲清楚任务怎么定义、数据怎么造、模型怎么选、损失怎么配、训练有哪些坑、以及最后怎么把修复效果量化出来。适合正在做文档去污、票据增强、古籍数字化、OCR前处理的算法工程师——不是泛讲GAN原理而是照着标题把这个任务真正跑通。2. 把“文字残缺”定义成可训练的任务数据集与预处理2.1 文字遮挡与模糊的多种退化方式做基于GAN的文字修复第一步不是调模型而是先把“复杂背景”和“文字受损”这两个概念变成能监督学习的东西。真实场景里文字受损常见形式有几种大色块覆盖比如印章、污渍、贴纸边缘磨损笔画断开但不缺整块区域运动模糊或失焦笔画的对比度下降反光与阴影文字被高光或暗影局部吞掉。不同退化形式对模型的要求差异很大——大色块覆盖考验生成器的语义想象能力边缘磨损考验笔画连续性建模模糊则是低频信息保留问题。如果只用单一退化方式训练模型一上真实数据就会露馅。常见做法是走合成数据路线找一批不带文字的复杂背景图把文字用随机字体、随机颜色、随机角度渲染上去得到“干净图”再叠加退化得到“破损图”同时保存一个掩码标明哪些像素需要修复。这套三元组clean, damaged, mask既便宜又能精确控制退化类型。背景图源不必追求高质量纹理丰富更重要——墙面上拍的照片、布料纹理、带噪点的扫描纸都行。我一般把背景库分成训练集和验证集验证集里刻意留出和训练集不同来源的背景避免模型背下背景纹理分布。2.2 数据标注与掩码生成一条脚本拉通合成脚本的核心是“文字渲染 退化叠加 掩码生成”三个环节。下面这段是我常用套路的一个精简版逻辑清晰、能直接改来用import numpy as np import cv2 from PIL import Image, ImageDraw, ImageFont def render_text_on_background(bg, text, font_path, max_angle15): 在背景图上渲染文字返回干净文字图和文字所在的矩形掩码 bg_h, bg_w bg.shape[:2] # 随机生成字体大小与颜色确保和复杂背景有真实拍摄的对比度 font_size np.random.randint(bg_h // 12, bg_h // 6) font ImageFont.truetype(font_path, font_size) # 先量文字尺寸再做旋转避免画布裁剪 canvas Image.new(RGB, (bg_w, bg_h), (0, 0, 0)) draw ImageDraw.Draw(canvas) text_w, text_h draw.textbbox((0, 0), text, fontfont)[2:] text_img Image.new(RGBA, (text_w 40, text_h 40), (0, 0, 0, 0)) text_draw ImageDraw.Draw(text_img) fill (np.random.randint(30, 220), np.random.randint(30, 220), np.random.randint(30, 220), 255) text_draw.text((20, 20), text, fontfont, fillfill) # 随机位置、旋转、透视贴到背景上 angle np.random.uniform(-max_angle, max_angle) text_img text_img.rotate(angle, expandTrue) paste_x, paste_y np.random.randint(0, bg_w - text_img.width), np.random.randint(0, bg_h - text_img.height) bg_pil Image.fromarray(bg) bg_pil.paste(text_img, (paste_x, paste_y), text_img) # 掩码文字区域为1背景为0之后退化会叠加在掩码上 mask np.zeros((bg_h, bg_w), dtypenp.uint8) mask[paste_y:paste_y text_img.height, paste_x:paste_x text_img.width] 255 return np.array(bg_pil), mask这段代码的要点先用RGBA画布独立渲染文字再旋转、贴回背景是为了保证文字边缘不会因为直接画在背景上而带上看不见的黑边字体颜色取30到220的随机范围避开纯黑纯白更接近真实拍摄中的反光环境。掩码按文字外接矩形生成是一个粗粒度掩码——这背后有意图真实场景里的遮挡往往比单条笔画大用矩形掩码比逐像素笔画掩码更能逼模型做语义重建而不是做膨胀卷积。退化叠加的函数我通常配合掩码一起写思路是对掩码区域分别施加模糊、污渍纹理、噪声、以及随机形状的色块生成最终的破损图。一个容易被忽略的参数是退化面积占整张图的比例。我一般让掩码区域占图的5%到25%之间浮动。太低模型不需要学习背景建模就能中太高生成器会倾向于把整图重画出现背景“重绘失真”的副作用。def degrade_region(clean, mask, blur_ks(9, 9), stain_intensity0.4): 对掩码区域执行多种退化返回受损图和保真掩码 damaged clean.copy() # 笔画级模糊模拟失焦与运动模糊 damaged cv2.GaussianBlur(damaged, blur_ks, 0) # 污渍用噪声叠加做半透明色块 noise np.random.randint(0, 60, clean.shape, dtypenp.uint8) stain_mask (mask 0).astype(np.uint8) damaged cv2.addWeighted(damaged, 1 - stain_intensity, noise, stain_intensity, 0) # 只保留掩码区域的信息破坏背景保持不变 out clean.copy() out[stain_mask 0] damaged[stain_mask 0] return out这里关键的参数是stain_intensity它控制退化强度。0.4表示原始干净文字的信息保留60%、噪声叠加40%适合第一轮预训练如果一上来就设0.8生成器要同时学重建和猜测训练很容易震荡。数据规模上我的经验是单卡训练用2万到5万张合成图足够不要盲目追求百万级——合成数据的多样性瓶颈在字体和背景组合不在数量。字体至少要准备10种以上常见做法是把系统自带的中文字体目录扫一遍再加上开源的宋体、黑体、手写体。艺术字、繁体、异体字这类在后期微调阶段再引入前期搅进去会拖慢收敛。3. 复杂背景为什么会骗过模型GAN在文字修复上的选型逻辑3.1 为什么L1/L2损失在复杂背景上会翻车如果用纯卷积网络加L1损失去重建文字区域模型会在“模糊平均”和“背景纹理复制”之间摇摆。原因是L1损失是逐像素损失的期望最小化它认为所有候选修复结果里取像素均值是最安全的。对白底黑字的规则票据这个均值结果尚可接受对复杂背景像素均值意味着颜色被周围背景拉平文字边界形成一圈“糊边”而且背景里本该有的高频纹理会被抹掉。我见过不少团队一上来就套用超分辨率或去噪的L1模型结果修复出来的文字方向错乱、笔画扭曲背景变成塑料表面——这就是任务定义错了。GAN的介入价值在于判别器不是逐像素对比而是对整块patch的真伪做判断它强制生成器输出落在真实图像的流形上。具体到文字修复判别器会学到“文字既不能模糊也不能是背景纹理的简单延伸”这让生成器被迫做出语义选择。注意我说的是“选择”——生成器在看到被印章盖住的数字“3”和“8”的中间状态时必须根据上下文猜一个最可能的数字。这种猜的能力来自对抗训练不来自重建损失。3.2 判别器要看什么感受野、局部判别与多尺度文字修复的判别器设计和图像生成不完全一样。生成人脸时判别器看全局整体就行文字修复里一个字的笔画可能只有十几个像素宽全局判别器会对整幅图的统计特征做判断根本看不清局部笔画是否断了。常见的做法是把判别器换成分块判别——PatchGAN输出每个patch的真伪概率图强迫生成器在每个局部块上都和真实图像分布对齐。Patch大小我一般取70x70对256x256的输入图来说差不多能覆盖两三个汉字既能约束细节又不至于把生成器锁死在单个笔画上。多尺度判别器是另一个有效增强同时对原图、1/2分辨率、1/4分辨率做判别。低分辨率分支约束整体色调和排版布局高分辨率分支约束笔画锐度和背景纹理。我在训练时会明显感到多尺度让生成图更少出现“颜色断层”——单判别器对色彩漂移不敏感多尺度里的低分分支会强行把全局色温拉回来。3.3 生成器怎么选U-Net、编解码还是带注意力生成器主体用U-Net是最稳妥的起点。U-Net的跳跃连接把编码器各层的浅层特征直接接到解码器对应层这对文字修复至关重要——文字笔画是高频边缘信息如果经过瓶颈层再上采样高频细节已经丢了跳跃连接让解码器可以直接引用原图的高清特征。在U-Net卷积模块上我建议用门控卷积替代普通卷积门控卷积对每个像素学习一个动态开关遇到掩码区域会把门打开去做重建遇到背景区域会把门关上保持原样这就避免模型把背景纹理误当成破损区进行重绘。如果预算允许可以在U-Net的瓶颈层加一个Transformer block。文字修复有一个特点同一个字符的上下文往往跨越很长的空间距离比如“某银行”三个字被横向污渍连成一条纯卷积的感受野不够需要注意力机制建立跨区域依赖。不过实际工程中Transformer的收益和训练成本不成正比我的建议是先上U-Net加门控卷积效果不够再提级。生成器里我还会挂一个辅助分支结构预测头输入中间特征输出和原图同尺寸的单通道掩码监督信号是文字笔画骨架的GT掩码。这个分支在推理时可以直接剪掉但在训练时相当于给生成器一个“先找文字再修文字”的显式引导比在损失函数里加权重更有效。下面是一个可运行的生成器骨架代码突出了我上面说的点import torch import torch.nn as nn class GatedConvBlock(nn.Module): 门控卷积学习掩码区域的开合状态保留背景纹理不被重绘 def __init__(self, in_ch, out_ch): super().__init__() self.conv_feat nn.Conv2d(in_ch, out_ch, 3, padding1) self.conv_gate nn.Conv2d(in_ch, out_ch, 3, padding1) self.bn nn.BatchNorm2d(out_ch) def forward(self, x): feat self.conv_feat(x) gate torch.sigmoid(self.conv_gate(x)) return self.bn(feat * gate) class TextRestorationGenerator(nn.Module): def __init__(self, in_ch4, out_ch3): in_ch4RGB图像 二进制掩码掩码区域1 out_ch3修复后的RGB图像 super().__init__() # 简化的U-Net编码-解码结构 self.enc1 GatedConvBlock(in_ch, 64) self.enc2 GatedConvBlock(64, 128) self.enc3 GatedConvBlock(128, 256) self.dec3 GatedConvBlock(256 128, 128) self.dec2 GatedConvBlock(128 64, 64) self.dec1 nn.Conv2d(64 in_ch, 3, 3, padding1) def forward(self, x, mask): inp torch.cat([x, mask], dim1) e1 self.enc1(inp) e2 self.enc2(e1) e3 self.enc3(e2) d3 self.dec3(torch.cat([e3, e2], dim1)) d2 self.dec2(torch.cat([d3, e1], dim1)) # 跳跃连接保留原始输入让生成器直接看到无伤背景 out self.dec1(torch.cat([d2, inp], dim1)) return torch.tanh(out)代码里的关键是门控卷积中gate的sigmoid输出它在训练中会自动学习“打在背景上的浅层特征门值为0、打在掩码区域的门值为1”这就是背景不被重绘的机制。输入把掩码作为第四通道连进去比单靠内部学习掩码更直接相当于显式告知模型哪里要修、哪里不能动。U-Net的跳跃连接体现在e3与e2拼接、d3与e1拼接、最后又与inp拼接层数比较浅但正好够256x256输入的文字修复任务。如果想要更强的重建能力把每层卷积替换成ResBlock并在瓶颈层加自注意力参数会增加到原来的2到3倍训练时间也随之上升——先跑通这个版本再决定要不要加重。4. 基于GAN的文字修复训练流程从预训练到微调4.1 第一阶段结构感知预训练GAN训练最怕的是生成器和判别器在对抗中双双摆烂尤其是文字修复这种任务生成器如果一开始输出就是乱的判别器很容易学到“凡是模糊就是假的”这种粗暴规则后续再怎么调都难救。我几乎总是先单独训生成器用L1加感知损失加结构引导不接判别器。这个阶段让生成器先学会“大方向正确”笔画位置对、字体粗细大致对、背景颜色不被破坏。结构感知预训练的损失函数核心是三部分加权L1重建损失保证像素级接近感知损失用VGG16中间层的特征做比对让生成图像和干净图像在高级语义特征上接近结构引导损失是把辅助分支预测的笔画骨架和GT骨架做二值交叉熵。权重我一般配成L1:感知:结构 1:0.1:0.05。感知损失权重不要贪大0.1已经能让背景纹理自然很多权重超过0.3就会出现“纹理太丰富、文字失真”的另一面翻车。def structure_aware_loss(generated, gt_text, pred_structure, gt_structure, l1_w1.0, vgg_w0.1, struct_w0.05): import torch.nn.functional as F # 感知损失需要预训练的VGG特征这里示意计算流程 l1_loss F.l1_loss(generated, gt_text) vgg_loss F.mse_loss(vgg_features(generated), vgg_features(gt_text)) struct_loss F.binary_cross_entropy_with_logits(pred_structure, gt_structure) return l1_w * l1_loss vgg_w * vgg_loss struct_w * struct_loss这个阶段的优化器我用Adam初始学习率1e-4batch size看显存取4到8。分辨率建议先在256x256上训练不要一上来就512因为文字修复的判别器最终要在高分辨率上精修而生成器结构在低分辨率先稳定更容易。训练步数大约5万步期间把学习率按cosine退火降到1e-5。判断这个阶段是否收敛我看的不单是loss曲线而是直接抽几批验证集图看文字区域是否从“糊成一团”变成“可辨认字体形状”背景是否保持原样。如果背景变了多半是感知损失权重太高生成器在“篡改背景”的边缘试探。4.2 第二阶段GAN对抗学习预训练稳定后加入判别器进入对抗阶段。常见错误是直接沿用上一阶段的低学习率。此时生成器的参数已经有合理的初始化判别器是白纸两者天然不平衡。我的做法是冻结生成器主干的前两层只解冻高层和辅助分支学习率降到1e-5。判别器单独用5e-5的学习率让它快速追上而不过冲。对抗损失用hinge形式比原始GAN的log-loss更稳定梯度在高置信区间被截断不会出现判别器瞬间把损失降到0的情况。训练节奏参考这个经验每轮的判别器和生成器更新频次固定1:1不搞交替加练判别器——文字修复的判别器特征相对简单加练会让它过拟合到背景纹理上生成器随即开始大量生成假纹理来对抗最终输出“五彩斑斓的黑”。我在训练中会盯两个数值D对真实patch的均值输出和D对生成patch的均值输出。理想状态是真实值略高于生成值两者差值不超过0.3且都在0.5附近振荡。如果真实值从训练开始就一直是1.0说明判别器太强生成器梯度会快速消失。对抗阶段的完整训练步可以用下面伪代码概括for step in range(total_steps): real_imgs, damaged_imgs, masks, gt_struct next(loader) # 生成 pred_imgs, pred_struct generator(damaged_imgs, masks) # 判别器更新真实patch判定为真生成patch判定为假 d_real discriminator(real_imgs) d_fake discriminator(pred_imgs.detach()) d_loss F.relu(1 - d_real).mean() F.relu(1 d_fake).mean() d_optimizer.zero_grad() d_loss.backward() d_optimizer.step() # 生成器更新对抗损失 重建损失 结构损失 d_fake_for_g discriminator(pred_imgs) g_adv -d_fake_for_g.mean() g_recon structure_aware_loss(pred_imgs, real_imgs, pred_struct, gt_struct) g_loss g_adv g_recon g_optimizer.zero_grad() g_loss.backward() g_optimizer.step()阶段二我一般跑到2万步左右。此时批量大小可以降到2或4因为判别器输入的是原尺寸图像加随机裁剪的patch显存占用比阶段一高很多。一个实用技巧是阶段性余弦退火每5000步把学习率降到当前值的0.2再恢复这样能让生成器再尝试几轮比较激进的结构变化不至于在一个局部解上停留太久。4.3 关键参数设置与消融验证参数表说一百遍不如跑一轮消融。建议在验证集上做三组对照不加GAN只保留结构感知预训练、加GAN但不加结构损失、完整版。对比指标除了OCR字准率还要肉眼对比背景纹理的一致性。我遇到过的情况是OCR准确率两者差不多但人工一眼能看出加GAN的图背景更自然——这说明可读性提升和视觉质量提升并不完全同步最终目标决定了你要不要付出对抗训练的时间成本。参数/组件预训练阶段对抗阶段说明学习率生成器1e-41e-5第二阶段不能沿用大学习率容易撕裂前期结构学习率判别器无5e-5判别器要从头学速率快于生成器批量大小82-4显存输入与patch数量共同决定损失权重L1/感知/结构1 / 0.1 / 0.051 / 0.1 / 0.05 减半对抗对抗损失加入后重建损失权重可以略微释放分辨率256256-512先在低分辨率定型结构再上调做细节精修消融实验本身也要设定统一的客观指标推荐用修复后图像的OCR字符准确率OCR Accuracy作为核心指标配合SSIM和LPIPS。OCR准确率反映的是“能不能读出来”LPIPS反映的是“人眼看像不像”两者结合才能判断一次改动是变好还是变糟。5. 复杂背景文字修复的常见问题排查5个典型坑5.1 现象文字修出来了背景糊成一片这是综合症我在不止一个项目里见过。生成器确实把文字区域补上了笔画也连贯但背景的纹理没了原来墙面的水泥颗粒、纸面的纤维感全变成光滑的渐变。原因在于重建损失太大生成器选择了一种保守策略输出频率低的均值图像背景高频纹理全部牺牲。另外生成器接收的输入是带掩码的原图如果门控卷积的门没有真正学会区分掩码内外背景区域也会被重新渲染一遍。解决的办法是三个方向同时上第一把重建损失从L1换成L1加拉普拉斯金字塔损失加强对高频细节的约束第二检查门控卷积的gate输出分布如果gate在背景区域也不为零说明预训练阶段背景重绘没被抑制可以加大背景区域的掩码权重让mask通道更强地压制生成活动第三把判别器的感受野从70x70缩到更小让局部纹理分析被加强。5.2 现象训练loss在下降但生成图越修越“脏”这是GAN训练里最隐蔽的陷阱。生成器的重建损失持续下降但抽出的样本里文字边缘出现大量颗粒状伪影、背景出现不自然的色斑。原因在于判别器被“骗过”了它发现生成器的输出中带着某种高频特征就能稳定骗过自己于是生成器就强化这种特征形成对抗中的“特征欺骗”循环。这种伪影不是噪声它和真实文字笔画交织在一起肉眼看着像墨迹晕染。解决思路非常直接验证集上的人工观察比任何loss都权威。一旦发现这种迹象立刻把对抗损失的权重下调一半或者切回纯预训练模式再训一段时间让重建损失把伪影磨掉。另一个有效手段是给生成patch加随机噪声后才送进判别器破坏判别器对单一特征的依赖伪影会明显减少。5.3 现象显存OOM或训练中途不再收敛训练到一半显存爆掉是家常便饭。文字修复比普通图像生成更吃显存因为输入要额外带一个掩码通道判别器又要处理原图和生成图两个分支。可能出现的情况是batch4在256分辨率下勉强能跑一旦把生成器换成更大的ResBlock版本显存直接溢出。解决方法是分块训练。把原图按patch切出若干区域每块做一个样本掩码也跟着切。常见做法是取128x128的patch步长64这样每张图能出多个训练样本batch可以调大。注意推理时要切成同样尺寸还要带overlap否则拼接处会有一条可见的接缝。训练收敛不了还要检查是否用了BatchNorm——GAN训练中BatchNorm在小batch下统计量抖动大建议换成InstanceNorm或干脆去掉注意这一改动会改变生成器输出的确定性适合在预训练阶段就定下来。5.4 现象修复后的文字OCR能读但字体、笔画形态失真这个现象很尴尬OCR准确率到95%了但人眼一看就知道字是“画”出来的宋体的衬线丢了手写体的粗细变化没了。原因在于模型学习的只是字符的语义类别并没有学习字体级的结构细节。这在线下部署到票据识别场景时尤其致命——下游系统往往需要同时读文字内容和做印章比对字体失真会干扰比对算法。解决方向一是数据侧合成数据时引入字体多样性同一个字符用不同字体渲染多份让模型看到同一个字在不同骨架下的表现形式。二是模型侧在结构预测分支的监督信号里不仅要预测笔画骨架还要让辅助分支输出一个“字重”二值图区分笔画的粗细分叉。三是损失侧在感知损失之外加一个针对笔画边缘方向的损失用Sobel算子提取梯度方向直方图让生成图在笔画方向的统计上和GT一致。这个方法能显著减少“笔画走向诡异”的问题。5.5 现象真实场景掩码与训练掩码分布不一致效果崩盘模型在合成mask下表现很好一到真实数据就各种怪异。这是分布偏移的典型表现。真实场景的掩码有多种来源印章叠加是非刚性的半透明掩码笔画缺损是不规则细长掩码而标注人员框选的可能是整块矩形。合成数据里掩码是规则的矩形或圆形真实掩码分布完全不同无监督GAN很容易把分布外的输入归为“可以乱来”的区域。最实用的解决方式是做一个“掩码增强”的预处理模块对标注的真实掩码做膨胀、腐蚀、随机旋转、加噪声生成“伪真实掩码”加入训练。同时保留一份纯规则掩码的数据比例约3:7规则7、增强3避免模型彻底适应伪真实掩码的噪声特征。我在真实项目里还会专门收集10到20张带真实遮挡的原图和标注掩码作为验证集合的补充——这比再多合成1万张数据都管用因为它是分布偏移方向的校准锚点。6. 评估指标与部署微调修复效果怎么量化、模型怎么上线6.1 三类评估指标OCR准确率、像素指标、人工打分修复模型不能只看“好看”也不能只看“准确率”要分三维度量化。第一是任务指标用OCR系统分别识别修复前和修复后的图像统计字符错误率CER和词错误率WER。修复算法有效的最低标准是CER显著下降如果OCR系统原来错得离谱、修复后也只是改错成另一种错那算法再好看也不能投入生产。第二是画质指标PSNR和SSIM是入门参考但PSNR在复杂背景上不可全信它在纹理区域容易被大误差主导LPIPS才是观察人类感知相似度更可靠的指标。计算LPIPS需要预训练的AlexNet特征跑一次全量验证集大概十几秒完全值得加进每次实验的评测代码里。第三是人工视觉打分每张验证图由3个人按5分制评价四个维度——文字可读性、字体保真度、背景一致性、整图自然度。我所在的团队是每次模型更新必过一次人工打分数量不用多40张图足够发现指标掩盖的细节问题。6.2 把模型接入OCR前处理管线实际部署时模型要作为OCR前处理的一环而不是独立产品。常见的接入方式输入图像先做文档矫正然后文字检测器定位文字区域检测出的文字bbox内的图像如果质量太差就送入修复模型修复结果再送回识别模型。修复模型不要对整张图跑——文字区域在整张图里占的比例不大整图推理会浪费大量算力还可能在无文字背景区域引入幻觉。用一个二次检测结果作为掩码生成的前置条件按patch推理只在需要修复的区域上花算力。模型导出和加速上PyTorch训练好的模型转ONNX是常见做法。注意转ONNX时的坑U-Net里有形状推断分支的话要用onnx动态轴或者固定输入尺寸否则batch size变化时导出失败门控卷积没有特殊算子转ONNX顺畅。如果目标是CPU推理INT8量化能把推理时间减一半以上代价是文字边缘的锐利度略降——这个取舍要在真实测试集上用OCR准确率重新验证不要凭感觉接受或拒绝。6.3 内存、速度与边缘部署的取舍落到实际生产复杂背景文字修复的算力需求往往比想象中高。生成器本身不算大参数量通常在20M到40M但推理时的有效计算量不低。256x256输入、单张图80ms在GPU上是可以接受的但换到OCR一体机那种小盒子CPU一张图可能要2到3秒。这就面临取舍是优先OCR一次识别准确率还是优先整条识别链路的时延预算。我的建议是分层策略第一轮先用轻量级传统算法做快速修复比如形态学重建搭配局部自适应阈值能解决一部分遮挡不严重的场景只有第一轮修复后OCR置信度仍低于阈值时才调用GAN修复模型。这种“快通道加慢通道”的结构在实际项目中能覆盖80%的简单场景算力消耗控制在GAN常开方案的十分之一以内。系统部署后还要做回归测试池固定一批票据、古籍、产品包装图每次模型更新都跑同一套OCR评测脚本回头翻看指标波动。我现在养成的习惯是任何模型改动都要拿一张最复杂、最苦手的真实样例做“体感测试”不只看人工打分还看OCR在修复前后输出的置信度分布——如果置信度上升但不稳定说明修复方向对了但还在猜测边缘需要回去调结构损失。这条路跑下来复杂背景文字修复并没有玄学每一步都有迹可循数据栈、模型栈、损失栈、评测栈把每一层拆开见真章。希望帮到你。本文还有配套的精品资源点击获取