使用Python+OpenCV2进行图片中的文字分割(支持竖版)

news2025/1/21 20:22:04

扣字和分割

把图片中的文字,识别出来,并将每个字的图片抠出来;

import cv2
import numpy as np

HIOG = 50
VIOG = 3
Position = []
 
'''水平投影'''
def getHProjection(image):
    hProjection = np.zeros(image.shape,np.uint8)
    # 获取图像大小
    (h,w)=image.shape
    # 统计像素个数
    h_ = [0]*h
    for y in range(h):
        for x in range(w):
            if image[y,x] == 255:
                h_[y]+=1
    #绘制水平投影图像
    for y in range(h):
        for x in range(h_[y]):
            hProjection[y,x] = 255
    # cv2.imshow('hProjection2',cv2.resize(hProjection, None, fx=0.3, fy=0.5, interpolation=cv2.INTER_AREA))
    # cv2.waitKey(0)
    return h_
 
def getVProjection(image):
    vProjection = np.zeros(image.shape,np.uint8);
    (h,w) = image.shape
    w_ = [0]*w
    for x in range(w):
        for y in range(h):
            if image[y,x] == 255:
                w_[x]+=1
    for x in range(w):
        for y in range(h-w_[x],h):
            vProjection[y,x] = 255
    # cv2.imshow('vProjection',cv2.resize(vProjection, None, fx=1, fy=0.1, interpolation=cv2.INTER_AREA))
    # cv2.waitKey(0)
    return w_


def scan(vProjection, iog, pos = 0):
    start = 0
    V_start = []
    V_end = []

    for i in range(len(vProjection)):
        if vProjection[i] > iog and start == 0:
            V_start.append(i)
            start = 1
        if vProjection[i] <= iog and start == 1:
            if i - V_start[-1] < pos:
                continue
            V_end.append(i)
            start = 0
    return V_start, V_end


def checkSingle(image):
    h = getHProjection(image)
    start = 0
    end = 0

    for i in range(h):
        pass

#分割
def CropImage(image,dest,boxMin,boxMax):
    a=boxMin[1]
    b=boxMax[1]
    c=boxMin[0]
    d=boxMax[0]
    cropImg = image[a:b,c:d]
    cv2.imwrite(dest,cropImg)
    
#开始识别
def DOIT(rawPic):
        # 读入原始图像
    origineImage = cv2.imread(rawPic)
    # 图像灰度化   
    #image = cv2.imread('test.jpg',0)
    image = cv2.cvtColor(origineImage,cv2.COLOR_BGR2GRAY)
    
    # cv2.imshow('gray',image)
    # 将图片二值化
    retval, img = cv2.threshold(image,127,255,cv2.THRESH_BINARY_INV)
    # kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
    # img = cv2.erode(img, kernel)
    # cv2.imshow('binary',cv2.resize(img, None, fx=0.3, fy=0.3, interpolation=cv2.INTER_AREA))
    #图像高与宽
    (h,w)=img.shape
    #垂直投影
    V = getVProjection(img)
 
    start = 0
    V_start = []
    V_end = []

    # 对垂直投影水平分割
    V_start, V_end = scan(V, HIOG)
    if len(V_start) > len(V_end):
        V_end.append(w-5)

    # 分割行,分割之后再进行列分割并保存分割位置
    for i in range(len(V_end)):
        #获取行图像
        if V_end[i] - V_start[i] < 30:
            continue

        cropImg = img[0:h, V_start[i]:V_end[i]]
        # cv2.imshow('cropImg',cropImg)
        # cv2.waitKey(0)
        #对行图像进行垂直投影
        H = getHProjection(cropImg)
        H_start, H_end = scan(H, VIOG, 40)


        if len(H_start) > len(H_end):
            H_end.append(h-5)

        for pos in range(len(H_start)):
            # 再进行一次列扫描
            DcropImg = cropImg[H_start[pos]:H_end[pos], 0:w]
            d_h, d_w = DcropImg.shape
            # cv2.imshow("dcrop", DcropImg)
            sec_V = getVProjection(DcropImg)
            c1, c2 = scan(sec_V, 0)
            if len(c1) > len(c2):
                c2.append(d_w)

            x = 1
            while x < len(c1):
                if c1[x] - c2[x-1] < 12:
                    c2.pop(x-1)
                    c1.pop(x)
                    x -= 1
                x += 1

            # cv2.waitKey(0)
            if len(c1) == 1:
                Position.append([V_start[i],H_start[pos],V_end[i],H_end[pos]])
            else:
                for x in range(len(c1)):
                    Position.append([V_start[i]+c1[x], H_start[pos],V_start[i]+c2[x], H_end[pos]])

    #根据确定的位置分割字符
    number=0
    for m in range(len(Position)):
        rectMin =  (Position[m][0]-5,Position[m][1]-5)
        rectMax =  (Position[m][2]+5,Position[m][3]+5)
        cv2.rectangle(origineImage,rectMin, rectMax, (0 ,0 ,255), 2)
        number=number+1
        #start-crop
        CropImage(origineImage,'result/' + '%d.jpg' % number,rectMin,rectMax)
    # cv2.imshow('image',cv2.resize(origineImage, None, fx=0.6, fy=0.6, interpolation=cv2.INTER_AREA))
    cv2.imshow('image',origineImage)
    cv2.imwrite('result/' + 'ResultImage.jpg' , origineImage)
    cv2.waitKey(0)

