AIOCR:AI文字识别web集成系统@Kylin+RISCV

基于kotti_ai的AI文字识别web集成系统

AIOCR项目目标:

在Kylin+RISCV搭建一个kotti_ai构架的网站,提供AI OCR文字识别web服务。

二期目标:在AIOCR的基础上提供chatgpt和文心一言等大模型调用,建立综合大模型应用平台。

功能:

1 AI 文字识别功能即ocr推理

2 web集成功能即web内容管理系统

技术实现

ocr推理部分

飞桨框架安装,参见https://blog.csdn.net/skywalk8163/article/details/136610462

ocr推理,参见:飞桨AI应用@riscv OpenKylin-CSDN博客

web框架部分

Kotti_ai框架调通,参见:安装调试kotti_ai:AI+互联网企业级部署应用软件包@riscv+OpenKylin-CSDN博客

为kotti_ai添加ocr文字识别部分,见下面。

实现难点:

1 飞桨框架在riscv平台的编译安装,碰到问题较多,索性都一一解决了。

2 ocr推理部分,以为会比较顺利的onnx推理没有调通,转而使用飞桨推理

3 kotti_ai安装,因为kotti本身的复杂性,安装时需要反复修改和纠错。

4 ocr与kotti_ai的连通

ocr与kotti_ai的连通

单独调通orc

根据Paddle2ONNX里面的源码infer.py,将ocr部分写成适合调用的函数,比如写入aiocr.py进行测试。

过程略。

将ocr调用功能写入kotti_ai

写并放置aiocr.py文件

将调好ocr调用函数的aiocr.py文件,放置在kotti_ai/kotti_ai目录:

import os
import sys

import cv2
import copy
import numpy as np

# import sys
# sys.path.insert(0, '.')
print("ok1")
from .utils import predict_rec 
from .utils import predict_det 
from .utils import predict_cls

#import .utils.predict_rec as predict_rec
#import .utils.predict_det as predict_det
#import .utils.predict_cls as predict_cls


import argparse


def str2bool(v):
    return v.lower() in ("true", "t", "1")


def init_args():
    parser = argparse.ArgumentParser()
    # params for text detector
    parser.add_argument("--image_path", type=str)
    parser.add_argument("--det_algorithm", type=str, default='DB')
    parser.add_argument("--det_model_dir", type=str)
    parser.add_argument("--det_limit_side_len", type=float, default=960)
    parser.add_argument("--det_limit_type", type=str, default='max')

    # DB params
    parser.add_argument("--det_db_thresh", type=float, default=0.3)
    parser.add_argument("--det_db_box_thresh", type=float, default=0.6)
    parser.add_argument("--det_db_unclip_ratio", type=float, default=1.5)
    parser.add_argument("--max_batch_size", type=int, default=10)
    parser.add_argument("--use_dilation", type=str2bool, default=False)
    parser.add_argument("--det_db_score_mode", type=str, default="fast")

    parser.add_argument("--rec_algorithm", type=str, default='CRNN')
    parser.add_argument("--rec_model_dir", type=str)
    parser.add_argument("--rec_image_shape", type=str, default="3, 32, 320")
    parser.add_argument("--rec_batch_num", type=int, default=6)
    parser.add_argument("--max_text_length", type=int, default=25)
    parser.add_argument(
        "--rec_char_dict_path",
        type=str,
        default="./utils/doc/ppocr_keys_v1.txt")
    parser.add_argument("--use_space_char", type=str2bool, default=True)
    parser.add_argument(
        "--vis_font_path", type=str, default="./utils/doc/fonts/simfang.ttf")
    parser.add_argument("--drop_score", type=float, default=0.5)

    # params for text classifier
    parser.add_argument("--use_angle_cls", type=str2bool, default=True)
    parser.add_argument("--cls_model_dir", type=str)
    parser.add_argument("--cls_image_shape", type=str, default="3, 48, 192")
    parser.add_argument("--label_list", type=list, default=['0', '180'])
    parser.add_argument("--cls_batch_num", type=int, default=6)
    parser.add_argument("--cls_thresh", type=float, default=0.9)

    parser.add_argument("--use_paddle_predict", type=str2bool, default=False)
    parser.add_argument("--seed", type=int, default=42)
    return parser.parse_args(["--seed", "42"])

