使用tensorflow和cnn(卷積神經網絡)識別驗證碼並構建API

項目源地址:github.com/nickliqian/… 歡迎你們star和fork~html

cnn_captcha

use CNN recognize captcha by tensorflow.
本項目針對字符型圖片驗證碼,使用tensorflow實現卷積神經網絡,進行驗證碼識別。
項目封裝了比較通用的校驗、訓練、驗證、識別、API模塊,極大的減小了識別字符型驗證碼花費的時間和精力。python

項目已經幫助不少同窗高效完成了驗證碼識別任務。 若是你在使用過程當中出現了bug和作了良好的改進,歡迎提出issue和PR,做者會盡快回復,但願能和你共同完善項目。nginx

若是你須要識別點選、拖拽類驗證碼,或者有目標檢測需求,也能夠參考這個項目nickliqian/darknet_captchagit

時間表

2018.11.12 - 第一版Readme.md
2018.11.21 - 加入關於驗證碼識別的一些說明
2018.11.24 - 優化校驗數據集圖片的規則
2018.11.26 - 新增train_model_v2.py文件,訓練過程當中同時輸出訓練集和驗證集的準確率
2018.12.06 - 新增多模型部署支持,修復若干bug
2018.12.08 - 優化模型識別速度,支持api壓力測試和統計耗時
2018.02.19 - 新增一種準確率計算方式github

目錄

1 項目介紹web

2 如何使用算法

3 說明json

4 已知BUGflask

1 項目介紹

1.1 關於驗證碼識別

驗證碼識別大可能是爬蟲會遇到的問題,也能夠做爲圖像識別的入門案例。目前一般使用以下幾種方法:api

方法名稱 相關要點
tesseract 僅適合識別沒有干擾和扭曲的圖片,訓練起來很麻煩
其餘開源識別庫 不夠通用,識別率未知
付費OCR API 需求量大的情造成本很高
圖像處理+機器學習分類算法 涉及多種技術,學習成本高,且不通用
卷積神經網絡 必定的學習成本,算法適用於多類驗證碼

這裏說一下使用傳統的圖像處理和機器學習算法,涉及多種技術:

  1. 圖像處理
  • 前處理(灰度化、二值化)
  • 圖像分割
  • 裁剪(去邊框)
  • 圖像濾波、降噪
  • 去背景
  • 顏色分離
  • 旋轉
  1. 機器學習
  • KNN
  • SVM

使用這類方法對使用者的要求較高,且因爲圖片的變化類型較多,處理的方法不夠通用,常常花費不少時間去調整處理步驟和相關算法。
而使用卷積神經網絡,只須要經過簡單的前處理,就能夠實現大部分靜態字符型驗證碼的端到端識別,效果很好,通用性很高。

這裏列出目前經常使用的驗證碼生成庫:

參考:Java驗證全家桶

在這裏插入圖片描述

1.2 目錄結構

1.2.1 基本配置

序號 文件名稱 說明
1 sample.py 配置文件
2 sample文件夾 存放數據集
3 model文件夾 存放模型文件

1.2.2 訓練模型

序號 文件名稱 說明
1 verify_and_split_data.py 驗證數據集和拆分數據爲訓練集和測試集
2 train_model.py 訓練模型
3 train_model_v2.py 訓練模型,訓練過程當中同時輸出訓練集和驗證集的準確率,推薦使用此種方式訓練
4 test_batch.py 批量驗證
5 gen_image/gen_sample_by_captcha.py 生成驗證碼的腳本
6 gen_image/collect_labels.py 用於統計驗證碼標籤(經常使用於中文驗證碼)

1.2.3 web接口

序號 文件名稱 說明
1 recognition_object.py 封裝好的識別類
2 recognize_api.py 使用flask寫的提供在線識別功能的接口
3 recognize_online.py 使用接口識別的例子
4 recognize_local.py 測試本地圖片的例子
5 recognize_time_test.py 壓力測試識別耗時和請求響應耗時

1.3 依賴

pip3 install tensorflow==1.7.0 flask==1.0.2 requests==2.19.1 Pillow==4.3.0 matplotlib==2.1.0 easydict==1.8
複製代碼

1.4 模型結構

序號 層級
輸入 input
1 卷積層 + 池化層 + 降採樣層 + ReLU
2 卷積層 + 池化層 + 降採樣層 + ReLU
3 卷積層 + 池化層 + 降採樣層 + ReLU
4 全鏈接 + 降採樣層 + Relu
5 全鏈接 + softmax
輸出 output

2 如何使用

2.1 數據集

原始數據集能夠存放在./sample/origin目錄中
爲了便於處理,圖片最好以2e8j_17322d3d4226f0b5c5a71d797d2ba7f7.jpg格式命名(標籤_序列號.後綴)

若是你沒有訓練集,你可使用gen_sample_by_captcha.py文件生成訓練集文件。 生成以前你須要修改相關配置(路徑、文件後綴、字符集等)。

