如何使用Pytesseract和Python 3从复杂背景照片中提取文本?
嘿,我完全懂你现在的窘境——复杂背景的OCR可比单一底色的验证码难多了,尤其是你作为刚接触Python+CV+Tesseract的新手,试了一堆方法都没效果肯定头大。不过别慌!既然你提到所有字符的字体颜色是统一的,这就是咱们的突破口,接下来我给你一套针对性的解决方案,一步步来搞定域名和电话号码的提取:
第一步:利用颜色分割精准分离字符与背景
因为字符颜色是固定的,咱们可以直接通过颜色过滤把字符从杂乱背景里抠出来,这比通用的灰度二值化靠谱多了。这里推荐用HSV色彩空间(比RGB更抗光照干扰),步骤如下:
import cv2 import numpy as np # 读取目标图片 img = cv2.imread('your_photo.jpg') # 转成HSV色彩空间(OpenCV默认是BGR,所以要转) hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 重点:调整下面的HSV范围,匹配你的字符颜色 # 你可以用取色工具(比如Photoshop、在线取色器)获取字符的HSV值,然后上下浮动范围 lower_char_color = np.array([90, 50, 50]) # 示例:蓝色下限 upper_char_color = np.array([130, 255, 255]) # 示例:蓝色上限 # 生成颜色掩码:只保留符合颜色范围的区域 color_mask = cv2.inRange(hsv_img, lower_char_color, upper_char_color) # 把掩码和原图结合,只留下字符区域 char_only_img = cv2.bitwise_and(img, img, mask=color_mask) # 转灰度图,方便后续处理 gray_char = cv2.cvtColor(char_only_img, cv2.COLOR_BGR2GRAY) # 二值化:让字符变成纯黑/纯白,增强对比度 _, thresh_img = cv2.threshold(gray_char, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
第二步:用形态学操作清理干扰噪点
复杂背景下,颜色分割后可能会残留一些小噪点,或者字符有轻微断裂,咱们用开闭运算来修复:
# 创建结构元素:根据字符大小调整,比如3x3的矩形(字符大就用5x5) kernel = np.ones((3, 3), np.uint8) # 先腐蚀掉小噪点,再膨胀修复字符断裂(闭运算) cleaned_img = cv2.morphologyEx(thresh_img, cv2.MORPH_CLOSE, kernel)
第三步:文本区域裁剪(可选但能大幅提升识别率)
如果图片里的文本分散在不同位置,咱们可以用轮廓检测定位所有字符区域,然后合并裁剪成一个小图,让Tesseract聚焦在文本上:
# 查找所有轮廓 contours, _ = cv2.findContours(cleaned_img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # 过滤掉太小的轮廓(排除非字符的噪点) min_char_area = 50 # 根据你的字符大小调整,比如小字符设30,大字符设100 text_boxes = [] for cnt in contours: area = cv2.contourArea(cnt) if area > min_char_area: x, y, w, h = cv2.boundingRect(cnt) text_boxes.append((x, y, w, h)) # 合并所有文本区域成一个大框 if text_boxes: x_min = min([x for x, y, w, h in text_boxes]) y_min = min([y for x, y, w, h in text_boxes]) x_max = max([x + w for x, y, w, h in text_boxes]) y_max = max([y + h for x, y, w, h in text_boxes]) cropped_text_img = cleaned_img[y_min:y_max, x_min:x_max] else: cropped_text_img = cleaned_img
第四步:用Tesseract针对性识别+正则提取目标内容
咱们不需要识别所有文本,只需要域名和电话号码,所以给Tesseract加配置限制识别范围,再用正则表达式精准过滤:
import pytesseract import re # 如果你没把Tesseract加到环境变量,就指定路径 # pytesseract.pytesseract.tesseract_cmd = r'C:\Program Files\Tesseract-OCR\tesseract.exe' # 自定义配置:只识别字母、数字、点、横杠(刚好匹配域名和电话的字符) # --oem 3:使用默认OCR引擎;--psm 6:假设图片是单一文本块 custom_config = r'--oem 3 --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-' raw_text = pytesseract.image_to_string(cropped_text_img, config=custom_config) # 用正则提取域名(匹配xxx.com/xxx.net这类格式) domain_regex = r'\b(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,}\b' extracted_domains = re.findall(domain_regex, raw_text) # 用正则提取电话号码(匹配带区号、横杠、空格的常见格式) phone_regex = r'\b(?:\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b' extracted_phones = re.findall(phone_regex, raw_text) # 输出结果 print("提取到的域名:", extracted_domains) print("提取到的电话号码:", extracted_phones)
新手调试小技巧
- HSV范围调整:这是最关键的一步!如果掩码没把所有字符留住,就扩大HSV的上下限;如果背景残留太多,就缩小范围。你可以写个小脚本用滑动条实时调整,比手动试高效多了。
- 字符倾斜矫正:如果文本是倾斜的,先用霍夫变换检测直线角度,把图片旋转回水平,再进行后续处理。
- Tesseract参数调整:如果识别不准,试试换
psm参数(比如psm 3是自动分页,psm 4是假设单列文本),或者更新Tesseract的语言包。
慢慢来,先拿一张样本图把预处理参数调对,再逐步扩展到其他图片,肯定能搞定的!
内容的提问来源于stack exchange,提问作者Gauthier Buttez
相关产品推荐
相关产品推荐

