SSD: Single Shot MultiBox Detector 檢測單張圖片

前言

博主也算是剛開始研究SSD項目,之前寫了一篇SSD:Single Shot MultiBox Detector的安裝配置和運行,這次是簡單介紹下如何用SSD檢測單張圖片,其實過程也比較簡單,下面正式開始。

準備工作

當然,首先你要把SSD按照教程編譯好,設置好python環境變量(相當重要),然後重啓計算機(建議),開始本次工作。SSD項目檢測單張圖片有C++程序和ipython程序,這裏建議用ipython,主要是方便簡單(最近新增了C++程序使用說明)。該工具路徑爲/home/mx/caffe/example/ssd_detect.ipynb,使用jupyter notebook工具操作。SSD項目常在更新,如果有模型不匹配的問題(報錯信息爲:shape mismatch. Source param shape is 12 512 3 3 (55296); target param shape is 16 512 3 3 (73728)),請去github下載最新的文件,包括代碼和模型

安裝 jupyter notebook

這裏用pip安裝該工具,安裝pip的過的可以跳過下面一段:
下載安裝包pip壓縮包解壓之後,發現裏面有個setup.py文件,終端運行:

$ sudo python setup.py install

這樣,pip就安裝上了。
下面用pip安裝jupyter notebook

#這裏臨時使用了清華大學的源,使用前後是蝸牛和火箭的速度對比
$ sudo pip install jupyter -i https://pypi.tuna.tsinghua.edu.cn/simple 

安裝成功後,運行notebook

$ jupyter notebook

程序會在瀏覽器中打開notebook, 點擊右上角的New-python2, 就可以新建一個網頁一樣的文件,擴展名爲ipynb。在這個網頁上,我們就可以像在命令行下面一樣運行python代碼了。輸入代碼後,按shift+enter運行,更多的快捷鍵,可點擊上方的help-Keyboard shortcuts查看,或者先按esc退出編輯狀態,再按h鍵查看。

這裏寫圖片描述

下載SSD模型

該工具使用的模型是VGG_VOC0712_SSD_300x300_iter_120000.caffemodel(以前是60000,作者更新了),爲了第一次就成功,我們就用它了,這是下載地址 ,下載完後解壓,把裏面的VGGNet文件夾移動到/home/mx/caffe/models/之下。當然,你掌握這個程序後,完全可以修改路徑,檢測其他模型的效果。

順便說下,部分人下載運行上述SSD模型會報錯,有些錯誤很難排查,可以使用我正在使用的SSD300模型,暫時沒有問題(對應的是最新的SSD代碼):https://pan.baidu.com/s/1eSECLEU

運行程序檢測單張圖片

$ cd /home/mx/caffe/examples # 在該目錄下打開jupyter notebook
$ jupyter notebook

在jupyter notebook打開的網頁中找到ssd_detect.ipynb,打開後發現是這樣:

這裏寫圖片描述

完整的程序我就不放出來了,你打開都和我一樣,然後檢查下面4個路徑是否正確:

labelmap_file = 'data/VOC0712/labelmap_voc.prototxt'
model_def = 'models/VGGNet/VOC0712/SSD_300x300/deploy.prototxt'
model_weights = 'models/VGGNet/VOC0712/SSD_300x300/VGG_VOC0712_SSD_300x300_iter_120000.caffemodel'
image = caffe.io.load_image('examples/images/cat.jpg')

如果檢查無誤,就可以開始從頭shift+enter運行了,一般會正常運行,也可能會出錯,比如我就遇到如下錯誤:

這裏寫圖片描述

我的辦法是,把caffe路徑換成絕對路徑:

把 caffe_root = ‘../’ 換成 caffe_root = ‘/home/mx/caffe/’ ,理論上不會再出錯了,然後在諸如labelmp的路徑前面添加caffe_root構成完整的絕對路徑,比如:labelmap_file = caffe_root+’data/VOC0712/labelmap_voc.prototxt’

還有一種模型錯誤也很常見,NameError:name ‘net’ is not defined

在caffe加載正常的情況下出現這種錯誤,很有可能是deploy.prototxt文件的問題,如果deploy.prototxt最後一層中能查找到save_output_param超參數,刪除後能解決問題(後文有詳細說明),如果不是,那還要繼續排查。

fish-bike.jpg的檢測結果如下:

這裏寫圖片描述

換一張複雜一點的圖片image = caffe.io.load_image(‘examples/images/my-pic.jpg’) ,檢測結果如下:

這裏寫圖片描述

保存運行Python文件

看來效果也是不錯的,但是我覺得如果不是去調試代碼,每次都打開jupyter notebook運行程序太麻煩,也不方便保存圖片之類的操作。這裏我的做法是把程序另存爲py文件(使用jupyter notebook打開ipynb文件,然後點選另存爲),稍作修改,再單獨運行這個py文件即可。改動的地方貌似只有一處,就是把get_ipython().magic(u'matplotlib inline')這句話給註釋掉,因爲脫離了jupyter notebook的環境,用不上了。然後python ssd_detect.py,代碼正常,沒有報錯,但是無法彈出窗口顯示最終的帶框圖片,上網查詢一番,原因是是默認的matplotlib的backend(後端)渲染有問題。那麼先查看目前的後端情況:

