1. 程式人生 > >【AI實戰】手把手教你文字識別(檢測篇二:AdvancedEAST、PixelLink方法)

【AI實戰】手把手教你文字識別(檢測篇二:AdvancedEAST、PixelLink方法)

 
自然場景下的文字檢測是深度學習的重要應用,在之前的文章中已經介紹過了在簡單場景、複雜場景下的文字檢測方法,包括MSER+NMS、CTPN、SegLink、EAST等方法,詳見文章:

【AI實戰】手把手教你文字識別(檢測篇一:  MSER、CTPN、SegLink、EAST方法)

今天將繼續介紹複雜場景下基於深度學習的文字檢測方法,手把手教你如何使用AdvancedEAST、PixelLink進行文字檢測。

1、AdvancedEAST方法實戰
在上一篇文字檢測的AI實戰文章中,介紹了EAST檢測方式,取得了不錯的檢測效果,但是在長文字預測中效果還不是很理想。於是,有大牛對EAST檢測方法進行了改進,獲得了比EAST更好的預測準確性(特別是在長文字上),並開源了原始碼,這就是AdvancedEAST方法。網路結構如下:

 
AdvancedEAST的網路結構與EAST相似(EAST技術原理詳見文章:大話文字檢測經典模型EAST),但採用了VGG作為網路主幹結構,基於Keras編寫,在特徵提取層中增加了後面卷積層的通道數量,對後處理方法也進行了優化。下面動手來試試AdvancedEAST的實際檢測效果吧。
(1)下載原始碼
 