def preprocess_boxes(dt_boxes, ori_im, FLAGS=None):
    def get_rotate_crop_image(img, points):
        assert len(points) == 4, "shape of points must be 4*2"
        img_crop_width = int(
            max(
                np.linalg.norm(points[0] - points[1]),
                np.linalg.norm(points[2] - points[3])))
        img_crop_height = int(
            max(
                np.linalg.norm(points[0] - points[3]),
                np.linalg.norm(points[1] - points[2])))
        pts_std = np.float32([[0, 0], [img_crop_width, 0],
                              [img_crop_width, img_crop_height],
                              [0, img_crop_height]])
        M = cv2.getPerspectiveTransform(points, pts_std)
        dst_img = cv2.warpPerspective(
            img,
            M, (img_crop_width, img_crop_height),
            borderMode=cv2.BORDER_REPLICATE,
            flags=cv2.INTER_CUBIC)
        dst_img_height, dst_img_width = dst_img.shape[0:2]
        if dst_img_height * 1.0 / dst_img_width >= 1.5:
            dst_img = np.rot90(dst_img)
        return dst_img

    def sorted_boxes(dt_boxes):
        num_boxes = dt_boxes.shape[0]
        sorted_boxes = sorted(dt_boxes, key=lambda x: (x[0][1], x[0][0]))
        _boxes = list(sorted_boxes)

        for i in range(num_boxes - 1):
            if abs(_boxes[i + 1][0][1] - _boxes[i][0][1]) < 10 and \
                    (_boxes[i + 1][0][0] < _boxes[i][0][0]):
                tmp = _boxes[i]
                _boxes[i] = _boxes[i + 1]
                _boxes[i + 1] = tmp
        return _boxes

    img_crop_list = []
    dt_boxes = sorted_boxes(dt_boxes)
    for bno in range(len(dt_boxes)):
        tmp_box = copy.deepcopy(dt_boxes[bno])
        img_crop = get_rotate_crop_image(ori_im, tmp_box)
        img_crop_list.append(img_crop)
    return dt_boxes, img_crop_list


def postprocess(dt_boxes, rec_res, FLAGS=None):
    filter_boxes, filter_rec_res = [], []
    for box, rec_result in zip(dt_boxes, rec_res):
        text, score = rec_result
        if score >= FLAGS.drop_score:
            filter_boxes.append(box)
            filter_rec_res.append(rec_result)

    return filter_boxes, filter_rec_res

def ai_ocr(FLAGS=None, img=None):


    # 本地测试
    img = cv2.imread(FLAGS.image_path)
    # if img == None:
    #     return "None"
    # img = base64.b64encode(img)

    ori_im = img.copy()

    # text detect
    text_detector = predict_det.TextDetector(FLAGS)
    dt_boxes = text_detector(img)
    dt_boxes, img_crop_list = preprocess_boxes(dt_boxes, ori_im, FLAGS=FLAGS)

    # text classifier
    if FLAGS.use_angle_cls:
        text_classifier = predict_cls.TextClassifier(FLAGS)
        img_crop_list, angle_list = text_classifier(img_crop_list)

    # text recognize
    text_recognizer = predict_rec.TextRecognizer(FLAGS)
    rec_res = text_recognizer(img_crop_list)

    _, filter_rec_res = postprocess(dt_boxes, rec_res, FLAGS=FLAGS)
    ocrtext = " "
    for text, score in filter_rec_res:
        ocrtext += text
        print("{}, {:.3f}".format(text, score))
    print("Finish!")
    print(ocrtext)
    return ocrtext

if __name__ == "__main__":
    FLAGS = init_args()
    FLAGS.cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer"
    FLAGS.rec_model_dir="./inference/ch_PP-OCRv2_rec_infer"
    FLAGS.det_model_dir="./inference/ch_PP-OCRv2_det_infer"
    FLAGS.image_path="./images/wahaha.jpg"
    # FLAGS.image_path="./images/lite_demo.png"
    FLAGS.use_paddle_predict="True"

    ai_ocr(FLAGS=FLAGS)

安装新的kotti_ai包

进入kotti_ai主目录,执行python setup.py develop 安装

使用develop选项,可以使用开发模式,修改源代码都会即时成效,不用再次安装。

测试

进入python,执行from kotti_ai.aiocr import ai_ocr ,如果通过,则证明aiocr.py文件写的正确。

最终测试代码为:

from kotti_ai.aiocr import ai_ocr
from kotti_ai.aiocr import init_args

FLAGS = init_args()
FLAGS.cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer"
FLAGS.rec_model_dir="./inference/ch_PP-OCRv2_rec_infer"
FLAGS.det_model_dir="./inference/ch_PP-OCRv2_det_infer"
FLAGS.image_path="./images/lite_demo.png"
FLAGS.use_paddle_predict="True"

ai_ocr(FLAGS=FLAGS)

在kotti_ai中添加aiocr网页处理部分