#############################
rawPicPath = r"H:\TEMP\TEXT_PROCCESS\TEST05.jpg"
DOIT(rawPicPath)
#############################


原图片:

分割后文件夹:

重命名

可见此时文件都还是数字为文件名称,那么接下来要利用OCR自动给每个文字图片文件命名

我们使用UMIOCR , UMI-OCR的安装建议去GITHUB上查,windows上部署还是很方便的;

这里使用本机安装好的UMI-OCR 的 API地址  http://127.0.0.1:1224/api/ocr

先定义API调用方法

  
############################################
import base64
import requests
import json

#API访问使用
def UMI_OCR_OPT(url,img_path): 
    # url = "http://127.0.0.1:1224/api/ocr"
    # img_path= './result/123.jpg'
 
    with open(img_path,'rb') as f:
        image_base64 = base64.b64encode(f.read())
        image_base64 =str(image_base64,'utf-8')
    
    data = {
        "base64": image_base64,
        # 可选参数
        # Paddle引擎模式
        # "options": {
        #     "ocr.language": "models/config_chinese.txt",
        #     "ocr.cls": False,
        #     "ocr.limit_side_len": 960,
        #     "tbpu.parser": "MergeLine",
        # }
        # Rapid引擎模式
        # "options": {
        #     "ocr.language": "简体中文",
        #     "ocr.angle": False,
        #     "ocr.maxSideLen": 1024,
        #     "tbpu.parser": "MergeLine",
        # }
    }
    headers = {"Content-Type": "application/json"}
    data_str = json.dumps(data)
    response = requests.post(url, data=data_str, headers=headers)
    if response.status_code == 200:
        res_dict = json.loads(response.text)
        #检测失败与否
        if(str(res_dict).find('No text found in image')!=-1):
            # print("返回失败内容\n", res_dict)
            return ''
        print("返回值字典\n", res_dict)
        resText = res_dict['data'][0]['text']
        return resText
    return ''

开始批量调用检测

import easyocr

import shutil

error =''

#api地址
uni_orc_url="http://127.0.0.1:1224/api/ocr"
#将所有字体
for i in range(1,285):
    filePath = "./result/"+str(i)+".jpg"
    # result = reader.readtext(filePath, detail = 0)
    result = UMI_OCR_OPT(uni_orc_url,filePath)
    if(len(result)==0 or result == ''):
        error+= filePath +'\n'
        continue
    print(result)
    destPath = "./resultX/"+result[0]+".jpg" 
    print('sour :: '+ filePath)
    print('dest :: '+ destPath)
    shutil.copyfile(filePath, destPath)

