Python使用EasyOCR庫對行程碼圖片進行OCR文字識別介紹與實踐

關注「WeiyiGeek」點我,點我

10年的資源網站建設經驗,針對設計、前端、開發、售后、文案、推廣等六對一服務,響應快,48小時及時工作處理。營銷型網站建設的優勢是能夠根據用戶設備顯示端的尺寸不同,自動調整資源建站的顯示方式,使網站能夠適用不同顯示終端,在瀏覽器中調整網站的寬度,無論在任何一種瀏覽器上瀏覽網站,都能展現優雅布局與設計,從而大程度地提升瀏覽體驗。創新互聯公司從事“資源網站設計”,“資源網站推廣”以來,每個客戶項目都認真落實執行。

設為「特別關注」,每天帶你在B站玩轉網絡安全運維、應用開發、物聯網IOT學習!

希望各位看友【關注、點贊、評論、收藏、投幣】,助力每一個夢想。

文章目錄
0x00 快速了解

  • EasyOCR 介紹
  • EasyOCR 參考來源

0x01 安裝部署

  • 環境依賴
  • 環境安裝
  • 方法參數

0x02 實踐案例

  1. 批量識別行程碼圖片

0x03 入坑出坑


0x00 快速了解

EasyOCR 介紹

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


EasyOCR 參考來源

官網地址: 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/cv

實踐視頻地址: https://www.bilibili.com/video/BV1nY4y1x7JG

溫馨提示: 該項目基于來自多篇論文和開源存儲庫的研究和代碼,所有深度學習執行都基于 Pytorch ,識別模型是 CRNN 它由 3 個主要部分組成:特征提取(我們目前使用 Resnet )和 VGG、序列標記( LSTM )和解碼??( CTC )。 ??


0x01 安裝部署

環境依賴

環境依賴

  • Python 建議 3.8 x64 以上版本 (原本我的環境是 Python 3.7 安裝時各種稀奇古怪的錯誤都出來,不得已abandon放棄)
  • easyocr 包 -> 依賴 torch 、torchvision 第三方包

注意事項:

  • Note 1.本章是基于 cpu 與 GPU 下使用 EasyOCR, 如果你需要使用 GPU 跑, 那么請你安裝相應的CUDA環境。
$ 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 / MiB |      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.),
 ([[477, 55], [499, 55], [499, 75], [477, 75]], '46', 0.),
 ([[533, 55], [555, 55], [555, 75], [533, 75]], '5G', 0.),
 ([[354, 76], [474, 76], [474, 104], [354, 104]],
  '中國移動四 ',
  0.),
 ([[489, 57], [625, 57], [625, 95], [489, 95]],
  'GMl s @',
  0.0),
 ([[693, 55], [801, 55], [801, 95], [693, 95]], 'Q92%', 0.0),
 ([[864, 60], [950, 60], [950, 92], [864, 92]], '09:03', 0.),
 ([[884, 158], [938, 158], [938, 214], [884, 214]], '@', 0.),
 ([[123, 298], [592, 298], [592, 361], [123, 361]],
  '通信行程卡提供服務>',
  0.),
 ([[115, 429], [384, 429], [384, 497], [115, 497]],
  '通信行程卡',
  0.),
 ([[153, 596], [848, 596], [848, 704], [153, 704]],
  '通信大數據行程卡',
  0.),
 ([[303, 723], [699, 723], [699, 785], [303, 785]],
  '疫情防控;人人有責',
  0.),
 ([[347, 844], [653, 844], [653, 892], [347, 892]],
  '請收下綠色行程卡',
  0.),
 ([[248, 950], [754, 950], [754, 1004], [248, 1004]],
  '157****2966的動態行程卡',
  0.),
 ([[173, 1045], [345, 1045], [345, 1105], [173, 1105]],
  '更新于:',
  0.),
 ([[360, 1049], [829, 1049], [829, 1100], [360, 1100]],
  '2022.05.2509:03:56',
  0.),
 ([[110, 1670], [633, 1670], [633, 1732], [110, 1732]],
  '您于前14夭內到達或途經:',
  0.),
 ([[648, 1674], [788, 1674], [788, 1730], [648, 1730]],
  '重慶市',
  0.),
 ([[104, 1778], [898, 1778], [898, 1810], [104, 1810]],
  '結果包含您在前14天內到訪的國家(地區) 與停留4小時以上的國內城市',
  0.),
 ([[272, 1825], [729, 1825], [729, 1863], [272, 1863]],
  '色卡僅對到訪地作提醒。不關聯健康狀況',
  0.),
 ([[383, 1891], [607, 1891], [607, 1933], [383, 1933]],
  '本服務聯合提供',
  0.),
 ([[119, 1966], [337, 1966], [337, 2006], [119, 2006]],
  'CAICT 中國信通院',
  0.),
 ([[435, 1963], [533, 1963], [533, 1999], [435, 1999]],
  '中國電信',
  0.0),
 ([[624, 1966], [702, 1966], [702, 1990], [624, 1990]],
  '中國移動',
  0.),
 ([[812, 1966], [892, 1966], [892, 1990], [812, 1990]],
  '中國聯通',
  0.),
 ([[441, 1993], [531, 1993], [531, 2005], [441, 2005]],
  'CINA TUUUC0',
  0.0),
 ([[629, 1987], [701, 1987], [701, 2003], [629, 2003]],
  'ChnaMobile',
  0.),
 ([[815, 1989], [893, 1989], [893, 2003], [815, 2003]],
  'Chnoumco',
  0.),
 ([[107, 2077], [281, 2077], [281, 2119], [107, 2119]],
  '證通查來了!',
  0.),
 ([[467, 2075], [825, 2075], [825, 2117], [467, 2117]],
  '全國移動電話卡"一證通查',
  0.),
 ([[79, 2131], [269, 2131], [269, 2173], [79, 2173]],
  '立即點擊進入',
  0.),
 ([[510, 2128], [644, 2128], [644, 2172], [510, 2172]],
  '防范詐騙',
  0.),
 ([[663, 2129], [793, 2129], [793, 2173], [663, 2173]],
  '保護你我',
  0.)]