aiocr.py文件中,ai_ocr函数修改成:

def ai_ocr(FLAGS=None, img=None):


    # 本地测试
    if img == None:
        # return "None"
        img = cv2.imread(FLAGS.image_path)
    # img = base64.b64encode(img)

edit.py修改:

            # out = ppshitu(im=im)

            from kotti_ai.aiocr import ai_ocr
            from kotti_ai.aiocr import init_args

            FLAGS = init_args()
            FLAGS.cls_model_dir="./inference/ch_ppocr_mobile_v2.0_cls_infer"
            FLAGS.rec_model_dir="./inference/ch_PP-OCRv2_rec_infer"
            FLAGS.det_model_dir="./inference/ch_PP-OCRv2_det_infer"
            FLAGS.image_path="./images/lite_demo.png"
            FLAGS.use_paddle_predict="True"

            out = ai_ocr(FLAGS=FLAGS, img=im)

            print("====out:", out)
            context.out = str(out)

启动kotti_ai

pserve development.ini

服务端口为5000

登录用户名admin 口令qwerty

上传图片测试文字识别,发现有报错,一一解决。

项目成功运行

经过紧张的调试,项目终于成功运行!

调试

报错AttributeError: 'str' object has no attribute 'decode'

File "/usr/lib/python3.8/site-packages/Kotti-2.0.9-py3.8.egg/kotti/security.py", line 103, in __init__
    password = get_principals().hash_password(password)
  File "/usr/lib/python3.8/site-packages/Kotti-2.0.9-py3.8.egg/kotti/security.py", line 564, in hash_password
    return bcrypt.hashpw(password, salt).decode("utf-8")
AttributeError: 'str' object has no attribute 'decode'

修改代码 即可

sudo vi /usr/lib/python3.8/site-packages/Kotti-2.0.9-py3.8.egg/kotti/security.py

        return bcrypt.hashpw(password, salt)
        # return bcrypt.hashpw(password, salt).decode("utf-8")

添加图片报错

ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()

 - Expression: "link(context, request)"
 - Filename:   ... /Kotti-2.0.9-py3.8.egg/kotti/templates/edit/el-parent.pt
 - Location:   (line 10: col 8)
 - Source:     ${link(context, request)}
                 ^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "link(context, request)"
 - Filename:   ... ages/Kotti-2.0.9-py3.8.egg/kotti/templates/editor-bar.pt
 - Location:   (line 24: col 14)
 - Source:     ${link(context, request)}
                 ^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "api.render_template('kotti:templates/editor-bar.pt')"
 - Filename:   ... ges/Kotti-2.0.9-py3.8.egg/kotti/templates/view/master.pt
 - Location:   (line 37: col 24)
 - Source:     ... ce="api.render_template('kotti:templates/editor-bar.pt')"></ ...
                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Expression: "api.macro('kotti:templates/view/master.pt')"
 - Filename:   /home/skywalk/kotti_ai/kotti_ai/templates/image.pt
 - Location:   (line 3: col 23)
 - Source:     ... :use-macro="api.macro('kotti:templates/view/master.pt')">
                               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 - Arguments:  view: <NoneType ('None',) at 0x3cfc48>
               renderer_name: kotti:templates/edit/el-parent.pt
               renderer_info: <RendererHelper ('None',) at 0x3e13e06400>
               context: <AImage ('test',) at 0x3e13fd3580>
               request: <Request ('None',) at 0x3e2005a790>
               req: <Request ('None',) at 0x3e2005a790>
               get_csrf_token: <partial ('None',) at 0x3e13f02310>
               api: <TemplateAPI ('None',) at 0x3e13fd30d0>
               link: <LinkRenderer ('None',) at 0x3f8848fc40>
               target_language: <NoneType ('None',) at 0x3cfc48>
               repeat: <RepeatDict ('None',) at 0x3e13fc1c70>

估计是返回值没有str导致的。原来img是个列表,所以aiocr.py文件中修改成img == []

报错找不到模型文件


将代码里的模型文件的配置,改为框架的相对路径,即:
```
            FLAGS = init_args()
            FLAGS.cls_model_dir="./kotti_ai/inference/ch_ppocr_mobile_v2.0_cls_infer"
            FLAGS.rec_model_dir="./kotti_ai/inference/ch_PP-OCRv2_rec_infer"
            FLAGS.det_model_dir="./kotti_ai/inference/ch_PP-OCRv2_det_infer"
            FLAGS.image_path="./kotti_ai/images/lite_demo.png"
            FLAGS.use_paddle_predict="True"
```

报错找不到rec_char_dict_path txt文件


