Python实现噪声平面图线条降噪与实体化的技术求助
噪声平面图的线条降噪与实体化优化方案
问题背景
对噪声严重的平面图进行线条降噪及实体化处理,已尝试masking、bluring、HoughLinesP及前两者的组合方法。使用HoughLinesP可实现线条实体化,但文字区域线条严重重叠,且调整minLineLength、maxLineGap参数无法解决该问题。
原始处理代码
import cv2 import numpy as np from tkinter import Tk # from tkinter import Tk for Python 3.x from tkinter.filedialog import askopenfilename import os Tk().withdraw() # 隐藏TK主窗口 filename = askopenfilename() # 打开文件选择对话框 print(filename) filename3, file_extension = os.path.splitext(filename) # 读取灰度图 img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) # 初始化彩色输出图 out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 中值模糊降噪并反转图像 img = 255 - cv2.medianBlur(img, 3) # 检测并绘制线条 lines = cv2.HoughLinesP(img, 1, np.pi/180, 10, minLineLength=40, maxLineGap=30) for line in lines: for x1, y1, x2, y2 in line: cv2.line(out, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow('out', out) cv2.imwrite(filename3+' '+'69'+'.png', out) cv2.waitKey(0) cv2.destroyAllWindows()
问题分析
文字区域的线条重叠本质是文字笔画被HoughLinesP误识别为线条,由于文字笔画短且密集,单纯调整长度或间隙参数会陷入“过滤文字则丢失有效短线条”的矛盾,需从预处理阶段分离文字与线条,或采用更精准的线条检测逻辑。
解决方案
方案1:形态学操作过滤文字区域
利用文字与线条的形态差异(线条为长条形,文字为小区域密集笔画),通过长条形核的开运算过滤文字,保留目标线条:
import cv2 import numpy as np from tkinter import Tk from tkinter.filedialog import askopenfilename import os Tk().withdraw() filename = askopenfilename() print(filename) filename3, file_extension = os.path.splitext(filename) # 读取灰度图并初始化输出 img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 反转图像(背景黑,线条白) img_inv = 255 - img # 用水平长核开运算,过滤文字保留水平线条 horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 1)) img_horizontal = cv2.morphologyEx(img_inv, cv2.MORPH_OPEN, horizontal_kernel, iterations=2) # 用垂直长核开运算,保留垂直线条 vertical_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 30)) img_vertical = cv2.morphologyEx(img_inv, cv2.MORPH_OPEN, vertical_kernel, iterations=2) # 合并水平与垂直线条 img_lines = cv2.addWeighted(img_horizontal, 0.5, img_vertical, 0.5, 0) # 降噪后检测线条 img_blur = cv2.medianBlur(img_lines, 3) lines = cv2.HoughLinesP(img_blur, 1, np.pi/180, threshold=20, minLineLength=40, maxLineGap=30) if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] cv2.line(out, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow('Processed Lines', out) cv2.imwrite(filename3+'_processed.png', out) cv2.waitKey(0) cv2.destroyAllWindows()
方案2:轮廓筛选替代HoughLinesP
通过Canny边缘检测提取轮廓,筛选长条形轮廓(线条),过滤小面积轮廓(文字):
import cv2 import numpy as np from tkinter import Tk from tkinter.filedialog import askopenfilename import os Tk().withdraw() filename = askopenfilename() print(filename) filename3, file_extension = os.path.splitext(filename) img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 降噪+Canny边缘检测 img_blur = cv2.GaussianBlur(img, (5,5), 0) edges = cv2.Canny(img_blur, 50, 150) # 提取轮廓并筛选长条形线条 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) for cnt in contours: x, y, w, h = cv2.boundingRect(cnt) # 计算长宽比,保留长线条(可根据图像调整阈值) aspect_ratio = max(w, h) / min(w, h) if min(w, h) !=0 else 0 if aspect_ratio > 10 and (w > 30 or h > 30): cv2.rectangle(out, (x,y), (x+w, y+h), (0,0,255), 2) cv2.imshow('Contour-based Lines', out) cv2.imwrite(filename3+'_contour.png', out) cv2.waitKey(0) cv2.destroyAllWindows()
方案3:文字检测屏蔽区域
用OCR工具检测文字区域,在HoughLinesP检测时屏蔽这些区域(需安装pytesseract及Tesseract引擎):
import cv2 import numpy as np import pytesseract from tkinter import Tk from tkinter.filedialog import askopenfilename import os # 配置Tesseract路径(根据实际安装路径调整) pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' Tk().withdraw() filename = askopenfilename() print(filename) filename3, file_extension = os.path.splitext(filename) img = cv2.imread(filename, cv2.IMREAD_GRAYSCALE) out = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 检测高置信度文字区域,生成掩码 d = pytesseract.image_to_data(img, output_type=pytesseract.Output.DICT) mask = np.ones_like(img, dtype=np.uint8) * 255 n_boxes = len(d['text']) for i in range(n_boxes): if int(d['conf'][i]) > 60: x, y, w, h = d['left'][i], d['top'][i], d['width'][i], d['height'][i] cv2.rectangle(mask, (x, y), (x+w, y+h), 0, -1) # 应用掩码去除文字区域 img_no_text = cv2.bitwise_and(img, mask) # 后续线条检测流程 img_inv = 255 - cv2.medianBlur(img_no_text, 3) lines = cv2.HoughLinesP(img_inv, 1, np.pi/180, 10, minLineLength=40, maxLineGap=30) if lines is not None: for line in lines: x1, y1, x2, y2 = line[0] cv2.line(out, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.imshow('No Text Lines', out) cv2.imwrite(filename3+'_no_text.png', out) cv2.waitKey(0) cv2.destroyAllWindows()
方案选型建议
- 形态学操作方案:无额外依赖,适合文字与线条形态差异明显的场景;
- 轮廓筛选方案:自定义性强,可灵活调整轮廓特征过滤无效区域;
- 文字检测方案:适合文字复杂但需精准屏蔽的场景,需额外安装OCR工具。
内容的提问来源于stack exchange,提问作者Luke-McDevitt
相关产品推荐
相关产品推荐