# 設置 --detail=0 輸出更簡單
>>> result = reader.readtext('00e336dbde464c809ef1f6ea568d4621.png', detail = 0) 

使用說明

  • Note 1.在使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文件夾中

  • Note 2.如果--gpu=True設置為True, 而機器又沒有GPU支持的化將默認采用 CPU ,所以通常你會看到如下提示:
# 如果您沒有 GPU,或者您的 GPU 內存不足,您可以通過添加 gpu=False. 
CUDA not available - defaulting to CPU. Note: This module is much faster with a GPU.
  • Note 3.在reader.readtext('參數值')函數中的參數值,可以是圖片路徑、也可是圖像文件字節或者 OpenCV 圖像對象(numpy 數組)以及互聯網上圖像的URL 等幾種方式.
# 圖像路徑
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)
  • Note 3.從上面結果可以看出輸出結果將采用列表格式,每個項目分別代表一個邊界框(四個點)、檢測到的文本和可信度
 ([[347, 844], [653, 844], [653, 892], [347, 892]],  # 邊界 1 --> 2 -> 3 -> 4
  '請收下綠色行程卡',       # 文本
  0.),     # 可信度
  • Note 4.我們也可以在命令行中直接調用easyocr。
# 語法示例:
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 .\0a1e948ed42b435d63c9f0aa268.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/ )

  • 1.EasyOCR 的基類
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 : 加載識別模型到內存中
  • 2.Reader 對象的主要方法, 有 4 組參數:General、Contrast、Text Detection 和 Bounding Box Merging, 其返回值為列表形式。
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 時合并文本框的最大垂直距離。
  • 3.detect method, 檢測文本框的方法。
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]]. 
  • 4.recognize method, 從文本框中識別字符的方法,如果未給出 Horizo??ntal_list 和 free_list,它將整個圖像視為一個文本框。
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 

0x02 實踐案例

1.批量識別行程碼圖片

描述: 公司有業務需求做一個行程碼識別, 當前是調用某云的文字識別接口來識別行程碼, 而其按照調用次數進行計費, 所以為了節約成本就要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: master@weiyigeek.top
# ====================================================================
# 環境依賴與模塊安裝, 建議 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.

# Flask 路由 - /tools/ocr
@app.route('/tools/ocr',methods=["GET"])
def Travelcodeocr():
  """
  請求路徑: /tools/ocr
  請求參數: (/tools/ocr?file=/test.png, /tools/ocr?dir=)
  """
  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=/00e336dbde464c809ef1f6ea568d4621.png地址,將會返回如下JSON字符串。

D:\Study\Project\img\\00e336dbde464c809ef1f6ea568d4621.png
127.0.0.1 - - [01/Jun/2022 16:58:58] "GET /tools/upload/ocr HTTP/1.1" 200 -
{'status': 'succ', 'file': '\\00e336dbde464c809ef1f6ea568d4621.png', '類型': '綠色', '電話': '157****2966', '日期': '2022.05.25', '時間': '09:03:56', '行程': '重慶市'} 

