当前位置: 首页 > news >正文

【OpenCV实现图像:OpenCV进行OCR字符分割】

文章目录

    • 概要
    • 基本概念
    • 读入图像
    • 图像二值化
    • 小结

概要

在处理OCR(Optical Character Recognition,光学字符识别)时,利用传统的图像处理方法进行字符切分仍然是一种有效的途径。即便当前计算机视觉领域主导的是卷积神经网络,但对于一些相对简单的实际应用场景,传统方法仍然表现出良好的效果。

在OCR任务中,字符切分是一个关键的步骤,它能够将整个文本图像分割成单个字符,为后续的处理任务提供基础。传统图像处理方法可以通过一系列技术来实现字符的准确切分。这些技术可能包括但不限于:

边缘检测: 使用算子(如Sobel、Canny)检测图像中字符的边缘,从而确定字符的边界。连通区域分析: 通过标记和分析图像中的连通区域,可以识别字符的位置和形状。投影法: 水平和垂直投影可以帮助检测字符之间的间隔,从而进行字符切分。轮廓分析: 提取字符的轮廓信息,进而判断字符的位置和形状。形态学操作: 使用腐蚀、膨胀等形态学操作来调整字符的形状,以便更好地进行切分。

虽然卷积神经网络在图像处理任务中表现出色,但在一些简单的场景中,传统方法的实用性仍然很大。例如,在文档扫描、数字识别等任务中,通过合理运用传统图像处理技术,可以快速、准确地完成字符切分,为后续的OCR处理奠定基础。这种混合使用传统方法和深度学习技术的方式,可以充分发挥各自的优势,实现更全面、高效的图像处理任务。

基本概念

OCR(Optical Character Recognition):全称光学字符识别,是一项技术,通过使用光学和图像处理技术,将图像中的文字转换为可编辑的文本。

Segmentation:在图像处理领域,分割是指将整个图像分解为多个子部分的过程,以便进行进一步的处理。

OCR Segmentation:是指在光学字符识别过程中,将包含文本的图像分解成多个小部分的操作。这旨在有效地识别图像中的文字,并将其从背景中分离出来,以便后续的OCR处理。通过分割,系统可以更准确地定位和识别每个字符,提高整体识别准确性。

读入图像

读入图像:

一旦获得了包含文本的数字图像,或者通过扫描仪将某些文档转换为数字图像进行存储,就可以迈入下一步,即预处理。在这个阶段,可以使用以下代码来读入图像,以便进行后续的处理。

import cv2# 读入图像
myImage = cv2.imread('12.png')# 显示图像
cv2.imshow('Text Image', myImage)
cv2.waitKey(0)

在这里插入图片描述

图像二值化

在开始分割文本图像之前,需要经过一系列预处理步骤,其中之一是图像的二值化。这个过程包括以下步骤:

灰度化: 首先,将输入图像转换为灰度图像。这一步的目的是简化图像,使系统能够更轻松地识别图像中的不同形状,同时去除颜色信息,从而减少处理的复杂性。这通常通过将图像中的每个像素的彩色信息转化为相应的灰度值来实现。

import cv2# 读入图像
myImage = cv2.imread('12.png')# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)# 二值化
_, binaryImage = cv2.threshold(grayImage, 128, 255, cv2.THRESH_BINARY)# 显示图像
cv2.imshow('Binary Image', grayImage)
cv2.waitKey(0)

在这里插入图片描述

二值化: 一旦图像变为灰度图,接下来的关键步骤是将其二值化。这意味着将图像中的像素值转换为两个可能的值之一,通常是0和255。这样的二值图像使得文字与背景更为明显,为后续的字符切分和识别提供了更好的基础。

这个可以根据自己的修改,转换颜色。

_, binaryImage = cv2.threshold(grayImage, 128, 255, cv2.THRESH_BINARY)
import cv2
# 读入图像
myImage = cv2.imread('12.png')
# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)
# 二值化
_, binaryImage = cv2.threshold(grayImage, 128, 255, cv2.THRESH_BINARY)
# 显示图像
cv2.imshow('Binary Image', binaryImage)
cv2.waitKey(0)

在这里插入图片描述

