写点什么

Django REST 项目实战:在线中文字符识别

作者:TiAmo
  • 2023-04-26
    江苏
  • 本文字数:6574 字

    阅读完需:约 22 分钟

Django REST项目实战:在线中文字符识别

简介: Django REST 项目实战:在线中文字符识别


01、RESTful 概述

RESTful 架构风格最初由 Roy T. Fielding(HTTP/1.1 协议专家组负责人)在其 2000 年的博士学位论文中提出。HTTP 就是该架构风格的一个典型应用。从其诞生之日开始,它就因其可扩展性和简单性受到越来越多的架构师和开发者们的青睐。一方面,随着云计算和移动计算的兴起,许多企业愿意在互联网上共享自己的数据和功能;另一方面,在企业中,RESTful API 也逐渐受到重视。时至今日,RESTful 架构风格已成为企业级服务的标配。REST 即 Representational State Transfer 的缩写,译为“表现层状态转化”。REST 最大的几个特点为:资源、统一接口、URI 和无状态。所谓“资源”,就是网络上的一个实体,或者说是网络上的一个具体信息,它可以是一段文本、一张图片、一首歌曲等。资源通过某种载体反应其内容,文本可以用 txt 格式表现,也可以用 HTML 格式或 XML 格式表现,甚至可以采用二进制格式;图片可以用 JPG 格式表现,也可以用 PNG 格式表现;JSON 是现在最常用的资源表示格式。


在前面的企业门户网站实战项目中,为了能够动态的显示页面内容,使用了 Django 提供的模板机制,即在前端 HTML 页面中嵌入了大量的 Django 模板标签,这些标签并不是 HTML 的标签,而是需要通过后台 Django 服务器对这些标签进行解析再返回页面内容给前端。尽管利用 Django 模板标签,可以使得后端开发人员比较方便的对前端页面内容进行控制,但是这种处理方式导致各个模板文件不再是纯粹的 HTML 页面,而是嵌入了一堆浏览器无法直接识别的模板标签,前端设计人员在不熟悉 Django 的情况下无法对这些内容进行设计和修改。目前,很多大型 Web 项目的开发往往是采用一种前后端分离的合作方式,前端设计人员专注于页面和交互功能的实现,通过 HTML、CSS 和 JS 即可在浏览器端进行设计并且查看效果。后端开发人员仅处理前端发来的各种请求,并返回各请求对应的内容即可,其中后端开发人员不再需要关注页面的设计,而是通过双方约定好的 API 接口协议进行资源上传和接收。这种前后端分离、仅通过内容交换实现的 Web 架构即为 REST。


在前后端分离的应用模式中,后端仅返回前端所需要的数据,不再渲染 HTML 页面,不再控制前端的效果。前端用户看到什么效果、从后端请求的数据如何加载到前端中,这些都由前端决定。例如网页有网页的设计方式,手机 APP 有手机 APP 的处理方式,但无论哪种前端其所需要的数据基本相同,后端仅需开发同一套逻辑对外提供资源数据即可。


02、搭建框架

我们将采用 Django 来开发一个基于 RESTful 风格的项目实例:中文字符识别。


我们首先完成基础框架搭建。新建一个 ocr 文件夹用于存放项目,在该文件夹下分别建立三个子文件夹 frontend、ocr 和 app,其中 frontend 文件夹用于存放前端文件,包括 html、css、js 和 img 文件等,ocr 文件夹用于存放项目的配置文件,app 文件夹作为应用文件夹用于存放每个独立应用文件。参照 Django 项目目录结构,在各子文件夹下创建一些空文件和空文件夹,完整结构如图 1 所示。


接下来将单文件 Django 项目的各模块内容填入到指定的文件中。打开 settings.py 文件,添加代码如下:

import os# 设置项目根目录BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 加密签名SECRET_KEY = 'b!iohd&_vv@gmva5b6gq@k9t01_k^52uludvw8@h0)1fnez^8l'      DEBUG = True                 # 设置当前为调试模式INSTALLED_APPS = ['app']   # 添加应用ROOT_URLCONF = 'ocr.urls'  # 设置项目路由文件urls
复制代码

