OpenCV形态学开运算后填充签名图像缺口的方法
解决签名图像网格线去除后缺口问题的方案
核心思路
先精准定位所有网格线(水平+垂直)生成掩码,再通过图像修复或受限形态学操作填补缺口,避免直接闭运算导致的过度填充。
方案一:基于图像修复的精准修复(推荐)
利用cv2.inpaint根据周围像素智能填补网格线位置的缺口,不会破坏签名原有结构:
import cv2 import numpy as np # 1. 加载图像并预处理 image = cv2.imread('Downloads/image.png') gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 二值化(适配签名深色、网格线浅色的场景,INV后签名为白色) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # 2. 检测水平网格线 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1)) # 数值根据网格线间距调整 horizontal_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) # 3. 检测垂直网格线 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 40)) # 数值根据网格线间距调整 vertical_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # 4. 合并网格线掩码并优化 grid_mask = cv2.add(horizontal_lines, vertical_lines) grid_mask = cv2.dilate(grid_mask, None, iterations=1) # 轻微膨胀确保覆盖完整网格线 # 5. 图像修复+二次二值化 restored_gray = cv2.inpaint(gray, grid_mask, 3, cv2.INPAINT_TELEA) final_thresh = cv2.threshold(restored_gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # 保存结果 cv2.imwrite('Downloads/out.png', final_thresh)
关键细节
- 结构元素调整:
(40,1)和(1,40)的数值需匹配你的网格线间距,确保只检测网格线而非签名笔画。 - 修复算法选择:
cv2.INPAINT_TELEA适合细小线条修复,效果不佳时可替换为cv2.INPAINT_NS(基于Navier-Stokes方程)。 - 二次二值化:修复后的灰度图再次二值化,能消除修复带来的灰度过渡,保证签名边缘清晰。
方案二:受限形态学填充(针对缺口精准处理)
通过签名掩码限制闭运算的作用范围,仅填充签名内部缺口,避免影响背景区域:
import cv2 import numpy as np # 原代码处理网格线部分 image = cv2.imread('Downloads/image.png') gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY) thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1] # 去除水平线 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1)) detected_lines = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(detected_lines, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts = cnts[0] if len(cnts) == 2 else cnts[1] for c in cnts: cv2.drawContours(thresh, [c], -1, (0,0,0), 2) # 新增:精准填充缺口 # 提取签名轮廓 cnts_signature = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) cnts_signature = cnts_signature[0] if len(cnts_signature) == 2 else cnts_signature[1] # 创建签名掩码(仅保留签名区域) signature_mask = np.zeros_like(thresh) cv2.drawContours(signature_mask, cnts_signature, -1, 255, thickness=cv2.FILLED) # 仅在签名掩码内执行闭运算填充缺口 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3)) filled_thresh = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1) # 保留签名区域的填充结果 final_thresh = cv2.bitwise_and(filled_thresh, signature_mask) cv2.imwrite('Downloads/out.png', final_thresh)
内容的提问来源于stack exchange,提问作者anonR
相关产品推荐
相关产品推荐

