PaddleOCR学习笔记3-通用识别服务

news2024/11/29 14:54:51

今天优化了下之前的初步识别服务的python代码和html代码。

采用flask + paddleocr+ bootstrap快速搭建OCR识别服务。

代码结构如下:

模板页面代码文件如下:

upload.html :

<!DOCTYPE html>
<html>
<meta charset="utf-8">
<head>
    <title>PandaCodeOCR</title>
    <!--静态加载 样式-->
    <link rel="stylesheet" href={{ url_for('static',filename='bootstrap3/css/bootstrap.min.css') }}></link>
    <style>
        body {
            font-family: Arial, sans-serif;
            margin: 0;
            padding: 0;
        }

        .header {
            background-color: #f0f0f0;
            text-align: center;
            padding: 20px;
        }

        .title {
            font-size: 32px;
            margin-bottom: 10px;
        }

        .menu {
            list-style-type: none;
            margin: 0;
            padding: 0;
            overflow: hidden;
            background-color: #FFDEAD;
            border: 2px solid #DCDCDC;
        }

        .menu li {
            float: left;
            font-size: 24px;
        }

        .menu li a {
            display: block;
            color: #333;
            text-align: center;
            padding: 14px 16px;
            text-decoration: none;
        }

        .menu li a:hover {
            background-color: #ddd;
        }

        .content {
            padding: 20px;
            border: 2px solid blue;
        }
    </style>
</head>
<body>
<div class="header">
    <div class="title">PandaCodeOCR</div>
</div>

<ul class="menu">
    <li><a href="/upload/">通用文本识别</a></li>
</ul>

<div class="content">
    <!--上传图片文件-->
    <div id="upload_file">
        <form id="fileForm" action="/upload/" method="POST" enctype="multipart/form-data">
            <div class="form-group">
                <input type="file" class="form-control" id="upload_file" name="upload_file">
                <label class="sr-only" for="upload_file">上传图片</label>
            </div>
        </form>
    </div>
</div>
</div>

<div id="show" style="display: none;">
    <!--显示上传的图片-->
    <div class="col-md-6" style="border: 2px solid #ddd;">
        <span class="label label-info">上传图片</span>
        <!--静态加载 图片, url_for() 动态生成路径 -->
        <img src="" alt="Image preview area..." title="preview-img" class="img-responsive">
    </div>

    <div class="col-md-6" style="border: 2px solid #ddd;">
        <!--显示识别结果JSON报文列表-->
        <span class="label label-info">识别结果:</span>
        <!-- 结果显示区 -->
        <div id="result_show">加载中......</div>
    </div>