print('error:\n'+error)

然后将能够识别出来的所有文字图片都复制并重命名为该字

效果如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1446785.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Langchain Agent研究】SalesGPT项目介绍(三)

【Langchain Agent研究】SalesGPT项目介绍&#xff08;二&#xff09;-CSDN博客 上节课&#xff0c;我们介绍了salesGPT项目的初步的整体结构&#xff0c;poetry脚手架工具和里面的run.py。在run.py这个运行文件里&#xff0c;引用的最主要的类就是SalesGPT类&#xff0c;今天我…

DS Wannabe之5-AM Project: DS 30day int prep day14

Q1. What is Autoencoder? 自编码器是什么&#xff1f; 自编码器是一种特殊类型的神经网络&#xff0c;它通过无监督学习尝试复现其输入数据。它通常包含两部分&#xff1a;编码器和解码器。编码器压缩输入数据成为一个低维度的中间表示&#xff0c;解码器则从这个中间表示重…

P1164 小A点菜题解

题目 uim拿到了uoi的镭牌后&#xff0c;立刻拉着基友小A到了一家餐馆&#xff0c;很低端的那种。uim指着墙上的价目表&#xff08;太低级了没有菜单&#xff09;&#xff0c;说&#xff1a;“随便点”。 不过uim由于买了一些书&#xff0c;口袋里只剩M元(M≤10000)。 餐馆虽…

算法村目录

大家好我是苏麟 , 这是算法村使用目录 . 算法通关村 从链表到动态规划的实战 目录 算法村开篇第一关 了解链表第二关 链表专题第三关 数组专题第四关 栈专题第五关 队列专题第六关 树专题第七关 二叉树遍历专题第八关 二叉树专题第九关 二分查找与二叉树专题第十关 快速排序与归…

Java学习18-- Override方法重写【★】

重点&#xff1a;super类 & 方法重写 ★看不明白多看几遍&#xff0c;记住static优先级>>高于override 重写Override methods★ 重写Override&#xff1a;child class可以覆盖father class中的method&#xff0c;即子类child class和父类father class有相同名称、…

extern 使用头文件

画红线的那个 很重要 详细解释之后写 全局变量定义在头文件&#xff0c;然后如果很多c文件通过include包含这个头文件&#xff0c;那么因为include是在预编译阶段&#xff0c;直接把这个头文件里面的东西解出来&#xff0c;然后插入在这个c文件&#xff0c;那么如果有很多个c文…

mysql数据库concat指定连接符号

SELECT CONCAT_WS(;;;, 你好,华为) FROM DUAL;

【算法随想录01】环形链表

题目&#xff1a;141. 环形链表 难度&#xff1a;EASY 代码 哈希表遍历求解&#xff0c;表中存储的是元素地址。 时间复杂度 O ( N ) O(N) O(N)&#xff0c;空间复杂度 O ( N ) O(N) O(N) /*** Definition for singly-linked list.* struct ListNode {* int val;* …

iTop-4412 裸机程序(十九)- 按键中断

目录 0.源码1.异常向量表1.1 原理1.2 异常种类1.3 ARMv7 规定的异常向量表 2. 中断2.1 iTop-4412 中使用的中断相关寄存器 上篇博文介绍了按键的轮询处理方式&#xff0c;本篇介绍按键的中断方式。 0.源码 GitHub&#xff1a;https://github.com/Kilento/4412NoOS 1.异常向量…

《Java 简易速速上手小册》第4章:Java 中的异常处理(2024 最新版)

文章目录 4.1 异常类型和错误 - 遇见你的小怪兽4.1.1 基础知识4.1.2 重点案例&#xff1a;文件读取处理4.1.3 拓展案例 1&#xff1a;处理空指针异常4.1.4 拓展案例 2&#xff1a;捕获多个异常 4.2 异常处理机制 - 穿上你的超级英雄斗篷4.2.1 基础知识4.2.2 重点案例&#xff1…

