【OpenCV】手写字符分割

OpenCV 是一个开源的计算机视觉(Computer Vision)与机器学习软件库,提供了多种图像处理算法与接口。在 OCR 技术中,字符分割用于提取图像中的文字信息,可以应用于车牌识别、身份证识别、文档扫描等场景。本文主要记录如何使用 OpenCV 实现手写字符分割。

目录

[1 工作原理](#1 工作原理)

[1.1 图像预处理](#1.1 图像预处理)

[1.2 字符检测](#1.2 字符检测)

[1.3 字符提取](#1.3 字符提取)

[2 程序设计](#2 程序设计)


1 工作原理

手写字符分割的主要目标是将连续的手写文本图像进行分割,得到单字符的图像。这里考虑字符按照水平方向书写的情况,使用 OpenCV 实现手写字符分割,主要包括以下几个步骤:

1)图像预处理:将图像转化为二值图,并进行图像去噪,使字符更容易被识别;

2)字符检测:使用轮廓检测函数,识别可能包含字符的区域;

3)字符提取:找到所有字符区域之后,从每个字符区域中提取字符。

1.1 图像预处理

在手写字符分割中,图像预处理过程包括:灰度图转换、二值化和中值滤波。其中,灰度图转换和二值化处理,使字符与背景区域之间的对比度更大,便于寻找可能的字符区域;中值滤波用于去除图像中的噪点。

使用 cv2.cvtColor() 和 cv2.threshold() 函数实现图像灰度图转换与二值化。

python 复制代码
# 灰度图转换
gray = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY)

# 二值化
_, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)

使用 cv2.medianBlur() 函数实现中值滤波。

python 复制代码
# 中值滤波
filter_size = 3
binary_f = cv2.medianBlur(binary, filter_size)

1.2 字符检测

图像预处理完成后,就可以使用 cv2.findContours() 函数检测图像的轮廓信息,进一步寻找字符区域。