首先,在github上下載AdvancedEAST原始碼(https://github.com/huoyijie/AdvancedEAST),可直接下載成zip壓縮包或者git克隆

git clone https://github.com/huoyijie/AdvancedEAST.git

(2)下載模型檔案
下載AdvancedEAST預訓練好的模型,下載連結: https://pan.baidu.com/s/1KO7tR_MW767ggmbTjIJpuQ 提取碼: kpm2
建立資料夾saved_model,將下載後的模型檔案解壓後放到裡面
 
修改cfg.py檔案裡面的train_task_id,將該id修改與下載的預訓練模型一致,以便於在執行程式時,可自動載入模型,修改如下:

train_task_id = ‘3T736’

下載keras的VGG預訓練模型,因為AdvancedEAST使用了VGG作為網路的主幹結構,因此,在呼叫keras時會載入VGG預訓練模型,下載地址為https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5,然後放到keras載入模型的預設路徑,目錄如下:

~/.keras/model

如果沒有手動下載,那麼在載入keras的VGG模型時,程式也會自動下載,但一般速度會很慢,經常會超時

(3)準備基礎環境
AdvancedEAST依賴於以下的基礎環境,使用conda或pip進行安裝準備。

  • python 3.6.3+
  • tensorflow-gpu 1.5.0+(or tensorflow 1.5.0+)
  • keras 2.1.4+
  • numpy 1.14.1+
  • tqdm 4.19.7+

(4)AdvancedEAST檢測文字
執行python predict.py進行文字檢測
 
預設讀取專案自帶的demo/012.png檔案,進行檢測
 
檢測後生成以下檔案
 
其中,012.png_act.jpg是檢測過程的結果
 
012.png_predict.jpg是檢測出最終文字框的圈定結果
 
012.txt是檢測文字框的位置座標(4個頂點)
 
在執行模型時,其中會有少部分檢測結果是不完整的(邊框少於4個頂點),預設會顯示出來
 
可通過在predict.py的原始碼中,讓其保持靜默(不提示不完整的檢測結果),修改最後一行為

predict(east_detect, img_path, threshold, quiet=True)

如果要檢測指定的圖片,在執行python predict.py時,可通過增加引數指定圖片路徑。另外,還可指定閾值,即在做畫素分類判斷是否為文字的閾值,預設為0.9。執行命令如下:

python predict.py --path=/data/work/tensorflow/data/icdar_datasets/ICDAR2015/ch4_test_images/img_364.jpg --threshold=0.9

執行效果如下:
 

(5)AdvancedEAST介面封裝
為了方便其它程式呼叫AdvancedEAST的文字檢測能力,在predict.py的基礎上進行程式碼修改,對AdvancedEAST進行介面封裝,核心程式碼如下:

# sigmoid 函式
def sigmoid(x):
    return 1 / (1 + np.exp(-x))

# AdvancedEAST 模型
def east_detect():
    east = East()
    east_detect = east.east_network()
    east_detect.load_weights(cfg.saved_model_weights_file_path)
    return east_detect

# 基於 Advanced EAST 的文字檢測
# 輸入:AdvancedEAST模型,圖片路徑,畫素分類閾值
# 返回:檢測後文本框的位置資訊
def text_detect(east_detect,img_path,pixel_threshold=0.9):
    img = image.load_img(img_path)
    d_wight, d_height = resize_image(img, cfg.max_predict_img_size)
    scale_ratio_w = d_wight / img.width
    scale_ratio_h = d_height / img.height
    img = img.resize((d_wight, d_height), Image.NEAREST).convert('RGB')
    img = image.img_to_array(img)
    img = preprocess_input(img, mode='tf')

    x = np.expand_dims(img, axis=0)
    y = east_detect.predict(x)

    y = np.squeeze(y, axis=0)
    y[:, :, :3] = sigmoid(y[:, :, :3])
    cond = np.greater_equal(y[:, :, 0], pixel_threshold)
    activation_pixels = np.where(cond)
    quad_scores, quad_after_nms = nms(y, activation_pixels)

    bboxes = []
    for score, geo in zip(quad_scores, quad_after_nms):
        if np.amin(score) > 0:
            rescaled_geo = geo / [scale_ratio_w, scale_ratio_h]
            rescaled_geo_list = np.reshape(rescaled_geo, (8,)).tolist()
            bboxes.append(rescaled_geo_list)

    return bboxes

 

2、Pixel Link方法實戰
前面介紹的文字檢測方法,一般都是執行兩個預測:通過分類判斷是文字/非文字,通過迴歸確定邊界框的位置和角度。其中,迴歸的耗時比分類要多得多,而PixelLink(畫素連線)方法則全部都是通過“分類”的方式實現文字/非文字的判斷,並同時給出文字框的位置和角度,具體技術原理詳見之前的文章:大話文字檢測經典模型PixelLink
PixelLink的整體框架如下圖:
 
下面介紹如何使用PixelLink模型來檢測文字。
(1)下載原始碼和模型
 
首先,在github上下載PixelLink原始碼(https://github.com/ZJULearning/pixel_link),可直接下載成zip壓縮包或者git克隆

git clone https://github.com/ZJULearning/pixel_link.git

下載pylib,下載路徑為https://github.com/dengdan/pylib/tree/e749559c9a4bcee3339081ec2d159a6dcf41636e ,解壓後將src目錄中的util資料夾放到pylib目錄下面,然後新增到環境變數,在test_pixel_link.py , test_pixel_link_on_any_image.py, visualize_detection_result.py,  datasets/dataset_utils.py的前面加上

import sys
sys.path.append('/data/work/tensorflow/model/pixel_link/pixel_link-master/pylib')
sys.path.append('/data/work/tensorflow/model/pixel_link/pixel_link-master/pylib/util')

或者在當前視窗執行以下命令,或在 /etc/profile,~/.bashrc 檔案中新增以下命令

export PYTHONPATH=xx:$PYTHONPATH

下載基於IC15資料集預訓練好的模型,作者提供了兩個預訓練好的模型PixelLink + VGG16 4s (下載地址 https://pan.baidu.com/s/1jsOc-cutC4GyF-wMMyj5-w),PixelLink + VGG16 2s(下載地址 https://pan.baidu.com/s/1asSFsRSgviU2GnvGt2lAUw)

新建資料夾models/4s和models/2s,解壓模型壓縮檔案,將兩個模型放入到相應的目錄下,方便進行呼叫

(2)安裝基礎環境
在下載的原始碼檔案中pixel_link_env.txt檔案提供了conda基礎環境安裝包,其中,由於現在清華的conda映象源已停止服務,於是將其替換為中科大的conda映象源,修改後的依賴基礎環境如下:

name: pixel_link
channels:
- menpo
- https://mirrors.ustc.edu.cn/anaconda/pkgs/free
- https://mirrors.ustc.edu.cn/anaconda/pkgs/main
- defaults
dependencies:
- certifi=2016.2.28=py27_0
- cudatoolkit=7.5=2
- cudnn=5.1=0
- funcsigs=1.0.2=py27_0
- libprotobuf=3.4.0=0
- mkl=2017.0.3=0
- mock=2.0.0=py27_0
- numpy=1.12.1=py27_0
- openssl=1.0.2l=0
- pbr=1.10.0=py27_0
- pip=9.0.1=py27_1
- protobuf=3.4.0=py27_0
- python=2.7.13=0
- readline=6.2=2
- setuptools=36.4.0=py27_1
- six=1.10.0=py27_0
- sqlite=3.13.0=0
- tensorflow-gpu=1.1.0=np112py27_0
- tk=8.5.18=0
- werkzeug=0.12.2=py27_0
- wheel=0.29.0=py27_0
- zlib=1.2.11=0
- opencv=2.4.11=nppy27_0
- pip:
  - backports.functools-lru-cache==1.5
  - bottle==0.12.13
  - cycler==0.10.0
  - cython==0.28.2
  - enum34==1.1.6
  - kiwisolver==1.0.1
  - matplotlib==2.2.2
  - olefile==0.44
  - pillow==4.3.0
  - polygon2==2.0.8
  - pyparsing==2.2.0
  - python-dateutil==2.7.2
  - pytz==2018.4
  - setproctitle==1.1.10
  - subprocess32==3.2.7
  - tensorflow==1.1.0
  - virtualenv==15.1.0

使用以下命令建立pixel_link的conda虛擬環境和安裝基礎依賴包

conda env create --file pixel_link_env.txt

 
完成基礎環境包安裝之後,即可使用以下命令切換到pixel_link虛擬環境,在裡面執行相應的操作

source activate pixel_link

該原始碼提供基礎環境是基於python2版本的,如果自己之前已安裝了相應的基礎環境,即可直接使用,其中,要特別注意的是如果是使用python3,則需要對以下指令碼進行改造:

  • 修改test_pixel_link.py第94行、第156行、第164行、第166行,在print後面加上括號
  • 修改datasets/dataset_util.py第112行,在print後面加上括號
  • 修改pylib/util/plt.py第174行,在print後面加上括號
  • 修改pylib/util/img.py第8行,在print後面加上括號
  • 修改pylib/util/proc.py第29行、第30行,在print後面加上括號。第35行,在raise後面加上括號
  • 修改pylib/util/thread_.py第39行,在raise後面加上括號
  • 修改pylib/util/caffe_.py第29行、第46行、第47行、第50行,在print後面加上括號
  • 修改pixel_link.py第187行,在raise後面加上括號
  • 修改pylib/util/tf.py第46行,將xrange改為range
  • 修改models/4s/config.py第153行,將xrange改為range
  • 修改pixel_link.py第257行、第353行,將xrange改為range
  • 由於在python3中沒有cPickle,在pylib/util/io_.py中,第11行,將import cPickle as pkl改為import _pickle as pkl
  • 由於在python3中commands已由subprocess代替,在pylib/util/io_.py中,第12行,將import commands改為import subprocess as commands。在pylib/util/cmd.py中,第4行,將import commands改為import subprocess as commands
  • 在test_pixel_link.py在前面加上import util.cmd

(3)PixelLink檢測文字測試(批量圖片)
通過執行以下命令進行測試

./scripts/test.sh ${GPU_ID} ${model_path}/model.ckpt-xxx ${image_dir}

該命令由三個引數組成,第1個引數表示GPU的序號,第2個引數表示模型路徑,第3個引數表示測試圖片的目錄。
在這裡使用剛才下載的PixelLink+VGG16 4s預訓練模型,使用場景文字圖片資料集ICDAR2015進行測試(下載地址 http://rrc.cvc.uab.es/?ch=4&com=downloads),也可以使用自己的測試圖片,將測試的圖片放入到指定的目錄。
執行指令碼如下:

./scripts/test.sh 0 models/4s/model.ckpt-38055 /data/work/tensorflow/data/icdar_datasets/ICDAR2015/ ch4_test_images


 
檢測後的結果儲存在模型目錄下,結果檔案是測試圖片中的文字框位置(4個座標點),如下圖:
 
所有結果還會生成zip壓縮檔案,如下圖:

如果要使檢測結果顯性化,可通過呼叫scripts/vis.sh指令碼,將會使文字檢測的結果直接顯示在圖片上,呼叫命令為

./scripts/vis.sh ${image_dir} ${det_dir}

其中,第一個引數表示原始圖片的路徑,第二個引數表示檢測後的文字框位置檔案所在目錄,最後輸出的標示文字框圖片結果儲存在~/temp/no-use/pixel_result目錄下
執行指令碼如下

./scripts/vis.sh /data/work/tensorflow/data/icdar_datasets/ICDAR2015/ch4_test_images models/4s/test/icdar2015_test/model.ckpt-38055/txt


 

輸出的結果圖片如下

 

(4)PixelLink檢測文字測試(任意圖片)
為方便測試,可直接呼叫以下命令對任意圖片進行測試,命令如下:

./scripts/test_any.sh ${GPU_ID} ${model_path}/model.ckpt-xxx ${image_dir}

該命令由三個引數組成,第1個引數表示GPU的序號,第2個引數表示模型路徑,第3個引數表示圖片的路徑。
例如仍拿ICDAR2015的測試圖片集進行測試,執行的命令如下:

./scripts/test_any.sh 0 models/4s/model.ckpt-38055 /data/work/tensorflow/data/icdar_datasets/ICDAR2015/ ch4_test_images


 
執行後,文字的檢測結果將會直接顯示在圖片上,如下圖

 

可能會有些人有疑惑,test_any.sh命令不就是把test.sh、vis.sh兩個命令整合在一起嗎,那究竟有什麼區別呢?主要的區別如下:
a. test_any.sh命令呼叫的是test_pixel_link_on_any_image.py,而test.sh命令呼叫的是test_pixel_link.py,兩者在呼叫檢測模型時,test_pixel_link_on_any_image.py將並查集的後處理放到模型裡面,而test_pixel_link.py則是將並查集的後處理放到模型外邊。從檢測效率來看,test_pixel_link_on_any_image.py比test_pixel_link.py在速度上慢了很多,這是由於並查集處理需要大量計算,放到模型外面利用CPU計算反而更加快速
b. test_pixel_link.py只輸出文本框位置資料,而test_pixel_link_on_any_image.py直接將檢測的文字框標示到圖片上

(5)PixelLink文字檢測能力封裝
為方便其它程式呼叫PixelLink的文字檢測能力,通過對test_pixel_link.py, visualize_detection_result.py程式碼進行改造封裝,即可將文字檢測能力提供給相應的程式呼叫,核心程式碼如下:

# 模型引數
checkpoint_dir='/data/work/tensorflow/model/pixel_link/pixel_link-master/models/4s/model.ckpt-38055'
image_width = 1280
image_height = 768

# 配置初始化
def config_initialization():
    image_shape = (image_height, image_width)
        
    config.init_config(image_shape, 
                       batch_size = 1, 
                       pixel_conf_threshold = 0.8,
                       link_conf_threshold = 0.8,
                       num_gpus = 1, 
                   )
    
# 文字檢測
def text_detect(img):
    with tf.name_scope('eval'):
        image = tf.placeholder(dtype=tf.int32, shape = [None, None, 3])
        image_shape = tf.placeholder(dtype = tf.int32, shape = [3, ])
        processed_image, _, _, _, _ = ssd_vgg_preprocessing.preprocess_image(image, None, None, None, None, 
                                                   out_shape = config.image_shape,
                                                   data_format = config.data_format, 
                                                   is_training = False)
        b_image = tf.expand_dims(processed_image, axis = 0)
        net = pixel_link_symbol.PixelLinkNet(b_image, is_training = True)
        global_step = slim.get_or_create_global_step()
    
    sess_config = tf.ConfigProto(log_device_placement = False, allow_soft_placement = True)
    sess_config.gpu_options.allow_growth = True
    
    saver = tf.train.Saver()
            
    checkpoint = util.tf.get_latest_ckpt(checkpoint_dir)
    bboxes = []

    with tf.Session(config = sess_config) as sess:
        saver.restore(sess, checkpoint)
        image_data = img

        pixel_pos_scores, link_pos_scores = sess.run(
            [net.pixel_pos_scores, net.link_pos_scores], 
            feed_dict = {
                image:image_data
        })

        mask = pixel_link.decode_batch(pixel_pos_scores, link_pos_scores)[0, ...]
        bboxes = pixel_link.mask_to_bboxes(mask, image_data.shape)

    return bboxes

(6)pixellink的keras版本
剛才介紹的pixel link是基於tensorflow版本的,還有大牛使用Keras對核心程式碼進行改寫,並在github上開放了keras版本pixel link的原始碼。具體使用如下:
a. 下載原始碼
 
下載地址為https://github.com/opconty/pixellink_keras,可直接下載成zip壓縮包或者git克隆

git clone https://github.com/opconty/pixellink_keras.git

b. 下載預訓練模型
作者並沒有重新訓練模型,而是直接拿tensorflow版本的訓練模型結果PixelLink-VGG 4s,轉化為Keras的權重檔案。下載地址為https://drive.google.com/file/d/1MK0AkvBMPZ-VfKN5m4QtSWWSUqoMHY33/view?usp=sharing

c. 安裝基礎環境
除了需要安裝Keras之外,還要安裝imutils依賴包

pip install imutils

如果是使用了OpenCV 4.x,則需要修改pixellink_utils.py第220行,將cv2.findContours的返回結果由3個結果修改為2個結果,將_,cnts,_改為cnts,_

d. 執行模型
執行pixellink_eval.py,即可進行文字檢測,命令如下

python pixellink_eval.py


 
預設對專案自帶的圖片進行檢測(路徑./samples/img_1099.jpg),檢測效果如下:

 


如果要指定圖片進行檢測,可修改pixellink_eval.py檔案中第21行,將img_path修改為指定的圖片路徑,然後再執行python pixellink_eval.py即可對指定的圖片進行文字檢測

為方便介紹,以上AdvancedEAST、PixelLink的文字檢測能力封裝時,將載入模型、文字框預測、圖片繪製文字框等一些程式碼寫在一起,而在實際生產使用中,一般是將其分開。如要了解在生產環境中的詳細使用,可再私信進行交流

 

推薦相關閱讀

1、AI 實戰系列

2、大話深度學習系列

3、圖解 AI 系列

4、AI 雜談

5、大資料超詳細系列