如何用OpenCV去除图像框线并保留文本?
去除图像框线同时保留文本的解决方案
问题背景
需要移除图像中的黑色框线、保留内部黑色文本,但当前使用drawContours的方案因框线与文本共享像素,导致部分字符被误删除。原图为白底黑框黑文本的图像,框线围绕多个文本区域;现有代码运行后,部分框线被标记,但文本边缘也被错误处理。
原实现代码
import cv2 def contour_height(contour): (x, y, w, h) = cv2.boundingRect(contour) return h image = cv2.imread("sample.png") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (9, 9), 0) # Applying threshold threshold = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1] edges = cv2.Canny(threshold, 50, 200) # Finding and sorting contours based on the contour area contours, hierarchy = cv2.findContours(edges, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key=contour_height, reverse = True) # Display cv2_imshow(cv2.drawContours(image, contours[:35], -1, (0, 255, 0), 2))
解决方案
方法一:形态学操作(针对规则框线)
利用形态学开运算,结合自定义横竖结构元素,针对性去除水平/垂直框线,避免误触文本:
import cv2 import numpy as np image = cv2.imread("sample.png") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 二值化得到黑底白字,方便后续处理 _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) # 构造水平结构元素,去除水平框线 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (40, 1)) remove_horizontal = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) cnts = cv2.findContours(remove_horizontal, 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) # 构造垂直结构元素,去除垂直框线 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 40)) remove_vertical = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, vertical_kernel, iterations=2) cnts = cv2.findContours(remove_vertical, 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) # 反转回白底黑字 result = cv2.bitwise_not(thresh) # 显示结果 cv2.imshow("Result", result) cv2.waitKey(0) cv2.destroyAllWindows()
方法二:精准轮廓筛选(区分框线与文本轮廓)
框线轮廓多为近似矩形的大轮廓,文本则是小而不规则的轮廓,通过轮廓面积、多边形边数筛选区分:
import cv2 import numpy as np image = cv2.imread("sample.png") gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (3, 3), 0) # 二值化 _, thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU) # 只提取最外层轮廓 contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 创建掩码,标记要去除的框线区域 mask = np.zeros_like(gray) for cnt in contours: area = cv2.contourArea(cnt) # 过滤过小的文本轮廓,只处理大轮廓 if area > 1000: # 轮廓近似为多边形 peri = cv2.arcLength(cnt, True) approx = cv2.approxPolyDP(cnt, 0.02 * peri, True) # 框线通常为4边形(矩形) if len(approx) == 4: cv2.drawContours(mask, [cnt], -1, 255, -1) # 从二值图中移除框线区域 result = cv2.bitwise_and(thresh, thresh, mask=cv2.bitwise_not(mask)) # 反转回白底黑字 result = cv2.bitwise_not(result) # 显示结果 cv2.imshow("Result", result) cv2.waitKey(0) cv2.destroyAllWindows()
说明
- 形态学操作适合规则水平/垂直框线,可调整结构元素的尺寸(如
(40,1)中的40)适配不同粗细的框线; - 轮廓筛选适合框线为矩形的场景,通过面积阈值和多边形边数可精准区分框线与文本;
- 若框线与文本粘连严重,可先执行一次小幅度膨胀操作,再分离轮廓后处理。
内容的提问来源于stack exchange,提问作者lisa
相关产品推荐
相关产品推荐