例如,獲取多個行程碼圖片識別信息,我本地瀏覽器訪問http://127.0.0.1:8000/tools/ocr?dir=地址,將會返回如下圖所示結果。

例如, 我們可以上傳并識別行程碼圖片信息,本地瀏覽器訪問http://127.0.0.1:8000/tools/upload/ocr地址,將會返回如下圖所示結果。


0x03 入坑出坑

問題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 
  • 錯誤原因: 平臺與下載的whl不符合, 此處我遇到的問題明顯不是這個導致的,百度后我想是由于pip版本與python版本、以及系統平臺聯合導致。
  • 解決辦法:
# 解決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.
  • 解決辦法: 在你的電腦上下載安裝 https://aka.ms/vs/16/release/vc_redist.x64.exe 缺少的C++運行庫,重啟電腦。

問題4.在安裝opencv_python_headless進行依賴模塊安裝時報ERROR: No matching distribution found for torchvision>=0.5錯誤

  • 錯誤信息:
Using cached https://mirrors.aliyun.com/pypi/packages/a4/0a/39bbcf3b1a58ee1cc83a9269b2a2c4c1ab3062a65f5292d8df6594/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
  • 解決辦法: 如果你的 python 版本為3.7.x,那么你只能安裝 torch 1.5torchvision0.6

問題5.在執行easyocr文字識別時出現Downloading detection model, please wait. This may take several minutes depending upon your network connection.提示

  • 問題描述: 在首次使用時會自動下載EasyOCR模塊所需的模型, 而由于國內網絡環境,通常會報出超時錯誤,此時我們提前從官網下載其所需的數據模型,并安裝在指定目錄中。
  • 模型下載: https://www.jaided.ai/easyocr/modelhub/
# 主要下載以下模型(如有其它需要請自行選擇下載)
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

作者:WeiyiGeek
原文連接: https://blog.weiyigeek.top/2022/5-8-658.html

文章書寫不易,如果您覺得這篇文章還不錯的,請給這篇專欄 【點個贊、投個幣、收個藏、關個注,轉個發】(人間五大情),這將對我的肯定,謝謝!。

本文章來源 我的Blog站點 或 WeiyiGeek 公眾賬號 以及 我的BiliBili專欄 (技術交流、友鏈交換請郵我喲),謝謝支持!(?′?‵?) ?
歡迎各位志同道合的朋友一起學習交流,如文章有誤請留下您寶貴的知識建議,通過郵箱【master#weiyigeek.top】聯系我喲!

網頁名稱:Python使用EasyOCR庫對行程碼圖片進行OCR文字識別介紹與實踐
新聞來源:http://m.kartarina.com/article8/dsogjip.html

成都網站建設公司_創新互聯,為您提供虛擬主機品牌網站設計網頁設計公司微信公眾號網站排名外貿網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

小程序開發
主站蜘蛛池模板: 无码色偷偷亚洲国内自拍| 亚洲Aⅴ在线无码播放毛片一线天| 亚洲一区二区三区无码中文字幕| 精品人妻系列无码人妻免费视频| 免费一区二区无码视频在线播放| 国产成人无码久久久精品一| 6080YYY午夜理论片中无码| 国产福利无码一区在线| 国产热の有码热の无码视频| 无码成人AAAAA毛片| 无码人妻精品一区二区三区夜夜嗨| 无码国产成人午夜电影在线观看| 变态SM天堂无码专区| 无码AV波多野结衣久久| 免费A级毛片无码A| 久久无码中文字幕东京热| 亚洲综合无码精品一区二区三区| 久久精品无码中文字幕| 国产成人AV片无码免费| 日本无码色情三级播放| 天堂无码久久综合东京热| 爆乳无码AV一区二区三区 | 久久久久亚洲av无码专区喷水| av色欲无码人妻中文字幕 | 中文字幕无码中文字幕有码| 亚洲乱码无码永久不卡在线| 久久精品无码专区免费| 狼人无码精华AV午夜精品| 激情无码亚洲一区二区三区| 亚洲av中文无码乱人伦在线观看| 久久久无码精品亚洲日韩按摩| 无码精品一区二区三区免费视频| 亚洲AV无码乱码在线观看富二代| 久久久人妻精品无码一区 | 日韩欧精品无码视频无删节| 亚洲日韩乱码中文无码蜜桃臀网站| av无码一区二区三区| 超清无码一区二区三区| 亚洲午夜国产精品无码老牛影视| 成人无码WWW免费视频| 亚洲精品无码专区久久久|