我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python中opencv实现文字分割的实践

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python中opencv实现文字分割的实践

图片文字分割的时候,常用的方法有两种。一种是投影法,适用于排版工整,字间距行间距比较宽裕的图像;还有一种是用OpenCV的轮廓检测,适用于文字不规则排列的图像。

投影法

对文字图片作横向和纵向投影,即通过统计出每一行像素个数,和每一列像素个数,来分割文字。
分别在水平和垂直方向对预处理(二值化)的图像某一种像素进行统计,对于二值化图像非黑即白,我们通过对其中的白点或者黑点进行统计,根据统计结果就可以判断出每一行的上下边界以及每一列的左右边界,从而实现分割的目的。

算法步骤:

  • 使用水平投影和垂直投影的方式进行图像分割,根据投影的区域大小尺寸分割每行和每块的区域,对原始图像进行二值化处理。
  • 投影之前进行图像灰度学调整做膨胀操作
  • 分别进行水平投影和垂直投影
  • 根据投影的长度和高度求取完整行和块信息

横板文字-小票文字分割


#小票水平分割
import cv2
import numpy as np

img = cv2.imread(r"C:\Users\An\Pictures\1.jpg")
cv2.imshow("Orig Image", img)
# 输出图像尺寸和通道信息
sp = img.shape
print("图像信息:", sp)
sz1 = sp[0]  # height(rows) of image
sz2 = sp[1]  # width(columns) of image
sz3 = sp[2]  # the pixels value is made up of three primary colors
print('width: %d \n height: %d \n number: %d' % (sz2, sz1, sz3))
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshold_img = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("threshold_img", threshold_img)

# 水平投影分割图像
gray_value_x = []
for i in range(sz1):
    white_value = 0
    for j in range(sz2):
        if threshold_img[i, j] == 255:
            white_value += 1
    gray_value_x.append(white_value)
print("", gray_value_x)
# 创建图像显示水平投影分割图像结果
hori_projection_img = np.zeros((sp[0], sp[1], 1), np.uint8)
for i in range(sz1):
    for j in range(gray_value_x[i]):
        hori_projection_img[i, j] = 255
cv2.imshow("hori_projection_img", hori_projection_img)
text_rect = []
# 根据水平投影分割识别行
inline_x = 0
start_x = 0
text_rect_x = []
for i in range(len(gray_value_x)):
    if inline_x == 0 and gray_value_x[i] > 10:
        inline_x = 1
        start_x = i
    elif inline_x == 1 and gray_value_x[i] < 10 and (i - start_x) > 5:
        inline_x = 0
        if i - start_x > 10:
            rect = [start_x - 1, i + 1]
            text_rect_x.append(rect)
print("分行区域,每行数据起始位置Y:", text_rect_x)
# 每行数据分段
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 3))
dilate_img = cv2.dilate(threshold_img, kernel)
cv2.imshow("dilate_img", dilate_img)
for rect in text_rect_x:
    cropImg = dilate_img[rect[0]:rect[1],0:sp[1]]  # 裁剪图像y-start:y-end,x-start:x-end
    sp_y = cropImg.shape
    # 垂直投影分割图像
    gray_value_y = []
    for i in range(sp_y[1]):
        white_value = 0
        for j in range(sp_y[0]):
            if cropImg[j, i] == 255:
                white_value += 1
        gray_value_y.append(white_value)
    # 创建图像显示水平投影分割图像结果
    veri_projection_img = np.zeros((sp_y[0], sp_y[1], 1), np.uint8)
    for i in range(sp_y[1]):
        for j in range(gray_value_y[i]):
            veri_projection_img[j, i] = 255
    cv2.imshow("veri_projection_img", veri_projection_img)
    # 根据垂直投影分割识别行
    inline_y = 0
    start_y = 0
    text_rect_y = []
    for i in range(len(gray_value_y)):
        if inline_y == 0 and gray_value_y[i] > 2:
            inline_y = 1
            start_y = i
        elif inline_y == 1 and gray_value_y[i] < 2 and (i - start_y) > 5:
            inline_y = 0
            if i - start_y > 10:
                rect_y = [start_y - 1, i + 1]
                text_rect_y.append(rect_y)
                text_rect.append([rect[0], rect[1], start_y - 1, i + 1])
                cropImg_rect = threshold_img[rect[0]:rect[1], start_y - 1:i + 1]  # 裁剪图像
                cv2.imshow("cropImg_rect", cropImg_rect)
                # cv2.imwrite("C:/Users/ThinkPad/Desktop/cropImg_rect.jpg",cropImg_rect)
                # break
        # break
# 在原图上绘制截图矩形区域
print("截取矩形区域(y-start:y-end,x-start:x-end):", text_rect)
rectangle_img = cv2.rectangle(img, (text_rect[0][2], text_rect[0][0]), (text_rect[0][3], text_rect[0][1]),
                              (255, 0, 0), thickness=1)
