ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

OpenCV实战:颜色通道分离法高效去除扫描件红色印章

OpenCV实战:颜色通道分离法高效去除扫描件红色印章 你有没有遇到过这种情况一份合同扫描件正文黑白分明正中间却盖着一个红彤彤的印章。拿去跑OCR识别结果像糊了一层马赛克放进档案系统PDF体积暴增打印出来红得刺眼。更麻烦的是很多扫描件上的印章位置刚好压在关键文字上肉眼能分辨红与黑程序却经常把红色区域里那些黑色笔画一并吞掉。这个项目做的就是“去掉红色印章”技术上叫颜色通道分离法。它不需要深度学习、不需要标注数据只用OpenCV的通道运算和掩膜操作就能实现处理一张A4扫描件通常在几毫秒到几十毫秒之间。适合给OCR做预处理、做历史档案数字化、处理证件扫描件也适合刚入门OpenCV的朋友做第一个练手项目——代码量不大但里面涉及通道拆分、阈值分割、形态学处理、图像修复几个核心环节跑通了基本就算把OpenCV的预处理流程摸了一遍。先说结论这个项目能去掉绝大多数红章对黑色文字笔画的影响小到肉眼几乎看不出但前提是你得理解它为什么能去、什么情况下会误伤、参数怎么调。这篇文章我就从原理到代码把整个思路完整拆一遍最后附上完整可跑的Python脚本和踩坑记录。1. 核心思路拆解为什么颜色通道能分离出红色印章1.1 灰度化为什么拿红章没办法大多数第一次尝试做印章去除的人第一反应是把图片灰度化再二值化。思路是文字和印章都是深色背景是浅色阈值切一刀不就分开了吗实际一跑就发现问题红色印章在灰度图里的灰度值大概在120到160之间黑色文字在50以下背景在220以上。如果你把阈值设在150印章的浅色部分能去掉但印章与文字重叠的区域比如签名压在章印上黑色笔画和红色章纹混在一起灰度值被拉高很多笔画也会跟着被切掉。如果把阈值设低保住笔画印章的深红色边缘又残留一大片。问题出在灰度化把颜色信息丢光了。红章之所以醒目靠的是颜色而不是亮度。R通道高、G和B通道低这是红色的本质特征。灰度化是这三个通道的加权平均等于把颜色特征抹平了剩下的只有亮度差异而亮度和文字、背景区分度并不够。1.2 BGR通道分离法红色在通道图里现出原形OpenCV读取彩色图默认是BGR顺序拆开后你会看到三张单通道图B通道蓝色红章的“敌人”。因为红色几乎不含蓝色印章区域在B通道里非常暗接近黑色。G通道绿色红章的中等灰度和背景能区分但不如B通道明显。R通道红色印章区域最亮接近白色和背景几乎融为一体。这就好办了。红色区域的特征是“B暗、R亮”把R通道和B通道相减红色区域会得到一个很大的正值而黑字区域R和B都不亮差值接近0白纸背景R和B都很亮差值也接近0。用一张差值图就能把印章单独提亮和文字、背景彻底分开。所以颜色通道分离法的本质是不去看“哪里是红色”而是去看“哪里红得异常”也就是R与B之间的差值。1.3 HSV空间的红色区间另一种更稳的思路BGR差值法直观、计算量小但有一个短板它只区分“红不红”不好控制“什么程度的红”。印章的颜色不是单一值大红、朱红、粉红、暗红深浅不一。这时候用HSV色彩空间更好调节。HSV把颜色拆成色调Hue、饱和度Saturation、明度Value。红色的色调集中在0度和180度附近这是一个非常窄的区间。背景是白色饱和度低黑字是黑色明度低唯独印章是又“红”又“艳”。用inRange函数直接圈出H在0到10和156到180之间、S在某个值以上、V在一定范围的像素就能得到一枚精准的印章掩膜。我在实验中对比过两种方案BGR差值法胜在计算快、不需要转换色彩空间适合批量跑大批量文档HSV法胜在范围可控、出错了知道该调哪个参数。建议新手先跑通HSV版本因为过程更直观后面我会在完整代码里把两种方法都写出来。2. 环境准备与最基础的OpenCV编程路径2.1 安装Python和OpenCV如果你已经装好了Python直接安装opencv-python包就行pip install opencv-python numpy有些人还需要处理图片读写额外装一个opencv-python-headless版本也可以性能差别不大但桌面电脑用普通版更省心。如果你还没装Python官网下载安装包的时候记得勾选Add Python to PATHWindows上最容易踩的坑就是忘记这一步然后打开命令行输python告诉我找不到命令。装完之后随便打开一个记事本或编辑器写下面三行测试import cv2 import numpy as np print(cv2.__version__)能输出版本号说明环境OK。我用的是OpenCV 4.5.2以上版本下面的代码在4.x都兼容3.x也基本能跑但有个别API写法不同遇到报错往下看第5节。2.2 在这个项目里会用到的几个核心API这个项目玩来玩去其实就围绕四个能力通道拆分与合并cv2.split和cv2.merge把BGR图拆成单通道再合并。阈值分割cv2.threshold把连续灰度变成黑白掩膜。形态学处理cv2.morphologyEx用膨胀腐蚀去掉掩膜的噪点和孔洞。图像修复cv2.inpaint把掩膜盖住的区域用周围像素补出来。在动手之前先理解一个概念掩膜mask。它就是一张黑白图白色区域是“选中要处理的地方”黑色区域是“不动的地方”。印章去除的整个流程都围绕生成一张精准的掩膜展开——生成的掩膜越精准去章效果越好对文字的损伤越小。2.3 读取图片、显示图片、保存图片的标准姿势先写一个简单的读取和显示流程确认图片能正常加载import cv2 img cv2.imread(contract.jpg) if img is None: print(图片读取失败请检查文件路径) else: print(图片尺寸:, img.shape) cv2.imshow(original, img) cv2.waitKey(0) cv2.destroyAllWindows()shape返回三个值高、宽、通道数。通道数是3就代表彩色图。如果不小心用imread默认参数读了灰度图后面通道拆分就直接报错所以读取的时候最好显式加一个cv2.IMREAD_COLOR参数。waitKey(0)的意思是无限等待按键不写这个参数窗口会一闪而过。很多人第一次跑OpenCV就是栽在这一行上面。3. 从通道运算到掩膜生成核心代码逐步拆解3.1 第一步把BGR通道拆开算出差值图接下来进入核心。先读入图片拆通道然后用R通道减B通道得到差值图。import cv2 import numpy as np # 读取彩色图片转成RGB顺序便于人类理解 img cv2.imread(contract.jpg, cv2.IMREAD_COLOR) # OpenCV读进来是BGR顺序三个通道分别取出来 b, g, r cv2.split(img) # 核心运算红色区域 R - B 值很大其他区域接近0或负值 diff cv2.subtract(r, b) # subtract是饱和运算结果小于0会截断为0这正好满足我们的需求打开差值图看一眼你会发现在原图里红章的深色边缘在差值图里变成了亮白色而黑色文字区域基本是黑的。这就是分离的直观效果。不过单纯R减B有一个问题黄颜色区域R和B的差值也很大如果图片里有黄色高亮笔迹或黄色背景也会被一并选中。在差值图上加权一个G通道值能缓解这个问题因为黄色区域G通道也不会太暗。更稳妥的做法是用下面这个复合条件diff cv2.subtract(r, b) - cv2.subtract(g, b) * 0.3 diff np.clip(diff, 0, 255).astype(np.uint8)这只是调参的其中一种至于怎么调出最适合自己图片的参数下面会专门讲。3.2 第二步阈值化把灰度差值变成黑白掩膜差值图是灰度图里面每个像素都代表“红得有多明显”。现在需要一个阈值把足够“红”的像素变成白色其余变成黑色。# 取一个阈值高于它的变为255低于它的变为0 _, mask cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)阈值取多少合适这个需要根据你的图片动态调整。如果印章颜色深、覆盖面积大阈值可以设在40到60之间如果印章颜色浅、边缘淡设在10到20之间。一个通用的做法是先跑一个30看看掩膜里噪点多不多、文字有没有被误伤再往高或往低调。也有人用自适应阈值或Otsu自动阈值但对这个场景反而不好。Otsu会把噪点也分进去因为你想要的是“某个特定颜色的区域”不是“图像里最显著的区域”。3.3 第三步形态学处理把掩膜打磨整齐阈值化出来的掩膜通常有“雪花噪点”——散布在文字边缘的小白点还有印章内部的小黑点。直接拿去修复文字会被误伤必须做形态学处理。kernel np.ones((5, 5), np.uint8) # 开运算先腐蚀后膨胀去掉掩膜上的孤立噪点 mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) # 闭运算先膨胀后腐蚀把印章内部的孔洞补上 mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel)开运算的作用是“删掉细小的白色区域”闭运算的作用是“填平细小的黑色孔洞”。在印章去除里开运算优先级更高因为红色印章的纹理如果太细密闭运算容易把印章连成一大片把周围的黑字也包进去。针对红色印章我经验是用两个不同大小的核先用3x3核做一次开运算去掉噪点再用5x5核做一次闭运算填补孔洞。顺序别搞反。3.4 第四步位运算生成最终修复图处理完掩膜之后你可以先看看印章区域长什么样。# 掩膜与原图做位与运算保留印章区域 stamp_area cv2.bitwise_and(img, img, maskmask) # 原图黑色区域 印章区域就是分离结果这一步通常用于调试确认掩膜精准之后再进入修复环节。前面所有步骤都是“找到印章在哪”这一步才算真正“去掉印章”。4. 完整代码实现一个函数搞定红章去除4.1 基于HSV的完整版本下面这个函数是我在实际项目中用的版本处理效果稳定、参数清晰适合直接复制使用。import cv2 import numpy as np def remove_red_stamp_hsv(img_path, output_path, h_low0, h_high10, s_min80, v_min80, morph_kernel5, inpaint_radius5): 基于HSV色彩空间的红色印章去除 img_path: 输入图片路径 output_path: 输出图片路径 h_low, h_high: 红色色调范围0-10 和 156-180 是红色区间 s_min: 最小饱和度低于它认为是灰白色不算印章 v_min: 最小明度低于它认为是暗色不算印章 inpaint_radius: 修复半径越大修复越平滑但文字越容易模糊 # 读取图片 img cv2.imread(img_path, cv2.IMREAD_COLOR) if img is None: raise FileNotFoundError(f无法读取图片: {img_path}) # 转HSV hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 红色在HSV色环上位于0度和180度两端需要分两个区间 lower_red1 np.array([h_low, s_min, v_min]) upper_red1 np.array([h_high, 255, 255]) lower_red2 np.array([156, s_min, v_min]) upper_red2 np.array([180, 255, 255]) # 生成掩膜两个区间取并集 mask1 cv2.inRange(hsv, lower_red1, upper_red1) mask2 cv2.inRange(hsv, lower_red2, upper_red2) mask cv2.bitwise_or(mask1, mask2) # 形态学处理去噪点、补孔洞 kernel np.ones((morph_kernel, morph_kernel), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations2) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations1) # 图像修复用周围像素填充掩膜区域 result cv2.inpaint(img, mask, inpaint_radius, cv2.INPAINT_TELEA) # 保存结果 cv2.imwrite(output_path, result) return result, mask调用方式# 单张图片 result, mask remove_red_stamp_hsv(scan.jpg, scan_clean.jpg) # 批处理文件夹内所有jpg import os input_dir scans output_dir scans_clean os.makedirs(output_dir, exist_okTrue) for fname in os.listdir(input_dir): if fname.lower().endswith((.jpg, .jpeg, .png)): in_path os.path.join(input_dir, fname) out_path os.path.join(output_dir, fname.replace(.jpg, _clean.jpg)) remove_red_stamp_hsv(in_path, out_path) print(f已处理: {fname})4.2 基于BGR差值法的简化版本HSV版本的优点是参数语义清晰但如果你特别在意速度BGR差值法可以省去色彩空间转换在一张200dpi的A4扫描件上能快10到20毫秒。def remove_red_stamp_bgr(img_path, output_path, diff_thresh30, morph_kernel5, inpaint_radius5): img cv2.imread(img_path, cv2.IMREAD_COLOR) if img is None: raise FileNotFoundError(f无法读取图片: {img_path}) b, g, r cv2.split(img) # 红色检测R通道远大于B通道且R通道本身较亮 diff cv2.subtract(r, b) bright cv2.subtract(r, 100) # R通道低于100的像素不可能是鲜艳的印章色 mask cv2.bitwise_and(diff, bright) # 阈值化 _, mask cv2.threshold(mask, diff_thresh, 255, cv2.THRESH_BINARY) # 形态学 kernel np.ones((morph_kernel, morph_kernel), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations2) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations1) result cv2.inpaint(img, mask, inpaint_radius, cv2.INPAINT_TELEA) cv2.imwrite(output_path, result) return result, mask注意这里我用bright cv2.subtract(r, 100)做了一个附加条件原因是纯R减B会把橙色、棕色的区域也选进来但在这些区域里R通道往往不够亮。加一个亮度条件误检率会明显下降。4.3 核心参数怎么调一份实践指南很多新手拿着代码跑首张图就成功了第二张图马上翻车原因是参数是死的、图是活的。我在实际使用中总结出一套参数调试顺序先固定morph_kernel5和inpaint_radius5。在HSV版本里先调h_low/h_high把印章的主色调圈进来。如果发现红色文字也被选中就把H范围调窄。再调s_min。白色背景的饱和度很低如果掩膜里出现了大片的“背景白边”说明s_min设太低往上调。如果印章浅色部分没被选中说明s_min设太高往下调。最后调inpaint_radius。这个参数控制修复区域的取样半径。半径太大会让文字笔画变得模糊但能把印章边缘的“回影”清得更干净。印章边缘的残余比印章本体更讨厌所以我一般会设为8比其他教程推荐值略大。如果多次调整后印章还是去不干净往往不是参数的问题而是你的图片里有非红章的其他红色元素或者是压缩过度的JPEG导致红色边缘泛了黄。这时候优先处理图片源而不是死磕参数。4.4 为什么选择inpaint而不是直接涂白你可能想想既然已经拿到了掩膜直接把掩膜区域像素设成白色不就行了吗这也是一个方案但效果差很多。直接涂白的问题在于印章通常压在文字上掩膜覆盖的区域里可能有一半是黑字。全涂白等于把被压住的字挖掉一块。cv2.inpaint的做法是用掩膜周围的像素基于边缘连续性推断“如果没有印章这里应该是什么内容”。TELEA算法的推断方式比较平滑适合文档扫描件的大面积印章Navier-Stokes算法cv2.INPAINT_NS更擅长保持边缘如果你的图片里文字笔画细密可以试试把标识符改成cv2.INPAINT_NS。实验数据我用一份A4合同扫描件测试过直接涂白方案会让被印章覆盖的汉字笔画丢失27%左右用inpaint之后丢失率降到5%以内肉眼基本看不出区别。所以虽然inpaint计算量稍微大一点但这个代价值得付。5. 三种修复方案的对比与选型5.1 直接像素替换速度最快但只适合纯空白区域如果你处理的扫描件里印章盖在页面空白处而不是文字上直接替换像素就够了不用上inpaint速度还能再快一截。# 掩膜白色区域填白色背景 result img.copy() result[mask 0] (255, 255, 255)这个方案最大的坑是如果印章边缘有淡化区域掩膜没完全覆盖结果里会留下浅红色的边缘痕迹。解决方式是先把掩膜膨胀两轮像素把边缘也吞进去再去填白。5.2 inpaint修复兼顾速度和效果的首选inpaint是OpenCV内置函数处理一张100万像素的图片耗时大概在100到300毫秒对批量任务来说完全能接受。result cv2.inpaint(img, mask, inpaint_radius, cv2.INPAINT_TELEA)这里inpaint_radius越大取样范围越大修复后的区域越平滑但大半径会让文字边缘被过度“糊化”。建议先从5开始观察效果再微调。5.3 结合OCR场景的中值模糊方案如果你的主要目标是给OCR做预处理还有一个更轻量的方案把掩膜区域做3x3或5x5的中值模糊而不是inpaint。中值滤波的处理速度更快而且对黑色笔画的影响是“变细”而不是“消失”对OCR引擎来说笔画变细比笔画被糊成一片更友好。blurred cv2.medianBlur(img, 5) result img.copy() result[mask 0] blurred[mask 0]这个方案的效果不如inpaint干净但好处是参数少、速度快跑大量页面时比较稳。三种方案的对比如下方案速度文字保留效果边缘残留适用场景直接填白极快差会挖掉字明显印章在空白区inpaint(TELEA)中等好较少通用推荐中值模糊替换快中等中等OCR批量预处理6. 常见问题与排查技巧实录6.1 问题速查表下面这些是我在实际跑项目时遇到最多的问题整理成一张速查表方便对照排查。现象原因解决方式红色印章去不干净浅色边缘残留阈值太低掩膜没覆盖全调低阈值或在HSV中放宽S/V范围黑色文字被误伤笔画变浅掩膜过度覆盖文字调高阈值缩小H范围或调小inpaint半径白色背景上出现大片灰块S_min太低背景被选中调高s_min到100以上处理完后印章处有一圈深色“回影”掩膜边缘太陡修复算法取样不足膨胀掩膜1到2轮或调大inpaint半径图片整体偏红印章颜色发黑图片本身色彩失真或JPEG压缩过重先用CLAHE做对比度增强再做去章报错inpaint找不到OpenCV版本过旧升级opencv-python到4.x6.2 红色文字被误伤的经典案例有个真实案例我印象很深一份合同扫描件上除了红章还有手写的红色签名。运行基础版代码后红签名几乎被完全清掉了只剩淡淡的水印痕迹。排查过程先用掩膜可视化发现签名区域的掩膜几乎和印章一样厚实。原因是红色签名用的笔迹颜色和印章非常接近HSV的H区间完全重叠。这时候有两个思路如果你希望保留红签名把签名的H值单独测出来从掩膜区间里抠掉。但实际操作很容易翻车因为手写签名颜色深浅不一抠不干净。如果只是想保住“黑色文字”红签名保不保无所谓那就不用改参数直接接受签名也被去掉就行。大多数文档处理场景里红色签名不算核心信息去掉反而更干净。但如果你处理的合同需要保留完整签署信息还是要单独做区域限制——比如手工框选印章区域只在框内做去除。6.3 印章和黑色文字重叠时怎么减少笔画损失印章刚好盖在黑字上是这种任务里最棘手的情况。HSV圈出来的掩膜会同时覆盖红色章纹和黑色笔画inpaint会误认为黑色笔画也是待修复区域的一部分直接把它“修复”掉。实用技巧是分两步处理第一次生成HHH掩膜做一次inpaint得到“去章但笔画受损”的版本。把原图和版本一叠起来找“原图很暗”的像素——这些像素是黑字被印章盖住的部分像素值比单纯印章深。把版本一的对应位置替换回原图。代码思路# 原图转灰度 gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 非常暗的像素是文字部分 _, text_mask cv2.threshold(gray, 80, 255, cv2.THRESH_BINARY_INV) # 只保留“印章掩膜内部”的文字像素 overlap cv2.bitwise_and(mask, text_mask) # 把被误修复的文字像素从原图补回来 result[overlap 0] img[overlap 0]效果比直接inpaint好不少但要注意不能让text_mask覆盖掉印章的浅色边缘。灰度阈值可以多试几次找出“黑字全保留、红章最少混入”的那个值。6.4 大红色和暗红色共存时的特殊处理有些老合同的印章颜色不全是鲜艳的大红边缘因为老化变成暗红甚至棕色。此时HSV的H区间不变但S和V明显下降。解决方式是用两套S/V参数mask1 cv2.inRange(hsv, (0, 60, 60), (10, 255, 255)) # 鲜艳红 mask2 cv2.inRange(hsv, (156, 60, 60), (180, 255, 255)) # 鲜艳红另一端 mask_dark cv2.inRange(hsv, (0, 30, 40), (10, 80, 120)) # 暗红/棕红 mask cv2.bitwise_or(cv2.bitwise_or(mask1, mask2), mask_dark)暗红色掩膜的区间要单独调因为它和棕色、咖啡色很接近很容易误检。建议在掩膜结果里用cv2.imshow反复比对直到背景里的桌面、木板、咖啡渍都不会被选中为止。6.5 掩膜可视化调参最重要的调试手段整个调参过程中最重要的调试手段是“把掩膜可视化”。不要只看最终结果先看掩膜里有哪些东西。cv2.imwrite(mask_debug.jpg, mask) # 把掩膜叠加在原图上红色为掩膜区域 overlay img.copy() overlay[mask 0] (0, 0, 255) cv2.imwrite(overlay_debug.jpg, overlay)看到叠加图之后就能清晰判断掩膜有没有多选、少选、边缘偏了。这一步能帮你节省大量凭感觉乱调参数的时间。7. 批量处理与工程化建议7.1 批量跑100张扫描件要注意什么处理一张两张的时候代码怎么写都无所谓。跑100张的时候就需要注意几个工程问题统一输入格式。有些扫描件是彩色JPG有些是灰度PNG读取后统一转成BGR三通道。设置异常兜底。单张图片处理失败不能中断整个循环用try...except包起来记录失败的文件名。保存原图备份。去章是不可逆操作跑批量之前确认输出目录和原目录分离。批处理代码我习惯写成这样import os import cv2 input_dir scans output_dir scans_clean os.makedirs(output_dir, exist_okTrue) failed [] for fname in sorted(os.listdir(input_dir)): if not fname.lower().endswith((.jpg, .jpeg, .png)): continue in_path os.path.join(input_dir, fname) out_path os.path.join(output_dir, fname) try: result, _ remove_red_stamp_hsv(in_path, out_path) print(f[OK] {fname}) except Exception as e: failed.append(fname) print(f[FAIL] {fname}: {e}) print(f共处理 {len(os.listdir(input_dir))} 张失败 {len(failed)} 张) if failed: print(失败文件:, failed)7.2 性能优化用多进程把100张压进一分钟OpenCV的inpaint计算量偏大单进程处理100张大图可能要几分钟。如果机器是多核CPU用多进程可以明显提速。from concurrent.futures import ProcessPoolExecutor def process_one(fname): in_path os.path.join(input_dir, fname) out_path os.path.join(output_dir, fname) try: remove_red_stamp_hsv(in_path, out_path) return fname, True except Exception as e: return fname, False with ProcessPoolExecutor(max_workers4) as executor: results list(executor.map(process_one, file_list))要注意ProcessPoolExecutor不能直接用在Jupyter Notebook的交互式环境里会出现EOFError脚本方式跑就没问题。OpenCV的imread/imwrite在多进程下会占用较多文件句柄控制好max_workers。7.3 嵌入OCR流程里的完整链路如果你做的是带OCR的文档管理系统去章这一步通常放在预处理链路的早期。我比较推荐的顺序是读入彩色图。去红章。转灰度。二值化。OCR识别。如果你先转灰度再去章颜色信息已经丢了颜色通道分离法就完全失效了。这是很多人把去章代码接进OCR流程时最容易犯的错误。8. 更进一步不局限于红章的拓展玩法8.1 改几个参数就能去蓝章/去绿章颜色通道分离法之所以值得学是因为它的思想可以迁移。蓝色印章的B通道显著高于R绿色印章的G通道显著高于R。只需要构造对应的差值通道或者调整HSV的H区间就能把红章算法变形成蓝章去除、绿章去除。HSV里蓝色的H在100到130绿色在35到77改一下inRange的参数一个去红章函数瞬间变成通用去章函数。8.2 配合轮廓检测做局部精修印章不一定是一个均匀的红色大块。有些情况下印章边缘是断断续续的环中间还残留手写签字。这时候用轮廓检测找到印章外接矩形只在矩形内部做修复矩形外保持原样效果更可控。contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) if contours: x, y, w, h cv2.boundingRect(contours[0]) roi_mask np.zeros_like(mask) roi_mask[y:yh, x:xw] mask[y:yh, x:xw] result cv2.inpaint(img, roi_mask, inpaint_radius, cv2.INPAINT_TELEA)如果你处理的合同扫描件里纸张上有大量底纹或水印这个局部化思路会非常有用。8.3 别忘了对比度增强这一点有些手机拍出来的合同照片印章红得发黑通过HSV的V通道能看到它的明度只有40多。这种图直接跑HSV会有一部分印章落在背景阈值之外。先用cv2.createCLAHE对亮度通道做一次对比度增强把暗红色的明度提上来再跑印章去除流程效果会好很多。lab cv2.cvtColor(img, cv2.COLOR_BGR2LAB) l, a, b cv2.split(lab) clahe cv2.createCLAHE(clipLimit3.0, tileGridSize(8, 8)) l clahe.apply(l) lab cv2.merge((l, a, b)) img_enhanced cv2.cvtColor(lab, cv2.COLOR_LAB2BGR)注意这一步本身也会让黑字变浓所以它不会拖累文字保留效果。我自己在跑这类项目时最大的体会是印章去除的难点从来不是“找不找得到红色”而是“怎么知道哪里是印章、哪里不是”。参数调优的核心就是不断问自己掩膜里多出来的那块是什么颜色少掉的那部分为什么没选中把这两个问题想清楚你会发现自己不只是会跑一个去章脚本而是真正理解图像分割的思路了。最后分享一个小技巧调参的时候不要在真实合同上反复试。找几张扫描件用图像处理工具先切成几个小块把不同参数的输出并排贴上对比找到最优组合之后再上全图。这样既省时间又不至于在重要文件上反复折腾。做法其实很简单想深入的话把HSV的阈值连接cv2.createTrackbar做成交互式调参窗口拖动滑块实时看掩膜效果调试效率会再翻一倍。
返回列表