2.2 配置文件

建立一個新項目前,須要自行修改相關配置文件

圖片文件夾
sample_conf.origin_image_dir = "./sample/origin/"  # 原始文件
sample_conf.train_image_dir = "./sample/train/"   # 訓練集
sample_conf.test_image_dir = "./sample/test/"   # 測試集
sample_conf.api_image_dir = "./sample/api/"   # api接收的圖片儲存路徑
sample_conf.online_image_dir = "./sample/online/"  # 從驗證碼url獲取的圖片的儲存路徑

# 模型文件夾
sample_conf.model_save_dir = "./model/"  # 訓練好的模型儲存路徑

# 圖片相關參數
sample_conf.image_width = 80  # 圖片寬度
sample_conf.image_height = 40  # 圖片高度
sample_conf.max_captcha = 4  # 驗證碼字符個數
sample_conf.image_suffix = "jpg"  # 圖片文件後綴

# 驗證碼字符相關參數
# 驗證碼識別結果類別
sample_conf.char_set = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
                        'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']

# 驗證碼遠程連接
sample_conf.remote_url = "https://www.xxxxx.com/getImg"
複製代碼

具體配置的做用會在使用相關腳本的過程當中提到 關於驗證碼識別結果類別,假設你的樣本是中文驗證碼,你可使用gen_image/collect_labels.py腳本進行標籤的統計。 會生成文件gen_image/labels.json存放全部標籤,在配置文件中設置use_labels_json_file = True開啓讀取labels.json內容做爲結果類別

2.3 驗證和拆分數據集

此功能會校驗原始圖片集的尺寸和測試圖片是否能打開,並按照19:1的比例拆分出訓練集和測試集。
因此須要分別建立和指定三個文件夾:origin,train,test用於存放相關文件。

也能夠修改成不一樣的目錄,可是最好修改成絕對路徑。
文件夾建立好以後,執行如下命令便可:

python3 verify_and_split_data.py
複製代碼

通常會有相似下面的提示

Total image count: 10094
====如下4張圖片有異常====
[第2123張圖片] [325.txt] [文件後綴不正確]
[第3515張圖片] [_15355300508855503.gif] [圖片標籤異常]
[第6413張圖片] [qwer_15355300721958663.gif] [圖片尺寸異常爲:(50, 50)]
[第9437張圖片] [abcd_15355300466073782.gif] [圖片沒法正常打開]
========end
開始分離原始圖片集爲:測試集(5%)和訓練集(95%)
共分配10090張圖片到訓練集和測試集,其中4張爲異常留在原始目錄
測試集數量爲:504
訓練集數量爲:9586
複製代碼

2.4 訓練模型

建立好訓練集和測試集以後,就能夠開始訓練模型了。
訓練的過程當中會輸出日誌,日誌展現當前的訓練輪數、準確率和loss。
此時的準確率是訓練集圖片的準確率,表明訓練集的圖片識別狀況
例如:

第10次訓練 >>> 準確率爲 1.0 >>> loss 0.0019966468680649996
複製代碼

這裏不具體介紹tensorflow安裝相關問題,直奔主題。
確保圖片相關參數和目錄設置正確後,執行如下命令開始訓練:

python3 train_model.py
複製代碼

也能夠調用類開始訓練或執行一次簡單的識別演示

from train_model import TrainModel
from sample import sample_conf

# 導入配置
train_image_dir = sample_conf["train_image_dir"]
char_set = sample_conf["char_set"]
model_save_dir = sample_conf["model_save_dir"]

# verify參數默認爲False,當verify=True則會在訓練前校驗全部圖片格式時候爲指定的後綴
tm = TrainModel(train_image_dir, char_set, model_save_dir, verify=False)

tm.train_cnn()  # 執行訓練

tm.recognize_captcha()  # 識別演示

複製代碼

2018.11.26 新增train_model_v2.py文件
一樣是訓練模型的腳本,在訓練過程當中增長了識別測試集的並輸出準確率的過程,例如:

第480次訓練 >>> [訓練集] 準確率爲 1.0 >>> loss 0.0017373242881149054
            >>> [驗證集] 準確率爲 0.9500000095367432 >>> loss 0.0017373242881149054
驗證集準確率達到99%,保存模型成功
複製代碼

因爲訓練集中經常不包含全部的樣本特徵,因此會出現訓練集準確率是100%而測試集準確率不足100%的狀況,此時提高準確率的一個解決方案是增長正確標記後的負樣本。

2.5 批量驗證

使用測試集的圖片進行驗證,輸出準確率。

python3 test_batch.py
複製代碼

也能夠調用類進行驗證

from test_batch import TestBatch
from sample import sample_conf

# 導入配置
test_image_dir = sample_conf["test_image_dir"]
model_save_dir = sample_conf["model_save_dir"]
char_set = sample_conf["char_set"]
total = 100  # 驗證的圖片總量