for rect_roi in text_rect:
    rectangle_img = cv2.rectangle(img, (rect_roi[2], rect_roi[0]), (rect_roi[3], rect_roi[1]), (255, 0, 0), thickness=1)
cv2.imshow("Rectangle Image", rectangle_img)

key = cv2.waitKey(0)
if key == 27:
    print(key)
    cv2.destroyAllWindows()

小票图像二值化结果如下:

在这里插入图片描述

小票图像结果分割如下:

在这里插入图片描述

竖版-古文文字分割

对于古籍来说,古籍文字书写在习惯是从上到下的,所以说在扫描的时候应该扫描列投影,在扫描行投影。

1.原始图像进行二值化

使用水平投影和垂直投影的方式进行图像分割,根据投影的区域大小尺寸分割每行和每块的区域,对原始图像进行二值化处理。

原始图像:

在这里插入图片描述

二值化后的图像:

在这里插入图片描述

2.图像膨胀

投影之前进行图像灰度学调整做膨胀操作,选取适当的核,对图像进行膨胀处理。

在这里插入图片描述

3.垂直投影

定位该行文字区域:
数值不为0的区域就是文字存在的地方(即二值化后白色部分的区域),为0的区域就是每行之间相隔的距离。
1、如果前一个数为0,则记录第一个不为0的坐标。
2、如果前一个数不为0,则记录第一个为0的坐标。形象的说就是从出现第一个非空白列到出现第一个空白列这段区域就是文字存在的区域。
通过以上规则就可以找出每一列文字的起始点和终止点,从而确定每一列的位置信息。

垂直投影结果:

在这里插入图片描述

通过上面的垂直投影,根据其白色小山峰的起始位置就可以界定出每一列的起始位置,从而把每一列分割出来。

4.水平投影

根据投影的长度和高度求取完整行和块信息
通过水平投影可以获得每一个字符左右的起始位置,这样也就可以获得到每一个字符的具体坐标位置,即一个矩形框的位置。


import cv2
import numpy as np
import os

img = cv2.imread(r"C:\Users\An\Pictures\3.jpg")
save_path=r"E:\crop_img\result" #图像分解的每一步保存的地址
crop_path=r"E:\crop_img\img" #图像切割保存的地址
cv2.imshow("Orig Image", img)
# 输出图像尺寸和通道信息
sp = img.shape
print("图像信息:", sp)
sz1 = sp[0]  # height(rows) of image
sz2 = sp[1]  # width(columns) of image
sz3 = sp[2]  # the pixels value is made up of three primary colors
print('width: %d \n height: %d \n number: %d' % (sz2, sz1, sz3))
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
retval, threshold_img = cv2.threshold(gray_img, 120, 255, cv2.THRESH_BINARY_INV)
cv2.imshow("threshold_img", threshold_img)
cv2.imwrite(os.path.join(save_path,"threshold_img.jpg"),threshold_img)

# 垂直投影分割图像
gray_value_y = []
for i in range(sz2):
    white_value = 0
    for j in range(sz1):
        if threshold_img[j, i] == 255:
            white_value += 1
    gray_value_y.append(white_value)
print("", gray_value_y)
#创建图像显示垂直投影分割图像结果
veri_projection_img = np.zeros((sp[0], sp[1], 1), np.uint8)
for i in range(sz2):
    for j in range(gray_value_y[i]):
        veri_projection_img[j, i] = 255
cv2.imshow("veri_projection_img", veri_projection_img)
cv2.imwrite(os.path.join(save_path,"veri_projection_img.jpg"),veri_projection_img)
text_rect = []


# 根据垂直投影分割识别列
inline_y = 0
start_y = 0
text_rect_y = []
for i in range(len(gray_value_y)):
    if inline_y == 0 and gray_value_y[i]> 30:
        inline_y = 1
        start_y = i
    elif inline_y == 1 and gray_value_y[i] < 30 and (i - start_y) > 5:
        inline_y = 0
        if i - start_y > 10:
            rect = [start_y - 1, i + 1]
            text_rect_y.append(rect)