SpringCloud-Feign:负载均衡(基于服务端)

7.Feign&#xff1a;负载均衡(基于服务端) 7.1 Feign简介 Feign是一个开源的声明式HTTP客户端&#xff0c;它可以简化HTTP API的调用过程。Feign的设计目标是使得使用者可以像调用本地方法一样调用远程服务&#xff0c;使得编写和维护HTTP客户端变得更加简单。类似controller…

2016-2022年哨兵影像的在线底图

有一个欧洲初创公司对哨兵影像进行了去云处理&#xff0c;制作了一个2016年-2022年的全球哨兵底图。目前底图通过wmts发布&#xff0c;可免费使用&#xff0c;无需搭梯子。 该数据的特点是&#xff1a; 很少的云覆盖&#xff0c;较少的条纹&#xff0c;色彩平衡 底图切片的网…

推荐高端资源素材图库下载平台整站源码

推荐高端图库素材下载站的响应式模板和完整的整站源码&#xff0c;适用于娱乐网资源网。该模板支持移动端&#xff0c;并集成了支付宝接口。 演示地 址 &#xff1a; runruncode.com/tupiao/19692.html 页面设计精美&#xff0c;不亚于大型网站的美工水准&#xff0c;并且用户…

如何对研究成果进行有效的专利布局

一、背景 研究成果通常是研究者、学者或创新者智力劳动的产物&#xff0c;如专利技术、设计、算法、新药物、研究方法等。通过专利申请、版权法、商标法、商业秘密等方式对其进行法律保护&#xff0c;确保研究者拥有对其成果的专有权&#xff0c;可以独享经济利益和控制权。 …

[LeetCode周赛复盘] 第 384 场周赛20240211

[LeetCode周赛复盘] 第 384 场周赛20240211 一、本周周赛总结100230. 修改矩阵1. 题目描述2. 思路分析3. 代码实现 100219. 回文字符串的最大数量1. 题目描述2. 思路分析3. 代码实现 100198. 匹配模式数组的子数组数目 II1. 题目描述2. 思路分析3. 代码实现 参考链接 一、本周…

GPT4:你是故意的吧!

请问下面选项中哪个是中文&#xff1f; A.Chinese B.英文 这是一个关于语言识别的问题。我们需要分析并确定所给选项中哪个表示中文。 对于选项A.Chinese&#xff1a;这个词本身表示“中文”或“中国的”。在多种语境中&#xff0c;它经常被用来指代中国的语言&#xff0c;即中…

京东组件移动端库的使用 Nut-UI

1.介绍 NutUI NutUI-Vue 组件库&#xff0c;基于 Taro&#xff0c;使用 Vue 技术栈开发小程序应用&#xff0c;开箱即用&#xff0c;帮助研发快速开发用户界面&#xff0c;提升开发效率&#xff0c;改善开发体验。 特性 &#x1f680; 80 高质量组件&#xff0c;覆盖移动端主…

Spring Boot 笔记 007 创建接口_登录

1.1 登录接口需求 1.2 JWT令牌 1.2.1 JWT原理 1.2.2 引入JWT坐标 1.2.3 单元测试 1.2.3.1 引入springboot单元测试坐标 1.2.3.2 在单元测试文件夹中创建测试类 1.2.3.3 运行测试类中的生成和解析方法 package com.geji;import com.auth0.jwt.JWT; import com.auth0.jwt.JWTV…

Spring Boot 笔记 010 创建接口_更新用户头像

1.1.1 usercontroller中添加updateAvatar&#xff0c;校验是否为url PatchMapping("updateAvatar")public Result updateAvatar(RequestParam URL String avatarUrl) {userService.updateAvatar(avatarUrl);return Result.success();} 1.1.2 userservice //更新头像…

BYTEVALUE 百为流控路由器远程命令执行漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…