基于OpenCV的古籍竖版文字分割与Python显示方案
一、竖版古籍文字处理的背景与挑战
古籍数字化是文化遗产保护的重要方向,而竖版排版古籍(如日文、中文古籍)因文字排列方向与现代横排文本不同,导致传统OCR技术难以直接应用。竖版文字的分割面临三大挑战:
- 文字方向识别:需准确判断文字是竖排还是横排;
- 字符粘连处理:古籍因年代久远可能存在墨迹晕染、纸张破损导致的字符粘连;
- 布局复杂性:竖排文本可能伴随行间注释、圈点符号等干扰元素。
以《论语》竖排古籍为例,其文字排列密度高,行间距小,传统基于投影法的分割方法易将竖排文字误判为横排连续区域。OpenCV的图像处理能力与Python的灵活性为解决此类问题提供了技术可能。
二、竖版文字分割的核心技术流程
1. 图像预处理:增强文字与背景对比度
古籍图像常存在光照不均、噪点干扰等问题,需通过以下步骤优化:
import cv2import numpy as npdef preprocess_image(img_path):# 读取图像并转为灰度图img = cv2.imread(img_path)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 自适应阈值二值化(处理光照不均)binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,cv2.THRESH_BINARY_INV, 11, 2)# 去噪(中值滤波)denoised = cv2.medianBlur(binary, 3)return denoised
关键点:自适应阈值比全局阈值更能适应古籍图像的光照变化,cv2.ADAPTIVE_THRESH_GAUSSIAN_C通过局部加权计算阈值,有效保留文字细节。
2. 竖排文字方向检测:基于霍夫变换的线条分析
通过检测图像中的垂直线条分布,可判断文字方向:
def detect_orientation(binary_img):# 边缘检测(Canny)edges = cv2.Canny(binary_img, 50, 150)# 霍夫直线检测(参数优化:阈值80,最小线长20,最大线间隙10)lines = cv2.HoughLinesP(edges, 1, np.pi/180, 80,minLineLength=20, maxLineGap=10)# 统计垂直线(角度接近90度)vertical_count = 0for line in lines:x1, y1, x2, y2 = line[0]angle = np.arctan2(y2-y1, x2-x1) * 180/np.piif 80 < abs(angle) < 100: # 接近垂直vertical_count += 1# 判断是否为竖排(垂直线占比超过60%)total_lines = len(lines) if lines is not None else 0return vertical_count / total_lines > 0.6 if total_lines > 0 else False
应用场景:若检测结果为竖排,后续处理需旋转图像或调整分割策略。例如,将图像顺时针旋转90度后,可复用横排文字分割算法。
3. 竖排文字分割:基于投影法的行切割
竖排文字的行切割需将图像旋转后按列投影:
def segment_vertical_text(binary_img):# 旋转图像(假设已检测为竖排)rows, cols = binary_img.shaperotated = cv2.rotate(binary_img, cv2.ROTATE_90_CLOCKWISE)# 列投影(统计每列的黑色像素数)projection = np.sum(rotated == 0, axis=0)# 寻找分割点(投影值低于阈值的列)threshold = np.mean(projection) * 0.3split_points = []start = 0for i in range(1, len(projection)):if projection[i] < threshold and projection[i-1] >= threshold:split_points.append(i)# 切割字符区域characters = []prev = 0for point in split_points:char = rotated[:, prev:point]characters.append(char)prev = pointreturn characters
优化方向:针对字符粘连问题,可结合形态学操作(如闭运算)连接断裂笔画,或使用连通域分析(cv2.connectedComponents)进一步细分。
三、Python显示竖排文字的两种方案
方案1:旋转图像后显示(简单但效率低)
def display_rotated(img_path):img = cv2.imread(img_path)# 旋转90度显示竖排rotated = cv2.rotate(img, cv2.ROTATE_90_CLOCKWISE)cv2.imshow("Vertical Text", rotated)cv2.waitKey(0)
适用场景:快速预览竖排效果,但无法直接处理文字识别。
方案2:逐字符显示并控制方向(推荐)
结合Pillow库实现更灵活的显示:
from PIL import Image, ImageDraw, ImageFontdef display_vertical_chars(characters, output_path="vertical_text.png"):# 假设characters为分割后的字符列表(需先转为PIL格式)max_height = max(char.shape[0] for char in characters)total_width = sum(char.shape[1] for char in characters)# 创建空白画布(白色背景)img = Image.new("RGB", (total_width, max_height), (255, 255, 255))draw = ImageDraw.Draw(img)# 加载字体(需指定竖排字体文件,如NotoSansCJKjp-Regular.otf)try:font = ImageFont.truetype("NotoSansCJKjp-Regular.otf", 24)except:font = ImageFont.load_default()# 逐字符绘制(从右到左)x_offset = 0for char in characters:# 将OpenCV格式转为PILchar_pil = Image.fromarray(255 - char) # 反色(OpenCV二值图为黑底白字)img.paste(char_pil, (x_offset, 0))x_offset += char.shape[1]img.save(output_path)img.show()
关键细节:需处理字体文件路径问题,建议使用支持竖排的CJK字体(如Noto Sans CJK)。若字体缺失,可先用默认字体显示,再提示用户下载。
四、实际应用中的优化建议
- 数据增强:对古籍图像进行旋转、缩放、噪点添加等操作,提升模型鲁棒性。
- 深度学习辅助:结合U-Net等分割网络,处理复杂粘连字符。
- 后处理规则:添加词典校验(如日文假名频率统计)修正分割错误。
五、总结与展望
本文提出的Python+OpenCV方案通过预处理、方向检测、投影分割和显示优化,实现了竖版古籍文字的有效处理。未来可探索将传统图像处理与深度学习结合,例如用CRNN模型直接识别竖排文字,进一步提升自动化水平。对于开发者而言,掌握此类技术不仅能解决古籍数字化痛点,还可迁移至其他竖排文本场景(如海报、手写笔记)。