Python 2.7.12 (default, Jul  1 2016, 15:12:24) 
[GCC 5.4.0 20160609] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import matplotlib
>>> matplotlib.get_backend()
u'Agg'

目前是Agg,但爲了正確將圖像顯示在屏幕上,需要設置爲TkAgg,解決方法是安裝幾個庫文件:

$ sudo apt-get install tcl-dev tk-dev python-tk python3-tk

重啓電腦,再次查看,這裏應該是變成了TkAgg,如果沒有變化,那還可以sudo pip uninstall matplotlib 先卸載,然後pip install matplotlib 安裝回去,重啓電腦,這樣就可以確保後端設置變成TkAgg。如此設置後再運行py程序,就完全正常了,下圖爲博主的運行截圖。

這裏寫圖片描述

其實這種程序也是學習pycaffe的好幫手,推薦博文:Caffe Python 接口學習筆記,如果不懂某個函數,記得善用help,比如:

>>>import caffe
>>>help(caffe.io)

Help on module caffe.io in caffe:
NAME
    caffe.io
FILE
    /home/mx/caffe/python/caffe/io.py
CLASSES
    Transformer    
    class Transformer
     |  Transform input for feeding into a Net.
     |  
     |  Note: this is mostly for illustrative purposes and it is likely better
     |  to define your own input preprocessing routine for your needs.
     |  
     |  Parameters
     |  ----------
     |  net : a Net for which the input should be prepared
     |  
     |  Methods defined here:
     |  

附:
ssd_detect.ipynb 可運行版
ssd_detect.py

—————————————–分割線————————————-

關於ssd_detect.cpp

好像有部分同學比較關心ssd的C++檢測圖片程序,也就是ssd_detect.cpp的用法。我們知道,C++程序要經過編譯,生成可執行程序才能進行使用(把它作爲一個類來調用則是另外一回事了),這個cpp理論上也是可以編譯的,有評論說Eclipse中實現了編譯,前提是你要會配置那些依賴項,我嘗試用“g++ -o ssd_detect ssd_detect.cpp”來進行編譯,發現一直報錯,主要是找不到需要的include項,很自然的想到添加CPLUS_INCLUDE_PATH環境變量來解決,可是後來又遇到google proto等等的問題,憑我這種三流水平只能投降了,暫時宣告手動編譯cpp失敗。

其實呢,這個cpp最好是通過make命令(Makefile文件指定包含目錄和依賴項等)編譯。所以,我們在配置caffe階段make all的時候,已經從ssd_detect.cpp生成了可執行的二進制文件(留意make all命令的終端顯示就可知道),也就是ssd的C++接口程序,路徑就在caffe/build/examples/ssd/ssd_detect.bin。那好,我們先看一下它的用法。

ps:最新博客已經實現了eclipse的SSD配置,可以移步:Ubuntu 16.04使用Eclipse運行SSD-Caffe的cpp代碼

終端輸入:

$ cd caffe
$ build/examples/ssd/ssd_detect.bin
#使用方法說明
ssd_detect.bin: Do detection using SSD mode.
Usage:
    ssd_detect [FLAGS] model_file weights_file list_file


  Flags from examples/ssd/ssd_detect.cpp:
    -confidence_threshold (Only store detections with score higher than the
      threshold.) type: double default: 0.01
    -file_type (The file type in the list_file. Currently support image and
      video.) type: string default: "image"
    -mean_file (The mean file used to subtract from the input image.)
      type: string default: ""
    -mean_value (If specified, can be one value or can be same as image
      channels - would subtract from the corresponding channel). Separated by
      ','.Either mean_file or mean_value should be provided, not both.)
      type: string default: "104,117,123"
    -out_file (If provided, store the detection results in the out_file.)
      type: string default: ""

可以看到,該程序需要三個必選參數以及一些可選參數,必選參數首先是model_file,也就是檢測模型描述文件;然後是weights_file,網絡權值文件;list_file,待檢測文件,格式爲txt,裏面列出檢測圖片/視頻的路徑。可選參數包括閾值、文件格式、均值文件、圖片均值、輸出文件這些,都有解釋,一看就懂。

運行一個命令試試:

$ cd caffe
$ build/examples/ssd/ssd_detect.bin models/VGGNet/VOC0712/SSD_300x300/deploy.prototxt models/VGGNet/VOC0712/SSD_300x300/VGG_VOC0712_SSD_300x300_iter_120000.caffemodel examples/images/test.txt 

其中test.txt內容爲“examples/images/cat.jpg”,是待檢測圖片的路徑,可以寫多行。

呵呵,又報錯了:“ImportError: libcaffe.so.1.0.0-rc3: cannot open shared object file: No such file or directory”,還好這個錯誤在本人知識範圍內,也就是靜態鏈接庫的問題,so easy。