tb = TestBatch(test_image_dir, char_set, model_save_dir, total)
tb.test_batch()  # 開始驗證

複製代碼

2.6 啓動WebServer

項目已經封裝好加載模型和識別圖片的類,啓動web server後調用接口就可使用識別服務。
啓動web server

python3 recognize_api.py
複製代碼

接口url爲http://127.0.0.1:6000/b

2.7 調用接口

使用requests調用接口:

url = "http://127.0.0.1:6000/b"
files = {'image_file': (image_file_name, open('captcha.jpg', 'rb'), 'application')}
r = requests.post(url=url, files=files)
複製代碼

返回的結果是一個json:

{
    'time': '1542017705.9152594',
    'value': 'jsp1',
}
複製代碼

文件recognize_online.py是使用接口在線識別的例子

2.8 部署

部署的時候,把recognize_api.py文件的最後一行修改成以下內容:

app.run(host='0.0.0.0',port=5000,debug=False)
複製代碼

而後開啓端口訪問權限,就能夠經過外網訪問了。
另外爲了開啓多進程處理請求,可使用uwsgi+nginx組合進行部署。
這部分能夠參考:Flask部署選擇

2.9 部署多個模型

部署多個模型: 在recognize_api.py文件彙總,新建一個Recognizer對象;
並參照原有up_image函數編寫的路由和識別邏輯。

Q = Recognizer(image_height, image_width, max_captcha, char_set, model_save_dir)
複製代碼

注意修改這一行:

value = Q.rec_image(img)
複製代碼

2.10 壓力測試和統計數據

提供了一個簡易的壓力測試腳本,能夠統計api運行過程當中識別耗時和請求耗時的相關數據,不過圖須要本身用Excel拉出來。
打開文件recognize_time_test.py,修改main函數下的test_file路徑,這裏會重複使用一張圖片來訪問是被接口。
最後數據會儲存在test.csv文件中。
使用以下命令運行:

python3 recognize_time_test.py
----輸出以下
2938,5150,13:30:25,總耗時:29ms,識別:15ms,請求:14ms
2939,5150,13:30:25,總耗時:41ms,識別:21ms,請求:20ms
2940,5150,13:30:25,總耗時:47ms,識別:16ms,請求:31ms
複製代碼

這裏對一個模型進行了兩萬次測試後,一組數據test.csv。 把test.csv使用箱線圖進行分析後能夠看到:

在這裏插入圖片描述

  • 單次請求API總耗時(平均值):27ms
  • 單次識別耗時(平均值):12ms
  • 每次請求耗時(平均值):15ms
    其中有:請求API總耗時 = 識別耗時 + 請求耗時

3 說明

  1. 目前沒有保存用於tensorboard的日誌文件

4 已知BUG

  1. 使用pycharm啓動recognize_api.py文件報錯
2018-12-01 00:35:15.106333: W T:\src\github\tensorflow\tensorflow\core\framework\op_kernel.cc:1273] OP_REQUIRES failed at save_restore_tensor.cc:170 : Invalid argument: Unsuccessful TensorSliceReader constructor: Failed to get matching files on ./model/: Not found: FindFirstFile failed for: ./model : ϵͳ�Ҳ���ָ����·����
; No such process
......
tensorflow.python.framework.errors_impl.InvalidArgumentError: Unsuccessful TensorSliceReader constructor: Failed to get matching files on ./model/: Not found: FindFirstFile failed for: ./model : ϵͳ\udcd5Ҳ\udcbb\udcb5\udcbdָ\udcb6\udca8\udcb5\udcc4·\udcbe\udcb6\udca1\udca3
; No such process
	 [[Node: save/RestoreV2 = RestoreV2[dtypes=[DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT, DT_FLOAT], _device="/job:localhost/replica:0/task:0/device:CPU:0"](_arg_save/Const_0_0, save/RestoreV2/tensor_names, save/RestoreV2/shape_and_slices)]]
複製代碼

由pycharm默認設置了工做空間,致使讀取相對路徑的model文件夾出錯。 解決辦法:編輯運行配置,設置工做空間爲項目目錄便可。

在這裏插入圖片描述

  1. FileNotFoundError: [Errno 2] No such file or directory: 'xxxxxx'
    目錄下有文件夾不存在,在指定目錄建立好文件夾便可。

  2. api程序在運行過程當中內存越佔越大
    結果查閱資料:連接
    在迭代循環時,不能再包含任何張量的計算表達式,否在會內存溢出。 將張量的計算表達式放到init初始化執行後,識別速度獲得極大的提高。

  3. 加載多個模型報錯 緣由是兩個Recognizer對象都使用了默認的Graph。 解決辦法是在建立對象的時候不使用默認Graph,新建graph,這樣每一個Recognizer都使用不一樣的graph,就不會衝突了。

  4. Flask程序的併發運行 暫缺,可使用flask+uwsgi實現

相關文章
相關標籤/搜索