实现批量图片文字识别(python+flask+EasyOCR)

话不多说,向上效果图

1)先说框架版本

为什么要先说框架版本呢,因为我在各种版本中尝试了两天,总算确定了如下版本适合我,至于其他的版本,各位自己去尝试

        python 3.9.7

        EasyOCR 1.7.2

        flask 3.0.3

2)执行操作效果图

        2.1)多选文件

2.2)图片预览

2.3)提取选中文件

2.4)提取所有文件

3.上代码

        3.1)前端代码index.html

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Python OCR</title><link rel="stylesheet" href="/static/js/bootstrap/css/bootstrap.min.css"><style>.container {max-width: 1024px;margin-top: 20px;}.preview-image {max-width: 300px;max-height: 400px;margin-top: 10px;}.file-input {display: none;}</style>
</head>
<body><div class="container"><div class="row"><div class="col-md-12"><input type="file" id="fileInput" class="file-input" multiple></div></div><div class="row mt-3"><div class="col-md-6"><div class="list-group" id="picListBox"></div><button id="btnExtractSelected" class="btn btn-primary mt-2">提取选中文件</button><button id="btnDeleteSelected" class="btn btn-danger mt-2">删除选中文件</button></div><div class="col-md-6"><img id="lblImage" class="preview-image" src="" alt="暂未选择文件"></div></div><div class="row mt-3"><div class="col-md-12"><textarea id="txtPressInof" class="form-control" rows="5" readonly></textarea></div></div><div class="row mt-3"><div class="col-md-12 text-center"><button id="btnDo" class="btn btn-success">立即提取所有文件</button></div></div></div><script src="/static/js/jQuery-2.2.0.min.js"></script><script>$(document).ready(function () {// 处理文件选择$('#fileInput').change(function () {const files = $(this)[0].files;$('#picListBox').empty();for (let i = 0; i < files.length; i++) {const filename = files[i].name;const item = $('<a href="#" class="list-group-item list-group-item-action">' + filename + '</a>');item.data('file', files[i]);$('#picListBox').append(item);}});// 图片列表项点击事件$('#picListBox').on('click', 'a', function () {// 移除其他列表项的 active 类$('#picListBox a').removeClass('active');// 为当前点击的列表项添加 active 类$(this).addClass('active');const file = $(this).data('file');const reader = new FileReader();reader.onload = function (e) {$('#lblImage').attr('src', e.target.result);};reader.readAsDataURL(file);});// 删除选中文件按钮点击事件$('#btnDeleteSelected').click(function () {const selectedFileItem = $('#picListBox a.active');if (!selectedFileItem.length) {alert('请选择一个文件');return;}// 移除选中的文件项selectedFileItem.remove();// 清空 lblImage$('#lblImage').attr('src', '');$('#lblImage').attr('alt', '暂未选择文件');});// 提取选中文件按钮点击事件$('#btnExtractSelected').click(function () {const selectedFile = $('#picListBox a.active').data('file');if (!selectedFile) {alert('请选择一个文件');return;}const formData = new FormData();formData.append('file', selectedFile);$(this).prop('disabled', true).text('正在提取...');$.ajax({url: '/extract-selected', // 后端接口,处理选中的图片并返回提取结果type: 'POST',data: formData,contentType: false,processData: false,success: function (data) {$('#txtPressInof').val(data);$('#btnExtractSelected').prop('disabled', false).text('提取选中文件');}});});// 立即提取所有文件按钮点击事件$('#btnDo').click(function () {const formData = new FormData();$('#picListBox a').each(function () {formData.append('files', $(this).data('file'));});$(this).prop('disabled', true).text('正在提取...');$.ajax({url: '/process-pictures', // 后端接口,处理所有图片并返回提取结果type: 'POST',data: formData,contentType: false,processData: false,success: function (data) {$('#txtPressInof').val(data);$('#btnDo').prop('disabled', false).text('立即提取所有文件');}});});});</script>
</body>
</html>

        3.2)后端代码

from flask import Flask, request, jsonify, render_template
import os
import easyocr
import time
import re
app = Flask(__name__)@app.route('/')
def index():return render_template('index.html')def clean_filename(filename):"""清理文件名,移除非法字符"""return re.sub(r'[\\/*?:"<>|]', "", filename)def get_unique_filename(target_folder, filename):"""确保文件名唯一,避免覆盖同名文件"""base, ext = os.path.splitext(filename)unique_filename = filenamecounter = 1while os.path.exists(os.path.join(target_folder, unique_filename)):unique_filename = f"{base}_{int(time.time())}{ext}"  # 添加时间戳确保唯一性counter += 1return unique_filename@app.route('/process-pictures', methods=['POST'])
def process_pictures():# 指定保存图片的目标文件夹target_folder = "D:/OCR_Images"  # 请确保该文件夹存在或在代码中创建它if not os.path.exists(target_folder):os.makedirs(target_folder)files = request.files.getlist('files')reader = easyocr.Reader(['ch_sim', 'en'], model_storage_directory='./model')result = ""for i, file in enumerate(files):# 获取文件名(不包含路径)filename = os.path.basename(file.filename)#print(filename)# 清理文件名safe_filename = clean_filename(filename)#print(safe_filename)# 确保文件名唯一unique_filename = get_unique_filename(target_folder, filename)#print(unique_filename)file_path = os.path.join(target_folder, unique_filename)file.save(file_path)result += f'【开始处理{i + 1}-{len(files)}张图片,{unique_filename}】\n'#print(file_path,result)ocr_result = reader.readtext(file_path)restxt = ""for ln in ocr_result:restxt += ln[1]restxt += "\n"result += restxtresult += "全部完成"return jsonify(result)@app.route('/extract-selected', methods=['POST'])
def extract_selected():# 指定保存图片的目标文件夹target_folder = "D:/OCR_Images"  # 请确保该文件夹存在或在代码中创建它if not os.path.exists(target_folder):os.makedirs(target_folder)file = request.files['file']# 获取文件名(不包含路径)filename = os.path.basename(file.filename)# 清理文件名safe_filename = clean_filename(filename)# 确保文件名唯一unique_filename = get_unique_filename(target_folder, safe_filename)file_path = os.path.join(target_folder, unique_filename)file.save(file_path)reader = easyocr.Reader(['ch_sim', 'en'], model_storage_directory='./model')ocr_result = reader.readtext(file_path)result = f'【开始处理文件,{unique_filename}】\n'restxt = ""for ln in ocr_result:restxt += ln[1]restxt += "\n"result += restxtreturn jsonify(result)if __name__ == '__main__':app.run(debug=True)

最后提示:文字模型需自行下载保存到本地,我保存在自己的项目下的model目录下

模型的引用语句(有gpu的情况):

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

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

相关文章

国产GPU生态现状评估:从寒武纪到壁仞的编程适配挑战

近年来&#xff0c;国产GPU厂商在硬件性能上持续突破&#xff0c;但软件生态的构建仍面临严峻挑战。本文以寒武纪、壁仞等代表性企业为例&#xff0c;对比分析其与CUDA生态的兼容性差异&#xff0c;并探讨技术突围路径。 一、编程适配的核心挑战 ‌编程模型差异与开发成本‌ …

YOLOv8 Bug 及解决方案汇总 【2024.1.24更新】【环境安装】【训练 断点续训】OMPError / KeyError

YOLOv8 Bug 及解决方案汇总&#xff1a;深入解析与应对 引言 YOLOv8作为一款高性能的目标检测算法&#xff0c;在实际应用中难免会遇到各种各样的问题。本文将对YOLOv8常见的Bug进行汇总&#xff0c;并提供相应的解决方案&#xff0c;旨在帮助开发者更好地使用和优化YOLOv8。…

面试算法高频08-动态规划-02

动态规划练习题 题目描述 给定两个字符串 text1 和 text2&#xff0c;要求返回这两个字符串的最长公共子序列。例如对于字符串 “ABAZDC” 和 “BACBAD”&#xff0c;需找出它们最长的公共子序列。子序列是指在不改变其余字符相对位置的情况下&#xff0c;从原始字符串中删除…

【人工智能学习-01-01】20250419《数字图像处理》复习材料的word合并PDF,添加页码

前情提要 20250419今天是上师大继续教育人工智能专升本第一学期的第一次线下课。 三位老师把视频课的内容提炼重点再面授。&#xff08;我先看了一遍视频&#xff0c;但是算法和图像都看不懂&#xff0c;后来就直接挂分刷满时间&#xff0c;不看了&#xff09; 今天是面对面授…

AI写代码工具分享:Cursor 高效使用攻略与实战秘籍

写在前面 在软件开发领域,效率和生产力是永恒的追求。集成开发环境(IDE)作为开发者的核心工具,其能力直接影响着开发速度和质量。近年来,人工智能(AI)的浪潮席卷了各个行业,编程领域也不例外。Cursor IDE 正是这股浪潮中的佼佼者,它以 AI-First 的理念,在广受欢迎的…

守护进程编程

守护进程编程 守护进程的含义 定义 守护进程&#xff08;Daemon Process&#xff09;是在后台运行的进程&#xff0c;它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件。守护进程是一种很有用的进程&#xff0c;它在系统后台运行&#xff0c;为系统或其他…

在复杂性的迷宫里寻找路标 —— 读《人月神话》有感

初读《人月神话》时&#xff0c;正值参与的第一个大型项目陷入泥潭&#xff1a;需求像不断膨胀的气球&#xff0c;团队规模从 10 人扩充到 30 人&#xff0c;进度却像被灌了铅的钟表&#xff0c;指针越来越沉重。布鲁克斯在书中写下的 "向进度落后的项目增加人力&#xff…

SpringCloud Alibaba微服务工程搭建

前言 在讲微服务工程的搭建之前&#xff0c;我们先分析下为什么要使用微服务呢&#xff1f; 1、单体应用的痛点 维护困难&#xff1a;代码臃肿&#xff0c;牵一发而动全身。扩展性差&#xff1a;无法按需扩展特定功能&#xff0c;只能整体扩容。技术栈僵化&#xff1a;难以引…

flutter json解析增强

依赖:xxf_json 反序列化兼容特征一览表 类型\是否兼容 int double num string bool int yes yes yes yes yes double yes yes yes yes yes num yes yes yes yes yes string yes yes yes yes yes bool yes yes yes yes yes 专业词语 .g…

Neo4j初解

Neo4j 是目前应用非常广泛的一款高性能的 NoSQL 图数据库&#xff0c;其设计和实现专门用于存储、查询和遍历由节点&#xff08;实体&#xff09;、关系&#xff08;边&#xff09;以及属性&#xff08;键值对&#xff09;构成的图形数据模型。它的核心优势在于能够以一种自然且…

学习MySQL的第十天

一、MySQL的数据类型 1.MySQL的数据类型 2.常见的数据类型的属性 二、整数类型 三、浮点类型 REAL默认就是DOUBLE。如果你把SQL模式设定为启用“REAL_AS_FLOAT”,那么,MySQL就认为REAL是FLOAT。如果要启用“REAL_AS_FLOAT”,可以通过以下SQL语句实现: SET sql_mode &…

ubuntu24.04上使用qemu+buildroot+uboot+linux+tftp+nfs模拟搭建vexpress-ca9嵌入式linux开发环境

1 准备工作 1.1 安装依赖工具 sudo apt-get update && sudo apt-get install build-essential git bc flex libncurses5-dev libssl-dev device-tree-compiler1.2 安装arm交叉编译工具链 sudo apt install gcc-arm-linux-gnueabihf安装之后&#xff0c;在终端输入ar…

ubuntu 22.04 使用ssh-keygen创建ssh互信账户

现有两台ubuntu 22.04服务器&#xff0c;ip分别为192.168.66.88和192.168.88.66。需要将两台服务器创建新用户并将新用户做互信。 创建账户 adduser user1 # 如果此用户不想使用密码&#xff0c;直接一直回车就行&#xff0c;创建的用户是没法使用用户密码进行登陆的 su - …

【PCIE配置空间】

1 PCIE配置空间 1.1 软件如何知道PCIE设备是Swith&#xff0c;RC还是EP&#xff1f; –软件通过读取寄存器信息。 PCIE配置空间• PCIE寄存器&#xff1b;--PCIE配置协议规定必须实现的空间。--PCIE存在两种配置空间Type0/Type1;--Type0配置空间EP设备必须实现&#xff1b;-…

Android 热点二维码简单示例

Android 热点二维码简单示例 一、前言 Android 原生设置有热点二维码分享功能&#xff0c;有些系统应用也会有这个需求。 下面看看是如何实现的。 本文是一个比较简单的内容。 二、热点二维码生成实现 1、效果 整个应用就一个普通的Activity&#xff0c;显示一个按钮和二维…

uv:重新定义Python开发效率的下一代工具链

在Python生态系统中&#xff0c;包管理和项目工具链的复杂性一直是开发者面临的一大挑战。从依赖管理、虚拟环境创建到多版本Python切换&#xff0c;传统的工具链&#xff08;如pip、virtualenv、poetry等&#xff09;虽然功能强大&#xff0c;但操作繁琐、性能不足的问题长期存…

T101D加固平板电脑:无人机地面站的高效智能控制核心

随着无人机技术在应急救援、农业监测、军事侦察等领域的广泛应用&#xff0c;对地面控制设备的要求也日益提高。鲁成伟业推出的T101D加固平板电脑凭借其高性能、强防护和专业化设计&#xff0c;成为无人机地面站的核心控制终端&#xff0c;为复杂环境下的作业提供了可靠支持。 …

Datawhale AI春训营】AI + 新能源(发电功率预测)Task1

赛题链接 官网 新能源发电功率预测赛题进阶方案 下面是ai给的一些建议 新能源发电功率预测赛题进阶方案 一、时序特性深度挖掘 1. 多尺度周期特征 # 分钟级周期编码 train[15min_index] (train[hour]*4 train[minute]//15)# 周周期特征 train[weekday] pd.to_datetime…

山东科技大学深度学习考试回忆

目录 一、填空&#xff08;五个空&#xff0c;十分&#xff09; 二、选择题(五个&#xff0c;十分&#xff09; 三、判断题&#xff08;五个&#xff0c;五分&#xff09; 四、论述题&#xff08;四个&#xff0c;四十分&#xff09; 五、计算题&#xff08;二个&#xff…

Redis线上操作最佳实践有哪些?

大家好&#xff0c;我是锋哥。今天分享关于【Redis线上操作最佳实践有哪些?】面试题。希望对大家有帮助&#xff1b; Redis线上操作最佳实践有哪些? 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在使用 Redis 时&#xff0c;尤其是在生产环境中&#xff0c;合理…