Python图像处理问题:如何分割粘连的字符?

这种粘连的字符要怎么切呢?
没思路了,希望能给点建议.






Python图像处理问题:如何分割粘连的字符?


5 回复

宽度?


import cv2
import numpy as np
from skimage import morphology, measure
import matplotlib.pyplot as plt

def split_connected_chars(image_path):
    """
    分割粘连字符的主要函数
    参数:
        image_path: 输入图像路径
    返回:
        separated_chars: 分割后的字符列表
    """
    # 1. 读取图像并预处理
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    if img is None:
        raise ValueError("无法读取图像,请检查路径")
    
    # 二值化
    _, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    
    # 2. 形态学操作去除噪声
    kernel = np.ones((3,3), np.uint8)
    cleaned = cv2.morphologyEx(binary, cv2.MORPH_CLOSE, kernel)
    cleaned = cv2.morphologyEx(cleaned, cv2.MORPH_OPEN, kernel)
    
    # 3. 距离变换找分割点
    dist_transform = cv2.distanceTransform(cleaned, cv2.DIST_L2, 5)
    _, sure_fg = cv2.threshold(dist_transform, 0.5*dist_transform.max(), 255, 0)
    sure_fg = np.uint8(sure_fg)
    
    # 4. 分水岭算法分割
    unknown = cv2.subtract(cleaned, sure_fg)
    _, markers = cv2.connectedComponents(sure_fg)
    markers = markers + 1
    markers[unknown == 255] = 0
    
    # 应用分水岭
    markers = cv2.watershed(cv2.cvtColor(img, cv2.COLOR_GRAY2BGR), markers)
    
    # 5. 提取分割后的字符
    separated_chars = []
    for label in np.unique(markers):
        if label < 2:  # 跳过背景
            continue
        
        # 创建掩码
        mask = np.zeros_like(img, dtype=np.uint8)
        mask[markers == label] = 255
        
        # 找到边界框
        contours, _ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        if contours:
            x,y,w,h = cv2.boundingRect(contours[0])
            char_img = img[y:y+h, x:x+w]
            separated_chars.append(char_img)
    
    return separated_chars

def alternative_method(image_path):
    """
    备选方法:使用轮廓分析
    适用于简单粘连情况
    """
    img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
    _, binary = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)
    
    # 查找轮廓
    contours, _ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
    chars = []
    for contour in contours:
        # 获取边界框
        x,y,w,h = cv2.boundingRect(contour)
        
        # 根据宽高比判断是否需要分割
        aspect_ratio = w / h
        if aspect_ratio > 1.5:  # 可能是粘连字符
            # 尝试垂直投影分割
            vertical_projection = np.sum(binary[y:y+h, x:x+w], axis=0)
            gaps = np.where(vertical_projection < np.max(vertical_projection)*0.1)[0]
            
            if len(gaps) > 0:
                # 在间隙处分割
                split_points = [0] + list(gaps) + [w]
                for i in range(len(split_points)-1):
                    start = split_points[i]
                    end = split_points[i+1]
                    if end - start > 5:  # 最小宽度阈值
                        char = img[y:y+h, x+start:x+end]
                        chars.append(char)
            else:
                chars.append(img[y:y+h, x:x+w])
        else:
            chars.append(img[y:y+h, x:x+w])
    
    return chars

# 使用示例
if __name__ == "__main__":
    # 方法1:分水岭算法(适合复杂粘连)
    chars1 = split_connected_chars("your_image.png")
    
    # 方法2:轮廓分析(适合简单粘连)
    chars2 = alternative_method("your_image.png")
    
    # 显示结果
    fig, axes = plt.subplots(1, len(chars1), figsize=(12,4))
    for i, char in enumerate(chars1):
        axes[i].imshow(char, cmap='gray')
        axes[i].axis('off')
    plt.show()

核心思路:

  1. 预处理:二值化+形态学去噪
  2. 距离变换:找到字符中心区域
  3. 分水岭算法:基于地形模拟分割粘连区域
  4. 轮廓提取:获取分割后的独立字符

简单建议: 先试分水岭,简单粘连用轮廓分析就够了。

个人感觉,如果图片没有旋转的话,可以把字符宽度和 Y 方向黑色的像素点的个数同时作为判断标准,一般粘连处像素点的个数不会太多

根据 y 方向的像素判断,来分割字符,PIL 可以解决

可以试试水滴算法及各种改良版:
http://www.intjit.org/cms/journal/volume/12/4/124_5.pdf

回到顶部