print("分列区域,每列数据起始位置Y:", text_rect_y)
# 每列数据分段
# kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (13, 3))
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
dilate_img = cv2.dilate(threshold_img, kernel)
cv2.imshow("dilate_img", dilate_img)
cv2.imwrite(os.path.join(save_path,"dilate_img.jpg"),dilate_img)
for rect in text_rect_y:
    cropImg = dilate_img[0:sp[0],rect[0]:rect[1]]  # 裁剪图像y-start:y-end,x-start:x-end
    sp_x = cropImg.shape
    # 垂直投影分割图像
    gray_value_x = []
    for i in range(sp_x[0]):
        white_value = 0
        for j in range(sp_x[1]):
            if cropImg[i, j] == 255:
                white_value += 1
        gray_value_x.append(white_value)
    # 创建图像显示水平投影分割图像结果
    hori_projection_img = np.zeros((sp_x[0], sp_x[1], 1), np.uint8)
    for i in range(sp_x[0]):
        for j in range(gray_value_x[i]):
            veri_projection_img[i, j] = 255
    # cv2.imshow("hori_projection_img", hori_projection_img)
    # 根据水平投影分割识别行
    inline_x = 0
    start_x = 0
    text_rect_x = []
    ind=0
    for i in range(len(gray_value_x)):
        ind+=1
        if inline_x == 0 and gray_value_x[i] > 2:
            inline_x = 1
            start_x = i
        elif inline_x == 1 and gray_value_x[i] < 2 and (i - start_x) > 5:
            inline_x = 0
            if i - start_x > 10:
                rect_x = [start_x - 1, i + 1]
                text_rect_x.append(rect_x)
                text_rect.append([start_x - 1, i + 1,rect[0], rect[1]])
                cropImg_rect = threshold_img[start_x - 1:i + 1,rect[0]:rect[1]]  # 裁剪二值化图像
                crop_img=img[start_x - 1:i + 1,rect[0]:rect[1]] #裁剪原图像
                # cv2.imshow("cropImg_rect", cropImg_rect)
                # cv2.imwrite(os.path.join(crop_path,str(ind)+".jpg"),crop_img)
                # break
        # break
# 在原图上绘制截图矩形区域
print("截取矩形区域(y-start:y-end,x-start:x-end):", text_rect)
rectangle_img = cv2.rectangle(img, (text_rect[0][2], text_rect[0][0]), (text_rect[0][3], text_rect[0][1]),
                              (255, 0, 0), thickness=1)
for rect_roi in text_rect:
    rectangle_img = cv2.rectangle(img, (rect_roi[2], rect_roi[0]), (rect_roi[3], rect_roi[1]), (255, 0, 0), thickness=1)
cv2.imshow("Rectangle Image", rectangle_img)
cv2.imwrite(os.path.join(save_path,"rectangle_img.jpg"),rectangle_img)
key = cv2.waitKey(0)
if key == 27:
    print(key)
    cv2.destroyAllWindows()

分割结果如下:

在这里插入图片描述

从分割的结果上看,基本上实现了图片中文字的分割。但由于中文结构复杂性,对于一些文字的分割并不理想,字会出现过度分割、有粘连的两个字会出现分割不够的现象。可以从图像预处理(图像腐蚀膨胀),边界判断阈值的调整等方面进行优化。

到此这篇关于python中opencv实现文字分割的实践的文章就介绍到这了,更多相关opencv 文字分割内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python中opencv实现文字分割的实践

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python+opencv实现阈值分割

使用Python和OpenCV可以很容易地实现阈值分割。下面是一个简单的示例代码:```pythonimport cv2# 读取图像image = cv2.imread('image.jpg', 0)# 二值化阈值分割_, binary_i
2023-08-14

Python+OpenCV怎么实现阈值分割

这篇文章主要介绍“Python+OpenCV怎么实现阈值分割”,在日常操作中,相信很多人在Python+OpenCV怎么实现阈值分割问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”Python+OpenCV怎么
2023-06-30

python中怎么使用opencv实现阈值分割

在Python中使用OpenCV实现阈值分割可以按照以下步骤进行:1. 导入OpenCV库:```pythonimport cv2```2. 读取图像:```pythonimg = cv2.imread('image.jpg', 0) #
2023-08-15

python+opencv图像分割如何实现分割不规则ROI区域

这篇文章将为大家详细讲解有关python+opencv图像分割如何实现分割不规则ROI区域,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。python有哪些常用库python常用的库:1.requesuts
2023-06-14

Python OpenCV基于HSV的颜色分割如何实现

本文小编为大家详细介绍“Python OpenCV基于HSV的颜色分割如何实现”,内容详细,步骤清晰,细节处理妥当,希望这篇“Python OpenCV基于HSV的颜色分割如何实现”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来
2023-07-02

OpenCV中图像如何实现分割与修复

这篇文章给大家分享的是有关OpenCV中图像如何实现分割与修复的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。背景图像分割本质就是将前景目标从背景中分离出来。在当前的实际项目中,应用传统分割的并不多,大多是采用深度
2023-06-29

python与php实现分割文件代码

前两天有个朋友说,想实现一个文本文件按照固定行数进行分割成多个文本文件,却不知如何实现。如果数据量小手动分割下就好了,如果数据量很大的话手动完成实在太耗费人力了,也不现实。那么就需要借助脚本去实现。既然有朋友想简单的完成这个任务,那么不如记
2022-06-04

C++中怎么实现OpenCV图像分割与分水岭算法

小编给大家分享一下C++中怎么实现OpenCV图像分割与分水岭算法,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!分水岭算法是一种图像区域分割法,在分割的过程中,它
2023-06-15

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录