import cv2# 读入图像
myImage = cv2.imread('12.png')# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)# 二值化
ret, thresh = cv2.threshold(grayImage, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
# 形态学操作
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 18))
dilation = cv2.dilate(thresh, horizontal_kernel, iterations=1)# 显示图像
cv2.imshow('Dilated Image', thresh)
cv2.waitKey(0)

在这里插入图片描述

接着可以选择并使用多种算法从上述二值图像中提取信息,例如直方图均衡、傅立叶变换、形态学等。
形态学操作

import cv2# 读入图像
myImage = cv2.imread('12.png')# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)# 二值化
ret, thresh = cv2.threshold(grayImage, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)
# 形态学操作
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 18))
dilation = cv2.dilate(thresh, horizontal_kernel, iterations=1)# 显示图像
cv2.imshow('Dilated Image', dilation)
cv2.waitKey(0)

在这里插入图片描述

查找轮廓
接着需要找到轮廓线,这样才能将图像与背景逐行分离。
为了清楚,换红色线条标注,可以修改这段代码更换颜色

    rect = cv2.rectangle(myImage, (x, y), (x + w, y + h), (0, 0, 255), 1)  # 红色矩形
import cv2# 读入图像
myImage = cv2.imread('12.png')# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)# 二值化
ret, thresh = cv2.threshold(grayImage, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)# 形态学操作
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 18))
dilation = cv2.dilate(thresh, horizontal_kernel, iterations=1)# 查找轮廓
horizontal_contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)# 在原始图像上绘制红色矩形
for cnt in horizontal_contours:x, y, w, h = cv2.boundingRect(cnt)rect = cv2.rectangle(myImage, (x, y), (x + w, y + h), (0, 0, 255), 1)  # 红色矩形# 显示图像
cv2.imshow('Image with Red Rectangles', myImage)
cv2.waitKey(0)

在这里插入图片描述
单词和字符分割

接着我们通过以下步骤对裁剪出的轮廓子图进行单词分割:

1-预处理(灰度、阈值)

2-形态学算法

3-找到边界并绘制它们

4-进入单个字符分割

进而我们将对输出图像中的每个单词再次重复相同的步骤进行单个字符的分割:

1-预处理(灰度、阈值)

2-形态学算法

3-找到边界并绘制它们

4-停止

最终我们得到的结果如下。
代码:

import cv2# 读入图像
myImage = cv2.imread('12.png')# 灰度化
grayImage = cv2.cvtColor(myImage, cv2.COLOR_BGR2GRAY)# 二值化
ret, thresh = cv2.threshold(grayImage, 0, 255, cv2.THRESH_OTSU | cv2.THRESH_BINARY_INV)# 形态学操作
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (18, 18))
dilation = cv2.dilate(thresh, horizontal_kernel, iterations=1)# 查找轮廓
horizontal_contours, hierarchy = cv2.findContours(dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)# 在原始图像上绘制红色矩形和进行字符分割
for cnt in horizontal_contours:x, y, w, h = cv2.boundingRect(cnt)# 绘制红色矩形rect = cv2.rectangle(myImage, (x, y), (x + w, y + h), (0, 0, 255), 1)# 在水平轮廓区域内进行字符分割roi = thresh[y:y + h, x:x + w]# 进行字符分割的额外步骤,例如形态学操作、查找字符轮廓等char_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))char_dilation = cv2.dilate(roi, char_kernel, iterations=1)char_contours, _ = cv2.findContours(char_dilation, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)# 在原始图像上绘制字符的边界for char_cnt in char_contours:char_x, char_y, char_w, char_h = cv2.boundingRect(char_cnt)char_rect = cv2.rectangle(myImage, (x + char_x, y + char_y), (x + char_x + char_w, y + char_y + char_h),(0, 255, 0), 1)# 显示图像
cv2.imshow('Image with Red Rectangles and Character Boundaries', myImage)
cv2.waitKey(0)