在代码里将其改为框架的相对路径
parser.add_argument(
        "--rec_char_dict_path",
        type=str,
        default="./kotti_ai/utils/doc/ppocr_keys_v1.txt")

报错__iterator = get('eval', eval)(_lookup_attr(getname('context'), 'out'))

  File "/usr/local/lib/python3.8/dist-packages/chameleon/template.py", line 200, in render
    self._render(
  File "/tmp/tmpv4xn_ul5/image_bbceef85f35e624757730558bb775d8e.py", line 375, in render
    __m(__stream, econtext.copy(), rcontext, __i18n_domain, __i18n_context, target_language)
  File "/tmp/tmp5dtqmvp7/master_21123e986705ec1c4189aca762f798cd.py", line 773, in render_main
    __slot_content(__stream, econtext.copy(), rcontext)
  File "/tmp/tmpv4xn_ul5/image_bbceef85f35e624757730558bb775d8e.py", line 248, in __fill_content
    __iterator = get('eval', eval)(_lookup_attr(getname('context'), 'out'))
  File "<string>", line None
SyntaxError: <no detail available>

    经过查看跟踪信息,发现已经正确文字识别了。是模板文件那个地方报错了template: /home/skywalk/kotti_ai/kotti_ai/templates/image.pt

修改该文件,将原来的循环画表语句去掉,直接显示:

<p><h2>OCR result:</h2>${context.out}</p>

最终网站起来拉!

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【链表】算法例题

目录 八、 链表 57. 环形链表 ① 58. 两数相加 ② √ 59. 合并两个有序链表 ① √- 60. 随机链表的复制 ② 61. 反转链表II ② 62. K个一组翻转链表 ③ 63. 删除链表的倒数第N个结点 ② √- 64. 删除排序链表中的重复元素II ② √- 65. 旋转链表 ② √- 66. 分隔链…

腾讯云服务器如何购买省钱?2024年优惠券和优惠活动整理

腾讯云代金券领取渠道有哪些&#xff1f;腾讯云官网可以领取、官方媒体账号可以领取代金券、完成任务可以领取代金券&#xff0c;大家也可以在腾讯云百科蹲守代金券&#xff0c;因为腾讯云代金券领取渠道比较分散&#xff0c;腾讯云百科txybk.com专注汇总优惠代金券领取页面&am…

基于torch.compile和gptfast代码风格实现ChatGLM模型推理加速

目录 一、ChatGLM模型代码重构迁移 二、推理的代码重构 三、效果分析对比 参考文章 torch2.0发布以后模型训练和推理可以实现一行代码加速&#xff0c;试用之后发现效果并不明显。随后gptfast项目也发布&#xff0c;表明它确实是可以实现模型推理的加速&#xff0c;看来之前…

c/c++ 深拷贝和浅拷贝

深拷贝与浅拷贝 深拷贝&#xff08;Deep Copy&#xff09;和浅拷贝&#xff08;Shallow Copy&#xff09;是对象复制的两种不同方式&#xff0c;它们涉及到对象成员数据的复制方式和内存管理。 浅拷贝&#xff08;Shallow Copy&#xff09;&#xff1a; 浅拷贝是指将一个对象的…

投资400亿美元!人工智能或将诞生超级大国

据外媒报道&#xff0c;沙特阿拉伯政府计划设立约 400 亿美元的基金来投资人工智能&#xff0c;如此规模的基金将成为迄今为止全球最大的专注于人工智能发展的基金之一。 据知情人士透露&#xff0c;该基金长期以来一直被硅谷用来为科技初创企业提供资金&#xff0c;甚至一度是…

在线教育话术(1W字精选)

产品结构图 Nginx实现代理 问&#xff1a;我们在本机的host文件中配置了域名映射&#xff0c;都是同一个服务器。我们只需要输入对应的域名就可以到对应的界面&#xff0c;这是怎么实现的&#xff1f; 答&#xff1a;主要就是通过Nginx反向代理来实现的&#xff0c;Nginx会先…

【go语言开发】性能分析工具pprof使用

本文主要介绍如何在项目中使用pprof工具。首先简要介绍pprof工具的作用&#xff1b;然后介绍pprof的应用场景&#xff0c;主要分为工具型应用和服务型应用。最后数据分析项目&#xff0c;先采集项目信息&#xff0c;再可视化查看 文章目录 前言应用场景工具型应用服务型应用 数…

基于补丁方式修复 nginx漏洞 缓冲区错误漏洞(CVE-2022-41741)、越界写入漏洞(CVE-2022-41742)

nginx1.22.0版本漏洞 CVE-2022-41741 、CVE-2022-41742 漏洞描述 1、nginx 缓冲区错误漏洞(CVE-2022-41741) 此插件基于版本检测&#xff0c;有可能误报&#xff0c;未开启 MP4 模块的nginx属于误报&#xff0c;请忽略该漏洞。Nginx是美国Nginx公司的一款轻量级Web服务器/反…

Jmeter Ultimate Thread Group 和 Stepping Thread Group

线程组&#xff1a;使用复杂场景的性能测试 有时候我们做性能测试时&#xff0c;只依靠自带的线程组&#xff0c;显示满足不了性能测试中比较复杂的场景&#xff0c;下面这两种线程组可以帮助你很好的完成复杂的场景 第一种&#xff1a;Stepping Thread Group 在取样器错误后…

2024年【安全员-C证】考试资料及安全员-C证新版试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 安全员-C证考试资料是安全生产模拟考试一点通生成的&#xff0c;安全员-C证证模拟考试题库是根据安全员-C证最新版教材汇编出安全员-C证仿真模拟考试。2024年【安全员-C证】考试资料及安全员-C证新版试题 1、【多选题…

Java基础入门day17

day17 复习二分查找java package com.saas; ​ public class BinarySearch { ​public static void main(String[] args) {int[] nums {12, 21, 33, 77, 89, 90}; ​System.out.println(binarySearch(nums, 21));} ​public static int binarySearch(int[] arrs, int target)…

springBoot项目,无配置中心,怎么实现类似功能

实现EnvironmentPostProcessor import cn.hutool.http.HttpUtil; import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.boot.env.YamlPropertySourceLoader; import org.springfr…

springboot企业级抽奖项目业务一(登录模块)

开发流程 该业务基于rouyi生成好了mapper和service的代码&#xff0c;现在需要在controller层写接口 实际操作流程&#xff1a; 看接口文档一>controller里定义函数一>看给出的工具类一>补全controller里的函数一>运行测试 接口文档 在登录模块有登录和登出方…

在windows上安装Jenkins

jenkins安装 下载jenkins 官网&#xff1a;Jenkins download and deployment 官方文档说明&#xff1a;Jenkins User Documentation 安装jenkins1.点击下载好的安装包&#xff0c;点击Next 2.选择一个安装路径 如果系统是windows家庭版打不开策略就创建一个txt文件&#xff0c…

Android分区存储到底该怎么做

文章目录 一、Android存储结构二、什么是分区存储&#xff1f;三、私有目录和公有目录三、存储权限和分区存储有什么关系&#xff1f;四、我们应该该怎么做适配&#xff1f;4.1、利用File进行操作4.2、使用MediaStore操作数据库 一、Android存储结构 Android存储分为内部存储和…

NBlog Java定时任务-备份MySQL数据

NBlog部署维护流程记录&#xff08;持续更新&#xff09;&#xff1a;https://blog.csdn.net/qq_43349112/article/details/136129806 为了避免服务器被攻击&#xff0c;给博客添加了一个MySQL数据备份功能。 此功能是配合博客写的&#xff0c;有些方法直接用的已有的&#xf…

Matlab中inv()函数的使用

在Matlab中&#xff0c;inv()函数是用来求解矩阵的逆矩阵的函数。逆矩阵是一个与原矩阵相乘后得到单位矩阵的矩阵。在数学中&#xff0c;矩阵A的逆矩阵通常用A^-1表示。 什么是逆矩阵 在数学中&#xff0c;对于一个n阶方阵A&#xff0c;如果存在一个n阶方阵B&#xff0c;使得…

Gradio官方文档

文章目录 构建您的第一个demo分享您的demo进度条受密码保护的应用程序The Interface class&#xff08;接口类&#xff09;Components Attributes&#xff08;组件属性&#xff09;多个输入和输出组件图像示例嵌套列表描述性内容手风琴中的附加输入The 4 Kinds of Gradio Inter…

Android: Gradle 命令

一、查看整个项目依赖传递关系 x.x.x (*) 该依赖已经有了&#xff0c;将不再重复依赖。x.x.x -> x.x.x 该依赖的版本被箭头所指的版本代替。x.x.x -> x.x.x(*) 该依赖的版本被箭头所指的版本代替&#xff0c;并且该依赖已经有了&#xff0c;不再重复依赖。 1. gradlew ap…

冰岛人[天梯赛]

文章目录 题目描述思路AC代码 题目描述 输入样例 15 chris smithm adam smithm bob adamsson jack chrissson bill chrissson mike jacksson steve billsson tim mikesson april mikesdottir eric stevesson tracy timsdottir james ericsson patrick jacksson robin patrickss…