關注「WeiyiGeek」點我,點我
設為「特別關注」,每天帶你在B站玩轉網路安全運維、應用開發、物聯網IOT學習!
希望各位看友【關注、點贊、評論、收藏、投幣】,助力每一個夢想。
文章目錄
0x00 快速瞭解
0x01 安裝部署
0x02 實踐案例
0x03 入坑出坑
Q: 什麼是 EasyOCR ?
描述: EasyOCR 是一個用於從影象中提取文字的 python 模組, 它是一種通用的 OCR,既可以讀取自然場景文字,也可以讀取檔案中的密集文字。目前支援 80 多種語言和所有流行的書寫指令碼,包括:拉丁文、中文、阿拉伯文、梵文、西里爾文等。
Q: 使用 EasyOCR 可以幹什麼?
描述: EasyOCR 支援兩種方式執行一種是常用的CPU,而另外一種是需要GPU支援並且需安裝CUDA環境, 我們使用其可以進行圖片中語言文字識別, 例如小程式裡圖片識別、車輛車牌識別(
即車債管理系統
)。
Tips: 在其官網有demo演示,我們可以使用其進行簡單圖片ocr識別,地址為https://www.jaided.ai/easyocr/
或者 https://huggingface.co/spaces/tomofi/EasyOCR
EasyOCR Framework
溫馨提示: 圖中 灰色插槽是可更換的淺藍色模組的預留位置,我們可以重構程式碼以支援可交換的檢測和識別演演算法 api
官網地址: https://www.jaided.ai/easyocr/
專案地址: https://github.com/JaidedAI/EasyOCR
實踐專案原始碼地址:https://github.com/WeiyiGeek/SecOpsDev/tree/master/Project/Python/EasyOCR/Travelcodeocr
檔案原文地址: https://www.bilibili.com/read/cv16911816
實踐視訊地址: https://www.bilibili.com/video/BV1nY4y1x7JG
溫馨提示: 該專案基於來自多篇論文和開源儲存庫的研究和程式碼,所有深度學習執行都基於 Pytorch ,識別模型是 CRNN 它由 3 個主要部分組成:特徵提取(我們目前使用 Resnet )和 VGG、序列標記( LSTM )和解碼( CTC )。 ❤️
環境依賴
注意事項:
$ nvidia-smi -l
Fri May 27 14:57:57 2022
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 465.19.01 Driver Version: 465.19.01 CUDA Version: 11.3 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|===============================+======================+======================|
| 0 NVIDIA Tesla V1... Off | 00000000:1B:00.0 Off | 0 |
| N/A 41C P0 36W / 250W | 0MiB / 32510MiB | 0% Default |
| | | N/A |
+-------------------------------+----------------------+----------------------+
Note 2.最好在Python 3.8 x64 位系統上安裝使用 easyocr , 非常注意其不支援32位元的python。
Note 3.對於 Windows,請先按照 https://pytorch.org 的官方說明安裝 torch 和 torchvision。 在 pytorch 網站上,請務必選擇您擁有的正確 CUDA 版本。 如果您打算僅在 CPU 模式下執行,請選擇 CUDA = None。
描述: 此處我們使用 pip 安裝 easyocr 使用以及通過官方提供的Dockerfile。
pip 方式
對於最新的穩定版本:
pip install easyocr -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
對於最新的開發版本:
pip install git+git://github.com/jaidedai/easyocr.git
Dockerfile
描述: 由於國內網路環境因素, 此處我將官方提供的Dockerfile稍作更改。
$ cd /opt/images/easyocr && git clone https://github.com/JaidedAI/EasyOCR.git --depth=1
$ ls
Dockerfile EasyOCR
$ cat Dockerfile
# pytorch OS is Ubuntu 18.04
FROM pytorch/pytorch
LABEL DESC="EasyOCR Enviroment Build with Containerd Images"
ARG service_home="/home/EasyOCR"
# Enviroment && Software
RUN sed -i -e "s#archive.ubuntu.com#mirrors.aliyun.com#g" -e "s#security.ubuntu.com#mirrors.aliyun.com#g" /etc/apt/sources.list && \
apt-get update -y && \
apt-get install -y \
libglib2.0-0 \
libsm6 \
libxext6 \
libxrender-dev \
libgl1-mesa-dev \
git \
vim \
# cleanup
&& apt-get autoremove -y \
&& apt-get clean -y \
&& rm -rf /var/lib/apt/lists
# COPY EasyOCR is Github(https://github.com/JaidedAI/EasyOCR.git)
COPY ./EasyOCR "$service_home"
# Build
RUN cd "$service_home" \
&& pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ \
&& python setup.py build_ext --inplace -j 4 \
&& python -m pip install -e .
環境驗證
# Windows 環境
pip freeze | findstr "easyocr"
easyocr @ file:///E:/%E8%BF%85%E9%9B%B7%E4%B8%8B%E8%BD%BD/easyocr-1.4.2-py3-none-any.whl
# Linux & 容器環境
$ pip freeze | grep "EasyOCR"
-e git+https://github.com/JaidedAI/EasyOCR.git@7a685cb8c4ba14f2bc246f89c213f1a56bbc2107#egg=easyocr
# python 命令列中使用
>>> from pprint import pprint # 方便格式化輸出
>>> import easyocr
>>> reader = easyocr.Reader(['ch_sim','en'])
CUDA not available - defaulting to CPU. Note: This module is much faster with a GPU.
>>> result = reader.readtext('00e336dbde464c809ef1f6ea568d4621.png')
>>> pprint(result)
[([[354, 46], [444, 46], [444, 76], [354, 76]], '中國移動', 0.981803297996521),
([[477, 55], [499, 55], [499, 75], [477, 75]], '46', 0.3972922105840435),
([[533, 55], [555, 55], [555, 75], [533, 75]], '5G', 0.5360637875500641),
([[354, 76], [474, 76], [474, 104], [354, 104]],
'中國移動四 ',
0.25950584649873865),
([[489, 57], [625, 57], [625, 95], [489, 95]],
'GMl s @',
0.011500043801327683),
([[693, 55], [801, 55], [801, 95], [693, 95]], 'Q92%', 0.022083675488829613),
([[864, 60], [950, 60], [950, 92], [864, 92]], '09:03', 0.9793587315696877),
([[884, 158], [938, 158], [938, 214], [884, 214]], '@', 0.29484160211053734),
([[123, 298], [592, 298], [592, 361], [123, 361]],
'通訊行程卡提供服務>',
0.6739866899213806),
([[115, 429], [384, 429], [384, 497], [115, 497]],
'通訊行程卡',
0.9159307714297187),
([[153, 596], [848, 596], [848, 704], [153, 704]],
'通訊巨量資料行程卡',
0.2522292283860262),
([[303, 723], [699, 723], [699, 785], [303, 785]],
'疫情防控;人人有責',
0.7030201163942564),
([[347, 844], [653, 844], [653, 892], [347, 892]],
'請收下綠色行程卡',
0.9120484515458063),
([[248, 950], [754, 950], [754, 1004], [248, 1004]],
'157****2966的動態行程卡',
0.9868984946820241),
([[173, 1045], [345, 1045], [345, 1105], [173, 1105]],
'更新於:',
0.972654586401667),
([[360, 1049], [829, 1049], [829, 1100], [360, 1100]],
'2022.05.2509:03:56',
0.9411191664033213),
([[110, 1670], [633, 1670], [633, 1732], [110, 1732]],
'您於前14夭內到達或途經:',
0.8531442220608394),
([[648, 1674], [788, 1674], [788, 1730], [648, 1730]],
'重慶市',
0.9605511910615995),
([[104, 1778], [898, 1778], [898, 1810], [104, 1810]],
'結果包含您在前14天內到訪的國家(地區) 與停留4小時以上的國內城市',
0.6574011574316847),
([[272, 1825], [729, 1825], [729, 1863], [272, 1863]],
'色卡僅對到訪地作提醒。不關聯健康狀況',
0.8806245499955613),
([[383, 1891], [607, 1891], [607, 1933], [383, 1933]],
'本服務聯合提供',
0.9781898210349773),
([[119, 1966], [337, 1966], [337, 2006], [119, 2006]],
'CAICT 中國信通院',
0.3636917908522541),
([[435, 1963], [533, 1963], [533, 1999], [435, 1999]],
'中國電信',
0.08182162046432495),
([[624, 1966], [702, 1966], [702, 1990], [624, 1990]],
'中國移動',
0.9323447942733765),
([[812, 1966], [892, 1966], [892, 1990], [812, 1990]],
'中國聯通',
0.9082608819007874),
([[441, 1993], [531, 1993], [531, 2005], [441, 2005]],
'CINA TUUUC0',
0.028013896371299665),
([[629, 1987], [701, 1987], [701, 2003], [629, 2003]],
'ChnaMobile',
0.7021787396208221),
([[815, 1989], [893, 1989], [893, 2003], [815, 2003]],
'Chnoumco',
0.19655737186726854),
([[107, 2077], [281, 2077], [281, 2119], [107, 2119]],
'證通查來了!',
0.9745880948510078),
([[467, 2075], [825, 2075], [825, 2117], [467, 2117]],
'全國行動電話卡"一證通查',
0.9208412317655043),
([[79, 2131], [269, 2131], [269, 2173], [79, 2173]],
'立即點選進入',
0.6082888941606105),
([[510, 2128], [644, 2128], [644, 2172], [510, 2172]],
'防範詐騙',
0.952128529548645),
([[663, 2129], [793, 2129], [793, 2173], [663, 2173]],
'保護你我',
0.9819014668464661)]
# 設定 --detail=0 輸出更簡單
>>> result = reader.readtext('00e336dbde464c809ef1f6ea568d4621.png', detail = 0)
使用說明
easyocr.Reader(['ch_sim','en'])
於將模型載入到記憶體中(可能會耗費一些時間), 並且我們需要設定預設閱讀的語言列表, 可以同時使用多種語言,但並非所有語言都可以一起使用, 而通常會採用英語與其他語言聯合。下面列舉出可用語言及其語言對應列表 (https://www.jaided.ai/easyocr/) :
# 對於我們來說常用語言如下:
# Language Code Name
Simplified Chinese ch_sim
Traditional Chinese ch_tra
English en
溫馨提示: 所選語言的模型權重將自動下載,或者您可以從模型中心 並將它們放在~/.EasyOCR/model
資料夾中
--gpu=True
設定為True, 而機器又沒有GPU支援的化將預設採用 CPU ,所以通常你會看到如下提示:# 如果您沒有 GPU,或者您的 GPU 記憶體不足,您可以通過新增 gpu=False.
CUDA not available - defaulting to CPU. Note: This module is much faster with a GPU.
# 影象路徑
reader.readtext('chinese.jpg')
# 影象URL
reader.readtext('https://www.weiyigeek.top/wechat.jpg')
# 圖形位元組
with open("chinese_tra.jpg", "rb") as f:
img = f.read()
result = reader.readtext(img)
# 影象作為 numpy 陣列(來自 opencv)傳遞
img = cv2.imread('chinese_tra.jpg')
result = reader.readtext(img)
邊界框(四個點)、檢測到的文字和可信度
。 ([[347, 844], [653, 844], [653, 892], [347, 892]], # 邊界 1 --> 2 -> 3 -> 4
'請收下綠色行程卡', # 文字
0.9120484515458063), # 可信度
# 語法範例:
usage: easyocr [-h] -l LANG [LANG ...] [--gpu {True,False}] [--model_storage_directory MODEL_STORAGE_DIRECTORY]
[--user_network_directory USER_NETWORK_DIRECTORY] [--recog_network RECOG_NETWORK]
[--download_enabled {True,False}] [--detector {True,False}] [--recognizer {True,False}]
[--verbose {True,False}] [--quantize {True,False}] -f FILE
[--decoder {greedy,beamsearch,wordbeamsearch}] [--beamWidth BEAMWIDTH] [--batch_size BATCH_SIZE]
[--workers WORKERS] [--allowlist ALLOWLIST] [--blocklist BLOCKLIST] [--detail {0,1}]
[--rotation_info ROTATION_INFO] [--paragraph {True,False}] [--min_size MIN_SIZE]
[--contrast_ths CONTRAST_THS] [--adjust_contrast ADJUST_CONTRAST] [--text_threshold TEXT_THRESHOLD]
[--low_text LOW_TEXT] [--link_threshold LINK_THRESHOLD] [--canvas_size CANVAS_SIZE]
[--mag_ratio MAG_RATIO] [--slope_ths SLOPE_THS] [--ycenter_ths YCENTER_THS] [--height_ths HEIGHT_THS]
[--width_ths WIDTH_THS] [--y_ths Y_THS] [--x_ths X_THS] [--add_margin ADD_MARGIN]
# 案例:
$ easyocr -l ch_sim en -f chinese.jpg --detail=1 --gpu=False
$ easyocr -l ch_sim en -f .\0a1e948e90964d42b435d63c9f0aa268.png --detail=0 --gpu=True
# CUDA not available - defaulting to CPU. Note: This module is much faster with a GPU.
....
請收下綠色行程卡
191****8499的動態行程卡
更新於:2022.05.2510:49:21
您於前14夭內到達或途經: 重慶市
結果包含您在前14天內到訪的國家(地區)與停留4小時以上的國內城市
.....
描述: 官方提供的包的模組方法以及引數說明, 參考地址 ( https://www.jaided.ai/easyocr/documentation/ )
easyocr.Reader(['ch_sim','en'], gpu=False, model_storage_directory="~/.EasyOCR/.",download_enabled=True, user_network_directory="~/.EasyOCR/user_network",recog_network="recog_network",detector=True,recognizer=True)
# download_enabled :如果 EasyOCR 無法找到模型檔案,則啟用下載
# model_storage_directory: 模型資料目錄的路徑
# user_network_directory: 使用者定義識別網路的路徑
# detector : 載入檢測模型到記憶體中
# recognizer : 載入識別模型到記憶體中
reader.readtext(
'chinese.jpg',image,decoder='greedy',beamWidth=5,batch_size=1,workers=0,allowlist="ch_sim",blocklist="ch_tra",detail=1,paragraph=False,min_size=10,rotation_info=[90, 180 ,270],
contrast_ths = 0.1, adjust_contrast = 0.5,
text_threshold = 0.7, low_text = 0.4,link_threshold = 0.4, canvas_size = 2560, mag_ratio = 1,
slope_ths = 0.1, ycenter_ths = 0.5, height_ths = 0.5, width_ths = 0.5, add_margin = 0.1, x_ths = 1.0, y_ths = 0.5
)
# Parameters 1: General
--batch_size : 當其值大於 1 時將使 EasyOCR 更快,但使用更多記憶體。
--allowlist : 強制 EasyOCR 僅識別字元子集。 對特定問題有用(例如車牌等)
--detail : 將此設定為 0 以進行簡單輸出.
--paragraph :將結果合併到段落中
--min_size: 過濾小於畫素最小值的文字方塊
--rotation_info:允許 EasyOCR 旋轉每個文字方塊並返回具有最高置信度分數的文字方塊。例如,對所有可能的文字方向嘗試 [90, 180 ,270]。
# Parameters 2: Contrast
--contrast_ths : 對比度低於此值的文字方塊將被傳入模型 2 次,首先是原始影象,其次是對比度調整為「adjust_contrast」值,結果將返回具有更高置信度的那個。
--adjust_contrast : 低對比度文字方塊的目標對比度級別
# Parameters 3: Text Detection (from CRAFT)
--text_threshold: 文字置信度閾值
--link_threshold: 連結置信度閾值
--canvas_size: 最大影象尺寸,大於此值的影象將被縮小。
--mag_ratio: 影象放大率
# Parameters 4: Bounding Box Merging
height_ths (float, default = 0.5) - 盒子高度的最大差異,不應合併文字大小差異很大的框。
width_ths (float, default = 0.5) - 合併框的最大水平距離。
x_ths (float, default = 1.0) - 當段落 = True 時合併文字方塊的最大水平距離。
y_ths (float, default = 0.5) - 當段落 = True 時合併文字方塊的最大垂直距離。
Parameters
image (string, numpy array, byte) - Input image
min_size (int, default = 10) - Filter text box smaller than minimum value in pixel
text_threshold (float, default = 0.7) - Text confidence threshold
low_text (float, default = 0.4) - Text low-bound score
link_threshold (float, default = 0.4) - Link confidence threshold
canvas_size (int, default = 2560) - Maximum image size. Image bigger than this value will be resized down.
mag_ratio (float, default = 1) - Image magnification ratio
slope_ths (float, default = 0.1) - Maximum slope (delta y/delta x) to considered merging. Low value means tiled boxes will not be merged.
ycenter_ths (float, default = 0.5) - Maximum shift in y direction. Boxes with different level should not be merged.
height_ths (float, default = 0.5) - Maximum different in box height. Boxes with very different text size should not be merged.
width_ths (float, default = 0.5) - Maximum horizontal distance to merge boxes.
add_margin (float, default = 0.1) - Extend bounding boxes in all direction by certain value. This is important for language with complex script (E.g. Thai).
optimal_num_chars (int, default = None) - If specified, bounding boxes with estimated number of characters near this value are returned first.
Return horizontal_list, free_list - horizontal_list is a list of regtangular text boxes. The format is [x_min, x_max, y_min, y_max]. free_list is a list of free-form text boxes. The format is [[x1,y1],[x2,y2],[x3,y3],[x4,y4]].
Parameters
image (string, numpy array, byte) - Input image
horizontal_list (list, default=None) - see format from output of detect method
free_list (list, default=None) - see format from output of detect method
decoder (string, default = 'greedy') - options are 'greedy', 'beamsearch' and 'wordbeamsearch'.
beamWidth (int, default = 5) - How many beam to keep when decoder = 'beamsearch' or 'wordbeamsearch'
batch_size (int, default = 1) - batch_size>1 will make EasyOCR faster but use more memory
workers (int, default = 0) - Number thread used in of dataloader
allowlist (string) - Force EasyOCR to recognize only subset of characters. Useful for specific problem (E.g. license plate, etc.)
blocklist (string) - Block subset of character. This argument will be ignored if allowlist is given.
detail (int, default = 1) - Set this to 0 for simple output
paragraph (bool, default = False) - Combine result into paragraph
contrast_ths (float, default = 0.1) - Text box with contrast lower than this value will be passed into model 2 times. First is with original image and second with contrast adjusted to 'adjust_contrast' value. The one with more confident level will be returned as a result.
adjust_contrast (float, default = 0.5) - target contrast level for low contrast text box
Return list of results
描述: 公司有業務需求做一個行程碼識別, 當前是呼叫某雲的文字識別介面來識別行程碼, 而其按照呼叫次數進行計費, 所以為了節約成本就要Python參考了Github上大佬的們專案, 擷取部分函數,並使用Flask Web 框架進行封裝,從而實現通過網頁進行請求呼叫,並返回JSON字串。
專案原始碼Github地址:https://github.com/WeiyiGeek/SecOpsDev/tree/master/Project/Python/EasyOCR/Travelcodeocr
專案實踐
步驟 01.安裝flask及其依賴模組的。
pip install flask -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
步驟 02.專案路徑以及圖片路徑 D:\Study\Project
PS D:\Study\Project> ls
目錄: D:\Study\Project
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2022/5/25 15:59 img
-a---- 2022/5/25 19:34 3966 setup.py
步驟 03.基於Flask web框架下進行呼叫EasyOCR執行圖片文字識別的python程式碼.
# -*- coding: utf-8 -*-
# ####################################################################
# Author: WeiyiGeek
# Description: 基於easyocr實現巨量資料通訊行程卡圖片識別資訊獲取-Flask專案。
# Time: 2022年5月25日 17點31分
# Blog: https://www.weiyigeek.top
# Email: [email protected]
# ====================================================================
# 環境依賴與模組安裝, 建議 Python 3.8.x 的環境下進行
# pip install flask
# pip install easyocr
# ====================================================================
# 行程碼有綠色、黃色、橙色、紅色四種顏色。
# 1、紅卡:行程中的中高風險地市將標記為紅色字型作提示。
# 2、橙卡:新冠肺炎確診或疑似患者的密切接觸者。
# 3、黃卡:海外國家和地區。
# 4、綠卡:其他地區。行程卡結果包含在前14天內到訪的國家(地區)與停留4小時以上的國內城市。色卡僅對到訪地作提醒,不關聯健康狀況。
# #####################################################################
import os,sys
import cv2
import re
import glob
import json
import easyocr
from flask import Flask, jsonify, request,render_template
from datetime import datetime
from werkzeug.utils import secure_filename
import numpy as np
import collections
app = Flask(__name__)
# 專案執行路徑與行程碼圖片路徑定義
RUNDIR = None
IMGDIR = None
colorDict= {"red": "紅色", "red1": "紅色", "orange": "橙色", "yellow": "黃色", "green": "綠色"}
def getColorList():
"""
函數說明: 定義字典存放 HSV 顏色分量上下限 (HSV-RGB)
例如:{顏色: [min分量, max分量]}
{'red': [array([160, 43, 46]), array([179, 255, 255])]}
返回值: 專門的容器資料型別,提供Python通用內建容器、dict、list、set和tuple的替代品。
"""
dict = collections.defaultdict(list)
# 紅色
lower_red = np.array([156, 43, 46])
upper_red = np.array([180, 255, 255])
color_list = []
color_list.append(lower_red)
color_list.append(upper_red)
dict['red']=color_list
# 紅色2
lower_red = np.array([0, 43, 46])
upper_red = np.array([10, 255, 255])
color_list = []
color_list.append(lower_red)
color_list.append(upper_red)
dict['red2'] = color_list
# 橙色
lower_orange = np.array([11, 43, 46])
upper_orange = np.array([25, 255, 255])
color_list = []
color_list.append(lower_orange)
color_list.append(upper_orange)
dict['orange'] = color_list
# 黃色
lower_yellow = np.array([26, 43, 46])
upper_yellow = np.array([34, 255, 255])
color_list = []
color_list.append(lower_yellow)
color_list.append(upper_yellow)
dict['yellow'] = color_list
# 綠色
lower_green = np.array([35, 43, 46])
upper_green = np.array([77, 255, 255])
color_list = []
color_list.append(lower_green)
color_list.append(upper_green)
dict['green'] = color_list
return dict
def getTravelcodeColor(img_np):
"""
函數說明: 利用閾值返回行程碼主頁顏色
引數值: cv2.imread() 讀取的影象物件(np陣列)
返回值: 行程卡顏色{紅、橙、綠}
"""
hsv = cv2.cvtColor(img_np, cv2.COLOR_BGR2HSV)
maxsum = -100
color = None
color_dict = getColorList()
for d in color_dict:
mask = cv2.inRange(hsv,color_dict[d][0],color_dict[d][1])
# cv2.imwrite(os.path.join(os.path.abspath(os.curdir),"img",d+'.jpg') ,mask)
binary = cv2.threshold(mask, 127, 255, cv2.THRESH_BINARY)[1]
binary = cv2.dilate(binary,None,iterations=2)
cnts, hiera = cv2.findContours(binary.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
sum = 0
for c in cnts:
sum+=cv2.contourArea(c)
if sum > maxsum :
maxsum = sum
color = d
return colorDict[color]
def information_filter(file_path,img_np,text_str):
"""
函數說明: 提出ocr識別的行程碼
引數值:字串,檔名稱
返回值:有效資訊組成的字典
"""
# 健康碼欄位
try:
re_healthcode = re.compile('請收下(.{,2})行程卡')
healthcode = re_healthcode.findall(text_str)[0]
except Exception as _:
healthcode = getTravelcodeColor(img_np) # 文字無法識別時採用圖片顏色識別
print("[*] Get Photo Color = ",healthcode)
# 電話欄位
re_phone = re.compile('[0-9]{3}\*{4}[0-9]{4}')
phone_str = re_phone.findall(text_str)[0]
# 日期欄位
re_data = re.compile('2022\.[0-1][0-9]\.[0-3][0-9]')
data_str = re_data.findall(text_str)[0]
# 時間欄位
re_time = re.compile('[0-9][0-9]:[0-9][0-9]:[0-9][0-9]')
time_str = re_time.findall(text_str)[0]
# 地區城市欄位
citys_re = re.compile('到達或途經:(.+)結果包含')
citys_str = citys_re.findall(text_str)[0].strip().split('(')[0]
result_dic = {"status": "succ", "file": file_path ,"型別": healthcode, "電話": phone_str, "日期": data_str, "時間": time_str, "行程": citys_str}
print("\033[032m",result_dic,"\033[0m")
return result_dic
def getTravelcodeInfo(filename, img_np):
"""
函數說明: 返回以JSON字串格式過濾後結果
引數值:檔名稱,影象作為 numpy 陣列(來 opencv傳遞
返回值:JSON字串格式
"""
# 灰度處理
img_gray = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
# 閾值二進位制 - > 127 設定為255(白),否則0(黑) -> 淡白得更白,淡黑更黑
_,img_thresh = cv2.threshold(img_gray,180,255,cv2.THRESH_BINARY)
# 影象 OCR 識別
text = reader.readtext(img_thresh, detail=0, batch_size=10)
result_dic = information_filter(filename, img_np, "".join(text))
return result_dic
# Flask 路由 - 首頁
@app.route('/')
@app.route('/index')
def Index():
return "<h4 style='text-algin:center'>https://www.weiyigeek.top</h4><script>window.location.href='https://www.weiyigeek.top'</script>"
# Flask 路由 - /tools/ocr
@app.route('/tools/ocr',methods=["GET"])
def Travelcodeocr():
"""
請求路徑: /tools/ocr
請求引數: (/tools/ocr?file=20220520/test.png, /tools/ocr?dir=20220520)
"""
filename = request.args.get("file")
dirname = request.args.get("dir")
if (filename):
img_path = os.path.join(IMGDIR, filename)
if (os.path.exists(img_path)):
print(img_path) # 列印路徑
img_np = cv2.imread(img_path)
try:
result_dic_succ = getTravelcodeInfo(filename,img_np)
except Exception as err:
print("\033[31m"+ img_path + " -->> " + str(err) + "\033[0m")
return json.dumps({"status":"err", "img": filename}).encode('utf-8'), 200, {"Content-Type":"application/json"}
return json.dumps(result_dic_succ, ensure_ascii=False).encode('utf-8'), 200, {"Content-Type":"application/json"}
else:
return jsonify({"status": "err","msg": "檔案"+img_path+"路徑不存在."})
elif (dirname and os.path.join(IMGDIR, dirname)):
result_dic_all = []
result_dic_err = []
img_path_all = glob.iglob(os.path.join(os.path.join(IMGDIR,dirname)+"/*.[p|j]*g")) # 正則匹配 png|jpg|jpeg 字尾的字尾,返回的是迭代器。
for img_path in img_path_all:
print(img_path) # 列印路徑
img_np = cv2.imread(img_path)
try:
result_dic_succ = getTravelcodeInfo(os.path.join(dirname,os.path.basename(img_path)),img_np)
except Exception as err:
print("\033[31m"+ img_path + " -->> " + str(err) + "\033[0m") # 輸出識別錯誤的影象
result_dic_err.append(img_path)
continue
# 成功則加入到List列表中
result_dic_all.append(result_dic_succ)
res_succ_json=json.dumps(result_dic_all, ensure_ascii=False)
res_err_json=json.dumps(result_dic_err, ensure_ascii=False)
with open(os.path.join(IMGDIR, dirname, dirname + "-succ.json"),'w') as succ:
succ.write(res_succ_json)
with open(os.path.join(IMGDIR, dirname, dirname + "-err.json"),'w') as error:
error.write(res_err_json)
return res_succ_json.encode('utf-8'), 200, {"Content-Type":"application/json"}
else:
return jsonify({"status": "err","msg": "請求引數有誤!"})
# Flask 路由 - /tools/upload/ocr
@app.route('/tools/upload/ocr',methods=["GET","POST"])
def TravelcodeUploadocr():
if request.method == 'POST':
unix = datetime.now().strftime('%Y%m%d-%H%M%S%f')
f = request.files['file']
if (f.mimetype == 'image/jpeg' or f.mimetype == 'image/png'):
filedate = unix.split("-")[0]
filesuffix = f.mimetype.split("/")[-1]
uploadDir = os.path.join('img',filedate)
# 判斷上傳檔案目錄是否存在
if (not os.path.exists(uploadDir)):
os.makedirs(uploadDir)
img_path = os.path.join(uploadDir,secure_filename(unix+"."+filesuffix)) # 圖片路徑拼接
print(img_path) # 列印路徑
f.save(img_path) # 寫入圖片
# 判斷上傳檔案是否存在
if (os.path.exists(img_path)):
img_np = cv2.imread(img_path)
try:
result_dic_succ = getTravelcodeInfo(os.path.join(filedate,os.path.basename(img_path)),img_np)
except Exception as err:
print("\033[31m"+ err + "\033[0m")
return json.dumps({"status":"err", "img": img_path}).encode('utf-8'), 200, {"Content-Type":"application/json"}
return json.dumps(result_dic_succ, ensure_ascii=False).encode('utf-8'), 200, {"Content-Type":"application/json"}
else:
return jsonify({"status": "err","msg": "檔案"+img_path+"路徑不存在!"})
else:
return jsonify({"status": "err","msg": "不能上傳除 jpg 與 png 格式以外的圖片"})
else:
return render_template('index.html')
# 程式入口
if __name__ == '__main__':
try:
RUNDIR = sys.argv[1]
IMGDIR = sys.argv[2]
except Exception as e:
print("[*] Uage:"+ sys.argv[0] + " RUNDIR IMGDIR")
print("[*] Default:"+ sys.argv[0] + " ./ ./img" + "\n" )
RUNDIR = os.path.abspath(os.curdir)
IMGDIR = os.path.join(RUNDIR,"img")
# finally:
# if os.path.exists(RUNDIR):
# RUNDIR = os.path.abspath(os.curdir)
# if os.path.exists(IMGDIR):
# IMGDIR = os.path.join(RUNDIR,"img")
# 使用easyocr模組中的Reader方法, 設定識別中英文兩種語言
reader = easyocr.Reader(['ch_sim', 'en'], gpu=False)
# 使用Flask模組執行web
app.run(host='0.0.0.0', port=8000, debug=True)
步驟 03.執行該指令碼並使用瀏覽進行指定行程碼圖片路徑以及識別提取。
python .\setup.py
# Using CPU. Note: This module is much faster with a GPU.
# * Serving Flask app 'index' (lazy loading)
# * Environment: production
# WARNING: This is a development server. Do not use it in a production deployment.
# Use a production WSGI server instead.
# * Debug mode: on
# * Running on all addresses (0.0.0.0)
# WARNING: This is a development server. Do not use it in a production deployment.
# * Running on http://127.0.0.1:8000
# * Running on http://10.20.172.106:8000 (Press CTRL+C to quit)
# * Restarting with stat
# Using CPU. Note: This module is much faster with a GPU.
# * Debugger is active!
# * Debugger PIN: 115-313-307
溫馨提示: 從上面的Python指令碼中可以看出我們可使用file引數指定圖片路徑或者使用dir引數指定行程碼圖片存放目錄(預設在img目錄下的子目錄)。
例如,獲取單個行程碼圖片資訊,我本地瀏覽器存取http://127.0.0.1:8000/tools/ocr?file=20220530/00e336dbde464c809ef1f6ea568d4621.png
地址,將會返回如下JSON字串。
D:\Study\Project\img\20220530\00e336dbde464c809ef1f6ea568d4621.png
127.0.0.1 - - [01/Jun/2022 16:58:58] "GET /tools/upload/ocr HTTP/1.1" 200 -
{'status': 'succ', 'file': '20220530\\00e336dbde464c809ef1f6ea568d4621.png', '型別': '綠色', '電話': '157****2966', '日期': '2022.05.25', '時間': '09:03:56', '行程': '重慶市'}
例如,獲取多個行程碼圖片識別資訊,我本地瀏覽器存取http://127.0.0.1:8000/tools/ocr?dir=20220530
地址,將會返回如下圖所示結果。
例如, 我們可以上傳並識別行程碼圖片資訊,本地瀏覽器存取http://127.0.0.1:8000/tools/upload/ocr
地址,將會返回如下圖所示結果。
問題1.通過pip install 安裝easyocr離線的whl包是報ERROR: No matching distribution found for torch
pip install ./easyocr-1.4.2-py3-none-any.whl -i https://mirrors.aliyun.com/pypi/simple/ --trusted-host mirrors.aliyun.com
ERROR: Could not find a version that satisfies the requirement torch (from easyocr) (from versions: none)
ERROR: No matching distribution found for torch
python.exe -m pip install --upgrade pip
問題2.在Python3.7的環境中安裝easyocr依賴的torch模組的whl安裝包報not a supported wheel on this platform.
錯誤
$ pip install torch-1.8.0+cpu-cp37-cp37m-win_amd64.whl -i https://pypi.tuna.tsinghua.edu.cn/simple/
WARNING: Requirement 'torch-1.8.0+cpu-cp37-cp37m-win_amd64.whl' looks like a filename, but the file does not exist
Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple/
ERROR: torch-1.8.0+cpu-cp37-cp37m-win_amd64.whl is
# 解決1.假如,你是linux你可以通過 https://download.pytorch.org/whl/torch_stable.html 找到所需版本。
檔名解釋:cpu或顯示卡/檔名-版本號-python版本-應該是編譯格式-平臺-cpu型別(intel也選amd64)
# torch-1.8.0+cpu-cp37-cp37m-win_amd64.whl
# 解決2.將 torch-1.8.0+cpu-cp37-cp37m-win_amd64.whl 更名為 torch-1.8.0+cpu-cp37-cp37m-win32.whl
問題3.在執行呼叫torch模組的py指令碼時報Error loading "D:\****\lib\site-packages\torch\lib\asmjit.dll" or one of its dependencies.
錯誤
Microsoft Visual C++ Redistributable is not installed, this may lead to the DLL load failure.
It can be downloaded at https://aka.ms/vs/16/release/vc_redist.x64.exe
Traceback (most recent call last):
.....
OSError: [WinError 193] <no description> Error loading "D:\Program Files (x86)\Python37-32\lib\site-packages\torch\lib\asmjit.dll" or one of its dependencies.
問題4.在安裝opencv_python_headless進行依賴模組安裝時報ERROR: No matching distribution found for torchvision>=0.5
錯誤
Using cached https://mirrors.aliyun.com/pypi/packages/a4/0a/39b102047bcf3b1a58ee1cc83a9269b2a2c4c1ab3062a65f5292d8df6594/opencv_python_headless-4.5.4.60-cp37-cp37m-win32.whl (25.8 MB)
ERROR: Could not find a version that satisfies the requirement torchvision>=0.5 (from easyocr) (from versions: 0.1.6, 0.1.7, 0.1.8, 0.1.9, 0.2.0, 0.2.1, 0.2.2, 0.2.2.post2, 0.2.2.post3)
ERROR: No matching distribution found for torchvision>=0.5
torch 1.5
和 torchvision0.6
。問題5.在執行easyocr文字識別時出現Downloading detection model, please wait. This may take several minutes depending upon your network connection.
提示
EasyOCR
模組所需的模型, 而由於國內網路環境,通常會報出超時錯誤,此時我們提前從官網下載其所需的資料模型,並安裝在指定目錄中。# 主要下載以下模型(如有其它需要請自行選擇下載)
english_g2 : https://github.com/JaidedAI/EasyOCR/releases/download/v1.3/english_g2.zip
zh_sim_g2 : https://github.com/JaidedAI/EasyOCR/releases/download/v1.3/zh_sim_g2.zip
CRAFT : https://github.com/JaidedAI/EasyOCR/releases/download/pre-v1.1.6/craft_mlt_25k.zip
# 模型安裝位置
# windows
C:\Users\WeiyiGeek\.EasyOCR\model
# Linux
/home/weiyigeek/.EasyOCR\model
文章書寫不易,如果您覺得這篇文章還不錯的,請給這篇專欄 【點個贊、投個幣、收個藏、關個注,轉個發】(人間五大情),這將對我的肯定,謝謝!。
本文章來源 我的Blog站點 或 WeiyiGeek 公眾賬號 以及 我的BiliBili專欄 (
技術交流、友鏈交換請郵我喲
),謝謝支援!(๑′ᴗ‵๑) ❤
歡迎各位志同道合的朋友一起學習交流,如文章有誤請留下您寶貴的知識建議,通過郵箱【master#weiyigeek.top】聯絡我喲!