述代码将原 Django 项目中的必要部分剥离出来,旨在能够建立更轻量更易于理解的 Django 项目。打开 app 应用下的 views.py 文件,添加代码:

from django.http import HttpResponsedef home(request):    return HttpResponse('Hello World')
复制代码

通过导入的 HttpResponse 函数响应前端,返回内容为一个字符串。在 urls.py 文件中添加路由:

from django.urls import pathfrom app.views import homeurlpatterns = [path('', home, name='home')]
复制代码

上述代码将访问根路径与视图 home 函数进行绑定。最后,在项目根目录下的 manage.py 文件中添加运行代码:

if __name__ == '__main__':    import sys    import django    import os    DJANGO_SETTINGS_MODULE = 'ocr.settings'    # 设置环境变量    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'ocr.settings')    django.setup()    from django.core.management import execute_from_command_line    execute_from_command_line(sys.argv)
复制代码

其中注意,我们将所有的配置全部放置在单文件脚本中,使用 settings.configure(**settings)来加载配置项,此处我们将所有的配置项放置在了独立的 settings.py 文件中。为了能够加载该配置文件,需要采用 django.setup()函数进行设置,该函数会自动查询环境变量 DJANGO_SETTINGS_MODULE 的值,把这个值作为配置文件的路径。保存所有修改后,在终端中运行命令:

python manage.py runserver
复制代码

然后打开浏览器访问 127.0.0.1:8000,查看页面是否输出对应的字符串“Hello World”。


03、前端开发

我们拟实现一个在线中文字符识别系统,用户在网页上上传图片,然后通过 Ajax 技术将图片传输至后台服务器,后台服务器调用中文字符识别算法将图片中的文字识别出来,并以 JSON 字符串的形式返回结果给前端页面进行显示。整个开发过程分为前端和后端,后端不再使用 Django 提供的模板机制来控制前端页面的执行逻辑,前后端之间所有的交互全部通过 API 接口进行。由于采用了前后端分离的机制,因此,前端开发人员可以使用纯 HTTP 和 JS 来开发页面和交互逻辑,并且能够在不借助后端的情况下运行页面查看效果。本小节先进行前端开发。


前端所有的开发文件全部放置在 frontend 文件夹中。为了程序美观,本实例依然采用 Bootstrap 框架设计页面。将 Bootstrap 包中的 bootstrap.min.css、jquery.min.js 和 bootstrap.min.js 文件按照文件类型分别放置在 frontend/css 和 frontend/js 文件夹中,然后在 img 文件夹下放置一张名为 sample.jpg 的图片文件用于展示图像显示区域。在 css 文件夹下额外新建一个空的 style.css 文件,该文件将作为本实例的个性化样式定制文件使用。


接下来开始编辑前端页面 index.html。首先设置页面标题 title 和元信息 meta,然后在页面头部引入必要的 css 和 js 文件:

<!DOCTYPE html><html lang="zh-CN"><head>    <meta charset="utf-8">    <meta http-equiv="X-UA-Compatible" content="IE=edge">    <meta name="viewport" content="width=device-width, initial-scale=1">    <title>在线中文字符识别</title>    <link href="css/bootstrap.min.css" rel="stylesheet">    <link href="css/style.css" rel="stylesheet">    <script src="js/jquery.min.js"></script>    <script src="js/bootstrap.min.js"></script></head><body></body></html>
复制代码

在页面部分采用 Bootstrap 栅格结构进行布局,主要分为左右两部分,各占 6 个栅格。左侧用来上传待识别的图像并显示,右侧用来显示识别结果。详细代码如下:

<div class="container">    <!-- 标题 -->    <div class="row">        <div class="col-lg-12">            <p class="text-center h1">                在线中文字符识别            </p>        </div>    </div>    <!-- 分隔符 -->    <div class="hr">        <hr />    </div>    <!-- 主体内容 -->    <div class="row">        <br>        <!-- 图片上传 -->        <div class="col-md-6">            <img id="photoIn" src="img/sample.jpg" class="img-responsive">            <input type="file" id="photo" name="photo" />        </div>        <!-- 运行结果 -->        <div class="col-md-6">            <div class="col-md-12">                <textarea id="output" disabled class="form-control" rows="5">                    </textarea>            </div>            <br>            <div class="col-md-12">                <p class="text-center h4">识别结果</p>            </div>        </div>    </div>    <br>    <div class="row">        <div class="text-center">            <button type="button" id="recognition" class="btn btn-primary">识别</button>        </div>    </div></div>
复制代码