`
在这里插入图片描述

小结

在传统图像处理中,如何利用常见的形态学方法进行字符轮廓查找,从而实现字符的切分。通过提供相应的代码实现,展示了在一些字符分布简单、字符间隔较大的场景下,该方法能够取得一定的效果。然而,由于采用传统方案,该方法的泛化性较为有限。在面对更复杂的场景时,可以考虑借助神经网络等先进技术,以实现更加鲁棒和适用于多种情况的字符切分算法。

相关文章:

【OpenCV实现图像:OpenCV进行OCR字符分割】

文章目录 概要基本概念读入图像图像二值化小结 概要 在处理OCR(Optical Character Recognition,光学字符识别)时,利用传统的图像处理方法进行字符切分仍然是一种有效的途径。即便当前计算机视觉领域主导的是卷积神经网络&#xf…...

景联文科技入选量子位智库《中国AIGC数据标注产业全景报告》数据标注行业代表机构

量子位智库《中国AIGC数据标注产业全景报告》中指出,数据标注处于重新洗牌时期,更高质量、专业化的数据标注成为刚需。未来五年,国内AI基础数据服务将达到百亿规模,年复合增长率在27%左右。 基于数据基础设施建设、大模型/AI技术理…...

ClickHouse SQL操作

基本上来说传统关系型数据库(以MySQL为例)的SQL语句,ClickHouse基本都支持,这里不会从头讲解SQL语法只介绍ClickHouse与标准SQL(MySQL)不一致的地方。 1 Insert 基本与标准SQL(MySQL&#xff09…...

Ubuntu安装Python环境(使用VSCode)

想在Ubuntu上安装Python环境,选择了VSCode,而不想多装Anaconda等环境,最后参考了这篇博客: python入门开发:ubuntu下搭建python开发环境(vscode)...

QTcpSocket发送结构体的做法

作者:朱金灿 来源:clever101的专栏 为什么大多数人学不会人工智能编程?>>> QTcpSocket发送结构体其实很简单:使用QByteArray类对象进行封装发送,示例代码如下: /* 消息结构体 */ struct stMsg {int m_A…...

微服务学习 | Ribbon负载均衡、Nacos注册中心、微服务技术对比

Ribbon负载均衡 负载均衡流程 负载均衡策略 通过定义IRule实现可以修改负载均衡规则,有两种方式: 1. 代码方式:在服务消费者order-service中的OrderApplication类中,定义一个新的IRule: 2.配置文件方式: 在order-service的application.yml…...

【FPGA】zynq 单端口RAM 双端口RAM 读写冲突 写写冲突

RAMRAM读写分类RAM原理及实现RAM三种读写模式不变模式写优先读优先 单端口 RAM伪双端口 RAM真双端口 RAM读写冲突和写写冲突读写冲突写写冲突总结: RAM RAM 的英文全称是 Random Access Memory,即随机存取存储器,简称随机存储器,…...

【备忘】websocket学习之挖坑埋自己

背景故事 以前没有好好学习过websocket,只知道它有什么用途,也知道是个好东西,平时在工作中没用过,所以对它并不知所以然。如今要做个自己的项目,要在付款的时候实时播报声音。自己是个开发者,也不想用别人…...

大数据研发工程师面试

文章目录 面试1.AUC,ROC,准确率与召回率都是怎么计算的?2.数据清洗是如何清洗的,要做哪些清洗的工作?3.什么是数据的完整性?4.数仓是怎么设计的?5.linux查看进程的命令是什么,如何查看具体某一行的内容(查看第n至m行&#xff0…...

【星海出品】云存储 ceph

https://ceph.com/en/ ceph组件介绍 Monitor 一个Ceph集群需要多个Monitor组成的小集群,它们通过Paxos同步数据,用来保存OSD的元数据。 OSD OSD全称Object Storage Device,也就是负责响应客户端请求返回具体数据的进程。一个Ceph集群一般都有…...

[nlp] grad norm先降后升再降

grad norm先降后升再降正常嘛 在深度学习中,梯度的范数通常被用来衡量模型参数的更新程度,也就是模型的学习进度。在训练初期,由于模型参数的初始值比较随机,梯度的范数可能会比较大,这是正常现象。随着模型的训练&…...

云积天赫AI全域营销系统,为品牌营销注入新活力

AIGC(生成式人工智能)的出现,标志着人工智能已经进入了一个全新的时代,它与传统的人工智能不同,可以更好地理解品牌的需求,并提供更精准的答案。目前,AIGC已经深入到各个领域,其中营…...

Arthas在线修改Java代码

Arthas在线修改Java代码 jad --source-only com.example.demo.arthas.user.UserController > /tmp/UserController.javamc /tmp/UserController.java -d /tmpretransform /tmp/com/example/demo/arthas/user/UserController.class参考链接: arthas retransform...

mapbox支持的坐标系

mapbox 中只支持 web墨卡托坐标系,不支持经纬度坐标系。 栅格数据 基于经纬度坐标系的栅格数据没有办法渲染。矢量数据 矢量数据代码中会自动转换成墨卡托投影坐标系再渲染。 输出坐标时候还是经纬度。...

腾讯云新客户优惠服务器88元/年,540元/3年,另有5年优惠服务器

在选择云服务器时,首先需要考虑的是性能与配置是否与自己的需求相匹配。对于小型网站或者个人博客,轻量应用服务器是一个不错的选择。腾讯云双十一活动中,2核2G轻量应用服务器的活动优惠价为88元/年,2核4G轻量应用服务器的活动优惠…...

伦敦银和美白银的关系

与黄金相似,世界上白银交易的基础就是伦敦白银市场,人们利用设立在伦敦的专们负责清算银行(与黄金的清算银行相同)所开设的账户进行白银保证金交易。在伦敦市场,以美元清算的伦敦白银价格,是以美元买进1金衡…...

Matplotlib的使用方法

Matplotlib是Python最著名的绘图库,它提供了一整套和Matlab相似的命令API,十分适合交互式地进行制图。而且也可以方便地将它作为绘图控件,嵌入到GUI应用程序中。Matplotlib能够创建多数类型的图表,如条形图、散点图、条形图、饼图…...

【入门篇】1.7 Redis 之 codis 入门介绍

文章目录 1. 简介2. Codis的安装与配置下载编译源码安装1. 安装 Go 运行环境2. 设置编译环境3. 下载 Codis 源代码4. 编译 Codis 源代码 Docker 部署 3. Codis的架构Codis的架构图和组件Codis的工作流程 4. Codis的核心特性自动数据分片数据迁移高可用性全面支持Redis命令分布式…...

【JavaEE】Servlet API 详解(HttpServlet类)

一、HttpServlet 写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自HttpServlet, 并重写其中的某些方法 1.1 HttpServlet核心方法 1.2 Servlet生命周期 这些方法的调用时机, 就称为 “Servlet 生命周期”. (也就是描述了一个 Servlet 实例从生到死的过程) 1.3 处理G…...

微软宣布计划在 Windows 10 版本 22H2 中引入 AI 助手 Copilot

根据之前的传言,微软宣布计划在 Windows 10 版本 22H2 中引入 AI 助手 Copilot。Copilot 将包含在 Windows 10 家庭版和专业版中。该更新的发布日期尚未公布,但预计将在不久的将来发布。 在一份新闻稿中,微软表示在向 Windows 11 用户提供 Co…...

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

Java 语言特性(面试系列1)

一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

简易版抽奖活动的设计技术方案

1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八

现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

Neo4j 集群管理:原理、技术与最佳实践深度解析

Neo4j 的集群技术是其企业级高可用性、可扩展性和容错能力的核心。通过深入分析官方文档,本文将系统阐述其集群管理的核心原理、关键技术、实用技巧和行业最佳实践。 Neo4j 的 Causal Clustering 架构提供了一个强大而灵活的基石,用于构建高可用、可扩展且一致的图数据库服务…...

解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错

出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...

AI书签管理工具开发全记录(十九):嵌入资源处理

1.前言 📝 在上一篇文章中,我们完成了书签的导入导出功能。本篇文章我们研究如何处理嵌入资源,方便后续将资源打包到一个可执行文件中。 2.embed介绍 🎯 Go 1.16 引入了革命性的 embed 包,彻底改变了静态资源管理的…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

视频行为标注工具BehaviLabel(源码+使用介绍+Windows.Exe版本)

前言: 最近在做行为检测相关的模型,用的是时空图卷积网络(STGCN),但原有kinetic-400数据集数据质量较低,需要进行细粒度的标注,同时粗略搜了下已有开源工具基本都集中于图像分割这块&#xff0c…...

Java数值运算常见陷阱与规避方法

整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...