python 复制代码
# 查找字符区域
contours, _ = cv2.findContours(binary_f, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

cv2.findContours() 函数会返回多个轮廓信息,考虑到一些特殊字符(例如 %,÷),这些字符存在多个不连接的部分,因此需要合并位置接近的轮廓,得到字符整体区域。

首先遍历所有的轮廓区域,获取最大宽度。然后计算每个区域的中点位置,若两个区域的中点位置距离小于最大宽度的一半,则拼接这两个区域。

python 复制代码
# 遍历所有区域,寻找最大宽度
w_max = 0
for cnt in contours:
   _, _, w, _ = cv2.boundingRect(cnt)
   if w > w_max:
      w_max = w

# 遍历所有区域,拼接x坐标接近的区域
char_dict = {}
for cnt in contours:
   x, y, w, h = cv2.boundingRect(cnt)
   x_mid = x + w//2 # 计算中点位置

   if not char_dict.keys() or all(np.abs(z - x_mid) > w_max//2 for z in char_dict.keys()):
      char_dict[x_mid] = cnt
   else:
      for z in char_dict.keys():
         if np.abs(z - x_mid) <= w_max//2:
            char_dict[z] = np.concatenate((char_dict[z], cnt), axis=0) # 拼接两个区域

1.3 字符提取

字符区域查找完成之后,遍历所有字符区域,使用 cv2.boundingRect() 函数获取端点位置和宽高信息,就可以提取字符了。

python 复制代码
# 遍历所有区域,提取字符
dst_img = []
for _, cnt in char_dict.items():
   x, y, w, h = cv2.boundingRect(cnt)
   roi = binary[y:y+h, x:x+w]
   dst_img.append(roi)

2 程序设计

使用 Gradio 实现交互式界面,中值滤波大小可选 3 × 3, 5 × 5 或 7 × 7。以下是 Python 实现代码:

python 复制代码
#-*- Coding: utf-8 -*-

import cv2
import numpy as np
import gradio as gr

def charSeperate(src_img, filter_size):
   """函数功能:字符分割
      @param src_img
      @param filter_size
      @return dst_img"""
   
   # 灰度图
   gray = cv2.cvtColor(src_img, cv2.COLOR_BGR2GRAY)
   
   # 二值化
   _, binary = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY)
   binary_inv = cv2.bitwise_not(binary)

   # 中值滤波
   filter_size = int(filter_size[0][0]) if filter_size else 3
   binary_f = cv2.medianBlur(binary_inv, filter_size)

   # 查找字符区域
   contours, _ = cv2.findContours(binary_f, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

   # 遍历所有区域,寻找最大宽度
   w_max = 0
   for cnt in contours:
      _, _, w, _ = cv2.boundingRect(cnt)
      if w > w_max:
         w_max = w

   # 遍历所有区域,拼接x坐标接近的区域
   char_dict = {}
   for cnt in contours:
      x, y, w, h = cv2.boundingRect(cnt)
      x_mid = x + w//2 # 计算中点位置

      if not char_dict.keys() or all(np.abs(z - x_mid) > w_max//2 for z in char_dict.keys()):
         char_dict[x_mid] = cnt
      else:
         for z in char_dict.keys():
            if np.abs(z - x_mid) <= w_max//2:
               char_dict[z] = np.concatenate((char_dict[z], cnt), axis=0) # 拼接两个区域

   # 按照中点坐标,对字符进行排序
   char_dict = dict(sorted(char_dict.items(), key=lambda item: item[0]))

   # 遍历所有区域,提取字符
   dst_img = []
   for _, cnt in char_dict.items():
      x, y, w, h = cv2.boundingRect(cnt)
      roi = binary[y:y+h, x:x+w]
      dst_img.append(roi)

   return dst_img

if __name__ == "__main__":
   demo = gr.Interface(
      fn=charSeperate,
      inputs=[
         gr.Image(label="input image"), 
         gr.Radio(['3x3', '5x5', '7x7'], value='3x3')
      ],
      outputs=[
         gr.Gallery(label="charset", columns=[3], object_fit="contain", height="auto")
      ],
      live=True
   )

   demo.launch()

以下是代码运行效果:

相关推荐
糖葫芦君12 分钟前
基于树结构突破大模型自身能力
人工智能·深度学习·大模型
诗句藏于尽头13 分钟前
MediaPipe+OpenCV的python实现交互式贪吃蛇小游戏
人工智能·python·opencv
汽车仪器仪表相关领域14 分钟前
汽车排放检测的 “模块化核心”:HORIBA OBS-ONE GS Unit 气体分析单元技术解析
大数据·人工智能·功能测试·车载系统·汽车·安全性测试·汽车检测
恒点虚拟仿真28 分钟前
“AI+XR”赋能智慧研创中心:告别AI焦虑,重塑教师未来
人工智能·xr·虚拟仿真·虚拟仿真教学·xr研创中心·数字教师·未来教师
2501_9389312539 分钟前
解构AI营销获客工具的四大智能中枢与价值逻辑
人工智能·机器学习·自动驾驶
Liquad Li1 小时前
汽车配件 AI 系统:重构汽车配件管理与多语言内容生成新范式
人工智能
音视频牛哥1 小时前
从云平台到系统内核:SmartMediakit如何重构实时视频系统
计算机视觉·音视频·gb28181对接·rtsp播放器rtmp播放器·smartmediakit·智能机器人低延迟播放方案·rtmp摄像头同屏推流
小白狮ww1 小时前
VASP 教程:使用 VASP 进行机器学习力场训练
人工智能·深度学习·机器学习·大模型·分子动力学·计算机程序·vasp
ayingmeizi1631 小时前
重构增长:生成式AI如何将CRM打造为企业的销售大脑
人工智能·重构
TG:@yunlaoda360 云老大1 小时前
火山引擎数智平台VeDI重磅发布“AI助手”:以大模型驱动数据飞轮,赋能非技术人员高效“看数、用数”
人工智能·信息可视化·火山引擎