$ cd /etc/ld.so.conf.d
$ sudo vi caffe.conf 
# conf文件加入 /home/mx/caffe/.build_release/lib,保存退出
sudo ldconfig

也有可能會出現這種錯誤:terminate called after throwing an instance of ‘boost::filesystem::filesystem_error’ what(): boost::filesystem::create_directories: Permission denied: “/home-2/wliu/data/VOCdevkit/results/VOC2007/SSD_300x300”。原因是作者提供的最新SSD300模型中deploy.prototxt裏面有些東西(代碼如下)沒有刪乾淨,找到最後一層,直接把超參數save_output_param整個刪掉(也可以替換爲個人路徑)。

save_output_param {
      output_directory: "/home-2/wliu/data/VOCdevkit/results/VOC2007/SSD_300x300/Main"
      output_name_prefix: "comp4_det_test_"
      output_format: "VOC"
      label_map_file: "data/VOC0712/labelmap_voc.prototxt"
      name_size_file: "data/VOC0712/test_name_size.txt"
      num_test_image: 4952
    } #deploy.prototxt的錯誤代碼,裏面是原作者個人路徑,可以直接刪除

然後重新運行檢測命令,這次有結果了:examples/images/cat.jpg 8 0.999853 163 38 350 358

這個C++程序目前只能得到這樣的描述結果,想要可視化的結果要麼寫一個程序讀取裏面的文本信息,然後用opencv畫框;也可以修改源cpp程序重新編譯,這個還沒嘗試,等有空了研究。

複雜一些的例子,檢測視頻(得到的結果也是每一幀的文本描述),改變閾值並保存檢測結果:

$ build/examples/ssd/ssd_detect.bin models/VGGNet/VOC0712/SSD_300x300/deploy.prototxt models/VGGNet/VOC0712/SSD_300x300/VGG_VOC0712_SSD_300x300_iter_120000.caffemodel examples/videos/test.txt --file_type video --out_file output.txt --confidence_threshold 0.4 #檢測視頻,閾值爲0.4並保存結果

ssd_detect.cpp檢測結果的可視化

之前博主說過,只用ssd_detect.bin檢測圖片,只能得到一些文本描述結果,大家想要的其實是可視化的帶框圖片。原本還想自己寫一個小程序實現,結果是我想多了,作者已經在新一版的SSD中增加了這一功能,具體而言,就是examples/ssd/plot_detections.py文件。下面來說說怎麼用。

首先想到這個py文件多半是讀取一些參數(examples/images/cat.jpg 8 0.999853 163 38 350 358這種)才能畫框,那麼打開這個py文件,找一下接口部分:

if __name__ == "__main__":
    parser = argparse.ArgumentParser(
            description = "Plot the detection results output by ssd_detect.")
    parser.add_argument("resultfile",
            help = "A file which contains all the detection results.")
    parser.add_argument("imgdir",
            help = "A directory which contains the images.")
    parser.add_argument("--labelmap-file", default="",
            help = "A file which contains the LabelMap.")
    parser.add_argument("--visualize-threshold", default=0.01, type=float,
            help = "Display detections with score higher than the threshold.")
    parser.add_argument("--save-dir", default="",
            help = "A directory which saves the image with detection results.")
    parser.add_argument("--display-classes", default=None,
            help = "If provided, only display specified class. Separate by ','")

果不其然,包含2個必選參數和4個可選參數。必選參數是檢測結果文件txt、原始圖片文件夾;可選參數有labelmap.prototxt、篩選閾值、保存路徑、特定的類別(比如只顯示汽車的檢測結果)。

先前已經用ssd_detect.bin得到了自帶圖片的檢測結果,存爲result.txt:

examples/images/cat.jpg 8 0.999429 169 26 347 356
examples/images/cropped_panda.jpg 12 0.975958 0 1 95 97
examples/images/fish-bike.jpg 2 0.717551 52 81 448 307
examples/images/fish-bike.jpg 15 0.99994 204 3 344 170

下面開工,用一下這個py文件:

$ python examples/ssd/plot_detections.py examples/images/result.txt examples/images --labelmap-file data/VOC0712/labelmap_voc.prototxt --save-dir examples/

立馬報錯:

examples/images/examples/images/cat.jpg does not exist
examples/images/examples/images/cropped_panda.jpg does not exist
examples/images/examples/images/fish-bike.jpg does not exist

看來圖片路徑沒對,txt中已經有了圖片路徑,造成路徑重複,這個參數不能這麼寫,但是不寫肯定不行。動下腦筋,變成絕對路徑不就行了嗎。

$ python examples/ssd/plot_detections.py examples/images/result.txt /home/mx/caffe --labelmap-file data/VOC0712/labelmap_voc.prototxt --save-dir examples/

現在好了,在examples文件夾下找到了三張圖片,已經畫好框,大功告成。
這裏寫圖片描述
這裏寫圖片描述
這裏寫圖片描述

發佈了34 篇原創文章 · 獲贊 360 · 訪問量 73萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章