在 style.css 文件中添加分割线对应的样式设计:

div.hr {    height: 3px;    background: #818080;}div.hr hr {    display: none;}
复制代码

为了能够实现图像浏览和上传的功能,需要使用 js 来实现。具体的,在部分末尾添加代码:

<script>    $(function () {        $('#photo').on('change', function () {            var r = new FileReader();            f = document.getElementById('photo').files[0];            r.readAsDataURL(f);            r.onload = function (e) {                document.getElementById('photoIn').src = this.result;            };        });    });</script>
复制代码

接下来,在前端页面中继续添加代码完成图像向后端的传输以及获取到后端发来的结果后的显示处理:

<!-- 图像发送至后台服务器进行识别 --><script>    $('#recognition').click(function () {        formdata = new FormData();        var file = $("#photo")[0].files[0];        formdata.append("image", file);        $.ajax({            url: '/ocr/',         // 调用Django服务器计算函数            type: 'POST',         // 请求类型            data: formdata,            dataType: 'json',     // 期望获得的响应类型为json            processData: false,            contentType: false,            success: ShowResult   // 在请求成功之后调用该回调函数输出结果        })    })</script><!-- 返回结果显示 --><script>    function ShowResult(data) {        output.value = data['output'];    }</script>
复制代码

图像的传输采用了 Ajax 技术,当用户单击“识别”按钮时将图像数据封装到 formdata 变量并发送至后端,发送地址为'/ocr/',发送方式为 POST。收到结果后执行 ShowResult 函数,将输出文本的值改为识别到的文字信息。


保存所有修改后,用浏览器直接打开 index.html 页面,单击“浏览”按钮,选择一张待识别的图片进行上传,可以看到选择的图片显示在指定位置,如图 2 所示。


到这里我们发现整个的前端设计和开发不再依赖后端服务器,并且由于页面没有嵌入 Django 模板标签,因此可以直接被浏览器解析和运行。这种前后端分离的开发模式可以极大的提高团队开发人员的沟通效率,使得项目的协同合作更加方便。

04、后端开发


我们继续将对后端进行开发。一般情况下,采用前后端分离机制以后前端静态资源(html 页面、css 样式文件、jpg 图片等)会采用额外的前端服务器来提供静态文件服务。我们为了简化服务器的搭建和使用,依然使用 Django 来提供静态文件服务,将所有的静态资源例如 css、js 和 jpg 图片文件等按照文件夹路径创建对应的视图处理函数,以文件读取方式获取文件内容并通过 HttpResponse 返回。


在 views.py 文件中添加代码如下:

def read_css(request, filename):    with open('frontend/css/{}'.format(filename), 'rb') as f:        css_content = f.read()    print('css文件')    return HttpResponse(content=css_content, content_type='text/css')def read_js(request, filename):    with open('frontend/js/{}'.format(filename), 'rb') as f:        js_content = f.read()    print('js文件')    return HttpResponse(content=js_content,                        content_type='application/JavaScript')def read_img(request, filename):    with open('frontend/img/{}'.format(filename), 'rb') as f:        img_content = f.read()    print('img文件')    return HttpResponse(content=img_content, content_type='image/jpeg')
复制代码

上述代码分别创建 js、css 和 jpg 文件访问的视图处理函数,然后在 urls.py 文件中设置访问路由:

from app.views import read_css, read_js, read_imgurlpatterns = [    ...其他路由...    path('css/<str:filename>', read_css, name='read_css'),    path('js/<str:filename>', read_js, name='read_js'),    path('img/<str:filename>', read_img, name='read_img'),]
复制代码


def home(request):    with open('frontend/index.html','rb') as f:        html = f.read()    return HttpResponse(html)
复制代码

通过这种方式,可以使得在不改变前端代码的情况下能够正确的提供静态资源请求服务。重新编辑 views.py 中的 home 函数:


同样的,html 页面也以文件读取方式获取内容并通过 HttpResponse 返回。保存所有修改后启动项目:

python manage.py runserver
复制代码

打开浏览器查看页面效果。可以发现页面效果与使用浏览器直接打开 index.html 页面相同。这说明,后端服务器正确的充当了静态资源服务器的角色,在不使用 Django 模板标签的情况下能够实现前端页面的正确渲染。


最后需要开发中文字符识别对应的 Ajax 视图处理函数。为了实现中文字符识别,我们采用开源库 Tesseract-OCR 来进行文字识别任务。Tesseract 是惠普布里斯托实验室在 1985~1995 年间开发的一个开源的字符识别引擎,曾经在 1995 UNLV 精确度测试中名列前茅。2005 年,惠普将其对外开源。2006 年由 Google 对 Tesseract 进行改进并对其进行深度优化。


Tesseract 的下载网址为:


https://digi.bib.uni-mannheim.de/tesseract/。根据系统版本进行选择,如果使用 Windows 64 位系统,可以下载 windows 64 对应的版本:tesseract-ocr-w64-setup-v4.1.0.20190314.exe。下载完成后双击进入安装界面,展开 Additional language data,勾选 arabic 和 Chinese simplified 使得能够同时支持阿拉伯数字和简体中文字符的识别。


为了能够在 Python 中使用该引擎库,需要安装对应的 Python 库:

pip install pytesseract
复制代码

然后修改 pytesseract 库文件,在 pytesseract 安装包中找到 pytesseract.py 文件,修改 tesseract_cmd 字段的值,将 tesseractOCR 的安装目录填入其中:

tesseract_cmd = r'<tesseractOCR安装目录>\tesseract.exe'
复制代码

通过上述修改,就可以使得 Python 能够找到本地的文字识别程序完成识别。接下来在 views.py 文件中添加视图处理函数,完整代码如下:

import numpy as np    import urllib         import numpy as np    import urllib         import json          import cv2          import pytesseractfrom PIL import Imageimport os  from django.views.decorators.csrf import csrf_exempt from django.http import JsonResponse  def read_image(stream=None):    data_temp = stream.read()    image = np.asarray(bytearray(data_temp), dtype="uint8")    image = cv2.imdecode(image, cv2.IMREAD_COLOR)    return image@csrf_exempt  # 用于规避跨站点请求攻击def ocrDetect(request):    result = {"code": None}      if request.method == "POST":        if request.FILES.get("image", None) is not None:              img = read_image(stream=request.FILES["image"])        # OpenCV转PIL        img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))        # 执行识别        code = pytesseract.image_to_string(img, lang='chi_sim')        result.update({"output": code})    return JsonResponse(result)
复制代码

通过客户端浏览器上传的图像照片进行识别处理然后返回结果,不同之处在于此处返回的结果是以 JSON 字符串形式给出,不需要再额外的进行图像编码。识别部分主要采用 pytesseract.image_to_string 函数进行识别,其中 lang='chi_sim'表示当前识别中文简体字符。


最后,在 urls.py 文件的 urlpatterns 字段中添加对应的路由:

path('ocr/', ocrDetect, name='ocrDetect'),  # 在线中文字符识别api
复制代码

完成所有修改后保存并运行项目,最终识别效果如图 4 所示。


经过测试,tesseract—OCR 对于印刷体中文字符效果较好,对于手写体中文字符效果一般。如果需要更高的检测精度和更好的适应性,则需要进一步优化算法。

发布于: 刚刚阅读数: 2
用户头像

TiAmo

关注

有能力爱自己,有余力爱别人! 2022-06-16 加入

CSDN全栈领域优质创作者,万粉博主;阿里云专家博主、星级博主、技术博主、阿里云问答官,阿里云MVP;华为云享专家;华为Iot专家;亚马逊人工智能自动驾驶(大众组)吉尼斯世界纪录获得者

评论

发布
暂无评论
Django REST项目实战:在线中文字符识别_django_TiAmo_InfoQ写作社区