</div>
</body>
</html>
<!--静态加载 script-->
<script src={{ url_for('static',filename='jquery1.3.3/jquery.min.js') }}></script>
<script src={{ url_for('static',filename='js/jquery-form.js') }}></script>
<script type="text/javascript">
    var fileInput = document.querySelector('input[type=file]');
    var previewImg = document.querySelector('img');
    {#上传图片事件#}
    fileInput.addEventListener('change', function () {
        var file = this.files[0];
        var reader = new FileReader();

        //显示预览界面
        $("#show").css("display", "block");

        // 监听reader对象的的onload事件,当图片加载完成时,把base64编码賦值给预览图片
        reader.addEventListener("load", function () {
            previewImg.src = reader.result;
        }, false);
        // 调用reader.readAsDataURL()方法,把图片转成base64
        reader.readAsDataURL(file);

        //初始化输出结果信息
        $("#result_show").html("加载中......");

        {#上传图片识别表单事件,并显示识别结果信息#}
        {# ajaxSubmit 请求异步响应#}
        $("#fileForm").ajaxSubmit(function (data) {
            var inner = "";
            //alert(data['recognize_time'])
            //循环输出返回结果,响应识别结果为每行列表
            for (var i in data['result']) {
                var value = data['result'][i]['text'];
                inner += "<p class='text-left'>" + value + "</p>";
            }
            //清空输出结果信息
            $("#result_show").html("");
            //添加识别结果信息
            $("#result_show").append(inner);
        });
    }, false);
</script>

主要python代码文件如下:

myapp.py:

import json
import os
import time

from flask import Flask, render_template, request, jsonify

from paddleocr import PaddleOCR
from PIL import Image, ImageDraw
import numpy as np

# 应用名称,当前py名称,视图函数
app = Flask(__name__)

# 项目文件夹的绝对路径
# BASE_DIR = os.path.dirname(os.path.abspath(__name__))
# 相对路径
BASE_DIR = os.path.dirname(os.path.basename(__name__))

# 上传文件路径
UPLOAD_DIR = os.path.join(os.path.join(BASE_DIR, 'static'), 'upload')

'''
PaddleOCR模型通用识别方法
'''
def rec_model_ocr(img):
    # 返回字典结果对象
    result_dict = {'result': []}
    # paddleocr 目前支持的多语言语种可以通过修改lang参数进行切换
    # 例如`ch`, `en`, `fr`, `german`, `korean`, `japan`
    # 使用CPU预加载,不用GPU
    # 模型路径下必须包含model和params文件,目前开源的v3版本模型 已经是识别率很高的了
    # 还要更好的就要自己训练模型了。
    ocr = PaddleOCR(det_model_dir='./inference/ch_PP-OCRv3_det_infer/',
                    rec_model_dir='./inference/ch_PP-OCRv3_rec_infer/',
                    cls_model_dir='./inference/ch_ppocr_mobile_v2.0_cls_infer/',
                    use_angle_cls=True, lang="ch", use_gpu=False)
    # 识别图片文件
    result0 = ocr.ocr(img, cls=True)
    result = result0[0]
    for index in range(len(result)):
        line = result[index]

        tmp_dict = {}
        points = line[0]
        text = line[1][0]
        score = line[1][1]
        tmp_dict['points'] = points
        tmp_dict['text'] = text
        tmp_dict['score'] = score

        result_dict['result'].append(tmp_dict)
    return result_dict


# 转换图片
def convert_image(image, threshold=None):
    # 阈值 控制二值化程度,不能超过256,[200, 256]
    # 适当调大阈值,可以提高文本识别率,经过测试有效。
    if threshold is None:
        threshold = 200
    print('threshold : ', threshold)
    # 首先进行图片灰度处理
    image = image.convert("L")
    pixels = image.load()
    # 在进行二值化
    for x in range(image.width):
        for y in range(image.height):
            if pixels[x, y] > threshold:
                pixels[x, y] = 255
            else:
                pixels[x, y] = 0
    return image


@app.route('/')
def upload_file():
    return render_template('upload.html')


@app.route('/upload/', methods=['GET', 'POST'])
def upload():
    if request.method == 'POST':
        # 每个上传的文件首先会保存在服务器上的临时位置,然后将其实际保存到它的最终位置。
        filedata = request.files['upload_file']
        upload_filename = filedata.filename
        print(upload_filename)
        # 保存文件到指定路径
        # 目标文件的名称可以是硬编码的,也可以从 ​request.files[file] ​对象的​ filename ​属性中获取。
        # 但是,建议使用 ​secure_filename()​ 函数获取它的安全版本
        if not os.path.exists(UPLOAD_DIR):
            os.makedirs(UPLOAD_DIR)
        img_path = os.path.join(UPLOAD_DIR, upload_filename)
        filedata.save(img_path)
        print('file uploaded successfully')

        start = time.time()

        print('=======开始OCR识别======')
        # 打开图片
        img1 = Image.open(img_path)
        # 转换图片, 识别图片文本
        # print('转换图片,阈值=220时,再转换为ndarray数组, 识别图片文本')
        # 转换图片
        img2 = convert_image(img1, 220)
        # Image图像转换为ndarray数组
        img_2 = np.array(img2)
        # 识别图片
        result_dict = rec_model_ocr(img_2)

        # 识别时间
        end = time.time()
        recognize_time = int((end - start) * 1000)

        result_dict["filename"] = upload_filename
        result_dict["recognize_time"] = str(recognize_time)
        result_dict["error_code"] = "000000"
        result_dict["error_msg"] = "识别成功"

        # render_template方法:渲染模板
        # 参数1: 模板名称  参数n: 传到模板里的数据
        # return render_template('result.html', result_dict=result_dict)

        # 将数据转换成JSON格式,一般用于ajax异步响应页面,不跳转页面用,等价下面方法
        # return json.dumps(result_dict, ensure_ascii=False), {'Content-Type': 'application/json'}

        # 将数据转换成JSON格式,一般用于ajax异步响应页面,不跳转页面用
        return jsonify(result_dict)

    else:
        return render_template('upload.html')


if __name__ == '__main__':
    # 启动app
   app.run(port=8000)

启动flask应用,测试结果如下:

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

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

相关文章

Linux命令200例:free用来显示系统内存使用情况

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;CSDN领军人物&#xff0c;全栈领域优质创作者✌。CSDN专家博主&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0…

通达信自定义副图换手率指标 HSL_QD

LB:VOL/((REF(VOL,1)REF(VOL,2)REF(VOL,3)REF(VOL,4)REF(VOL,5))/5); DRAWBAND(25,RGB(0,0,0),IF((20MA(LB,5)*5)<40,20MA(LB,5)*5,40),RGB(205,205,0));{量比均线}{DRAWBAND(0,RGB(66,66,66),10,RGB(66,66,66))}; {DRAWBAND(10,RGB(66,66,66),MA(IF((100*VOL/CAPITAL3)<…

【数据结构--二叉树】平衡二叉树

题目描述&#xff1a; 代码实现&#xff1a; /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/ int TreeHeight(struct TreeNode* root) {if(rootNULL)return 0;//左右子树中大的…

12分钟从Executor自顶向下彻底搞懂线程池

通读本篇文章前先来看看几个问题&#xff0c;看看你是否已经理解线程池 什么是池化技术&#xff1f;它有什么特点&#xff0c;哪些场景使用&#xff1f;Executor是什么&#xff1f;它的设计思想是什么样的&#xff1f;工作任务有几种&#xff1f;有什么特点&#xff1f;如何适…

小节1:Python字符串打印

1、字符串拼接 用可以将两个字符串拼接成一个字符串 print("你好 " "这是一串代码") 输出&#xff1a; 2、单双引号转义 当打印的字符串中带有引号或双引号时&#xff0c;使用\或\"表示 print("He said \"Let\s go!\"") 输…

OpenRoads两期工程量(挖填)方量计算

分别生成各期地形&#xff0c;由Create Terrain Model From Ascii File展点&#xff1b; 其中至少一期地形特征设为Existing组特征 创建挖填体积&#xff08;Terrain\Analysis\Create Cut Fill Volumes或Home\Model Analysis and Reporting\Civil Analysis\Create Cut Fill Vo…

深度学习相关VO梳理

相关论文 基于学习的VO 相关&#xff1a; DeepVO Towards End-to-End Visual Odometry with Deep Recurrent Convolutional Neural Networks&#xff08;ICRA&#xff0c;2017&#xff09; TartanVO: A Generalizable Learning-based VO(CoRL2021) SimVODIS: Simultaneous Vis…

第22章 自旋锁死锁实验(iTOP-RK3568开发板驱动开发指南 )

在上一小节中&#xff0c;学习了内核中自旋锁的使用&#xff0c;而自旋锁若是使用不当就会产生死锁&#xff0c;在本章将会对自旋锁的特殊情况-死锁进行讲解。 22.1 自旋锁死锁 死锁是指两个或多个事物在同一资源上相互占用&#xff0c;并请求锁定对方的资源&#xff0c;从而…

【Docker】容器化应用程序的配置管理策略与实践

一、引言 1.1 Docker的背景和优势 Docker是一种开源的容器化平台&#xff0c;简化应用程序的打包、交付和运行过程。基于Linux容器技术&#xff0c;通过提供一个轻量级、可移植和自包含的容器来实现应用程序的隔离和部署。 在传统的应用程序开发和部署中&#xff0c;往往需要…

九科-模块化-创建目录_如果不存在

python代码 # 创建目录_如果不存在 def create_directory_if_not_exists(dir_path):# 如果目录不存在if not os.path.exists(dir_path):# 创建目录os.makedirs(dir_path) 九科组件模块 总图 查询目录是否存在 IF判断目录是否存在 如果目录不存在&#xff0c;创建目录

syn洪流原理

TCP三次握手 建立连接发送或回应第一次握手客户端发送报文&#xff0c;标志位为SYN&#xff08;seqa&#xff09;第二次握手服务器发送报文&#xff0c;标志位为SYN&#xff0c;ACK&#xff08;seqb,acka1&#xff09;第三次握手客户端回应服务器报文&#xff0c;标志位为ACK&…

Java 设置免登录请求接口被拦截问题

1、在设置免登录时&#xff0c;前端将请求的路由添加到白名单后&#xff0c;请求接口还是被拦截到了&#xff0c;将请求接口也设置后还是会被拦截跳转到登录页面 通过JAVA 注解 Anonymous 进行设置匿名访问就可以了

Docker 的常用命令

0 基本命令 概述 [root192 home]# docker --helpUsage: docker [OPTIONS] COMMANDA self-sufficient runtime for containersOptions:--config string Location of client configfiles (default "/root/.docker")-c, --context string Name of the context…

js中如何判断一个对象是否为空对象?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用 Object.keys()⭐ 使用 for...in 循环⭐ 使用 JSON.stringify()⭐ 使用 ES6 的 Object.getOwnPropertyNames()⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带…

windows本地认证

来自帅气学弟得经验 阅读流程 windows系统认证包括**本地交互式认证 **和 网络认证 交互式登录&#xff1a;向本地计算机或域账户确认用户的身份 网络登录&#xff1a;对用户尝试访问的网络服务或资源提供用户认证 若是本地用户本地认证需要了解**windows密码 **&#xff0c;…

【C++心愿便利店】No.5---构造函数和析构函数

文章目录 前言一、类的6个默认成员函数二、构造函数三、析构函数 前言 &#x1f467;个人主页&#xff1a;小沈YO. &#x1f61a;小编介绍&#xff1a;欢迎来到我的乱七八糟小星球&#x1f31d; &#x1f4cb;专栏&#xff1a;C 心愿便利店 &#x1f511;本章内容&#xff1a;类…

通过curl命令分析http接口请求各阶段的耗时等

目录 一、介绍二、功能1、-v 输出请求 响应头状态码 响应文本等信息2、-x 测试代理ip是否能在该网站使用3、-w 额外输出查看接口请求响应的消耗时间4、-o 将响应结果存储到文件里面5、-X post请求测试 (没测成功用的不多) 一、介绍 Curl是一个用于发送和接收请求的命令行工具和…

TCP/IP传输协议学习

了解完整的通信过程 1.发送方源终端设备的应用创建数据。 2.当数据在源终端设备中沿协议栈向下传递&#xff0c;对其分段和封装。 3.在协议栈网络接入层的介质上生成数据。 4.通过由介质和任意中间设备组成的网际层网络传输数据。 5.在目的终端设备中沿协议栈向上传递时对其…

用队列实现栈(C语言版本)

&#x1f388;个人主页:&#x1f388; :✨✨✨初阶牛✨✨✨ &#x1f43b;强烈推荐优质专栏: &#x1f354;&#x1f35f;&#x1f32f;C的世界(持续更新中) &#x1f43b;推荐专栏1: &#x1f354;&#x1f35f;&#x1f32f;C语言初阶 &#x1f43b;推荐专栏2: &#x1f354;…

ArcGIS 10.5安装教程!

软件介绍&#xff1a; ArcGIS Desktop 10.5中文特别版是一款功能强大的GSI专业电子地图信息编辑和开发软件&#xff0c;ArcGIS Desktop 包括两种可实现制图和可视化的主要应用程序&#xff0c;即 ArcMap 和 ArcGIS Pro。ArcMap 是用于在 ArcGIS Desktop 中进行制图、编辑、分析…