Dlib 好用的的Machine learning工具 (一)

看到這張Akai在凌陽盃壘球比賽時英勇的揮棒畫面,我們很容易的在腦海裏反射出這些東西:紅色的襯衫、球棒、好多位坐著的觀眾、放置地上的球棒手套、沙地…但對於電腦來說,要像人類這樣辨識出相片中的影像可是不容易的,但由於近年來電腦視覺技術與機器學習高速的發展,要讓電腦看懂一張相片已經不再是天馬行空的事了。

C:\Users\ch.tseng\Downloads\28227734250_ee45d68eed_z.jpg

例如,這張相片在上傳時,Flickr網路相薄背後的電腦視覺與機器學習技術便在高速運作了,上傳完成後Flickr大致看懂了這張相片,並給予它下列幾個tags:outdoor、sport、ball game、field game。

        Flickr是如何看出這張相片是屬於outdoor、sport而且是ball game呢?這就是接下來我們要開始study的影像識別技術。

最簡單的物件偵測技術

最基本的物件偵測方式就是Template matching,例如,我們要偵測相片有沒有這樣的便當盒,只要使用OpenCV提供的matchTemplate指令:

 result = cv2.matchTemplate(source, template, cv2.TM_CCOEFF)C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp22.png

 (minVal, maxVal, minLoc, (x, y)) = cv2.minMaxLoc(result)

便能簡單快速的在相片中尋找該物體。這個指令會依序的從左上至右下,每個像素依序比對是否有與Template圖片相符合的區域,有的話則認定該物體存在於該相片中。

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp23.png

        不過,您應該也看出這個方法的缺點:Template必須與圖片中的圖形一模一樣,不可變形旋轉、色差、放大縮小…等,因此實際應用時Template matching方法並不實用。

在開始深入影像識別技術之前,我們可以先試看看dlib這套容易上手的機器學習系統,體驗一下這令人炫目的技術是如何運作的。

DLIB

dlib是一套包含了機器學習、計算機視覺、圖像處理等的函式庫,使用C++開發而成,目前廣泛使用於工業及學術界,也應用在機器人、嵌入式系統、手機、甚至於大型的運算架構中,而且最重要的是,它不但開源且完全免費,而且可跨平台使用(Linux、Mac OS、Windows),並且除了C++之外還提供了Python API ,因此如果我們想要建立一套物件偵測系統,dlib是相當適合的平台。

開發者是Davis King,您可以到他的網站http://blog.dlib.net看看他如何使用dlib。

安裝dlib

Dlib安裝可參考官方的http://dlib.net/compile.html,如果在python中可正常import,即表示安裝成功。

$ python

>>> import dlib

Technet-256 dataset

裝好了dlib,下面我們馬上利用它來訓練物體辨識的工作。不過一般人要作影像的學習辨識,首先面臨的最大問題就是訓練用的影像資料來源取得不易,在這裏我們建議可以採用被廣泛應用於學術界及商業界,而且免費的Caltech-101影像資料集。

不知道您有沒有留意到這個新聞,也就是最近Google挖角了多位專家成立機器學習部門,其中包含了兩位華人女性http://udn.com/news/story/6812/2133419,其中的一位李飛飛可是世界上頂尖的計算機視覺專家之一,網路上關於她的介紹文章也非常多,有興趣可以Google瞭解一下。這個Technet-256資料集以及知名的ImageNet就是由她所創立的,。

5771e27b44f32

        在下面的示範中,我們將使用她所release出來讓大眾公開使用的影像資料庫Caltech-101,這個資料集包含了101種類別、每種類別約有40到800張含有各種物件的影像,尺寸為200×300 pixels,這是由李飛飛和另外兩位Marco Andreetto及Marc ‘Aurelio Ranzato共同收集並於2003年九月release公開。除了Caltech-101,該網站上還有更大的資料集Caltech-256,擁有3,067影像256種類別的Caltech-256,也是提供大眾無償使用。

下載Caltech-101

Caltech-101資料集請至http://www.vision.caltech.edu/Image_Datasets/Caltech101/下載,約有131MB大小,另外也需要一併下載Outlines of objects in the picture Annotations.tar。

Annotations.tar是matlab script格式,它描述了每張影像中物件的座標尺寸,可方便機器進行物件的辨識學習。例如,在hawksbill(玳瑁)類別的這張照片,透過Annotations資訊,機器不僅可學習到該張相片的類別(資料夾名稱),亦可從Annotations方框中的影像學習其物件特徵:

程式內容

第一段程式

我們先看第一段程式:


#匯入必要的library
from __future__ import print_function
from imutils import paths
from scipy.io import loadmat
from skimage import io
import argparse
import dlib

#讀入相關的參數
ap = argparse.ArgumentParser()
ap.add_argument("-c", "--class", required=True, help="Path to the CALTECH-101 class images")
ap.add_argument("-a", "--annotations", required=True, help="Path to the CALTECH-101 class annotations")
ap.add_argument("-o", "--output", required=True, help="Path to the output detector")
args = vars(ap.parse_args())

from scipy.io import loadmat這行是為了讀取Annotation的Matlab .mat檔案格式。

另外,由於dlib Python API與scikit-image搭配使用相當方便,因此在這裏我們使用scikit-image而沒有用OpenCV。

第二段程式

Dlib提供了一組預設的參數方便我們直接使用,我們可透過下面方式來看看這些參數的內容,在稍後的程式中我們將使用這預設的參數:

>>> import dlib

>>> options = dlib.simple_object_detector_training_options()

>>> fpr opt in dir(options):

>>> for opt in dir(options):

…    print opt

C

__class__

__delattr__

__dict__

__doc__

__format__

__getattribute__

__hash__

__init__

__instance_size__

__module__

__new__

__reduce__

__reduce_ex__

__repr__

__setattr__

__sizeof__

__str__

__subclasshook__

__weakref__

add_left_right_image_flips

be_verbose

detection_window_size

epsilon

num_threads

上述的引入預設參數就在第二段程式的第一行。


options = dlib.simple_object_detector_training_options()
images = [] #存放相片圖檔
boxes = [] #存放Annotations

#依序處理path下的每張圖片
for imagePath in paths.list_images(args["class"]):
#從圖片路徑名稱中取出ImageID
imageID = imagePath[imagePath.rfind("/") + 1:].split("_")[1]
imageID = imageID.replace(".jpg", "")
#載入Annotation
p = "{}/annotation_{}.mat".format(args["annotations"], imageID)
annotations = loadmat(p)["box_coord"]

#取出annotations資訊繪成矩形物件,放入boxes變數中。
bb = [dlib.rectangle(left=long(x), top=long(y), right=long(w), bottom=long(h))
for (y, h, x, w) in annotations]
boxes.append(bb)

#將圖片放入images變數
images.append(io.imread(imagePath))

上面的程式最主要是將由annotations取出後產生矩形物件放入boxes變數,再將影像物件放入images變數,這兩個變數是後面dlib進行影像識別訓練時所需要使用的。

第三段程式

接下來是最重要的,也就是機器學習的部份,不過反而這段是最簡單的,因為大部份工作dlib已經替我們處理了。因此,我們可只要放入剛剛我們處理好的三個參數:images, boxes, options,執行dlib.train_simple_object_detector指令就可以了。


#丟入三個參數開始訓練
print("[INFO] training detector...")
detector = dlib.train_simple_object_detector(images, boxes, options)

# 將訓練結果匯出到檔案
print("[INFO] dumping classifier to file...")
detector.save(args["output"])

# 圖形化顯示Histogram of Oriented Gradients(簡稱HOG)
win = dlib.image_window()
win.set_image(detector)
dlib.hit_enter_to_continue()

 

訓練

我們就來訓練讓電腦認識杯子看看,在caltech101\101_ObjectCategories\cup目錄下有57張不同的杯子圖片:

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp44.png

執行上述的程式,並分別傳入下方三個藍色字體的參數,由於樣本數目少,因此不用幾分鐘就執行結束了。

python train_detector.py –class /media/sf_VM/caltech101/101_ObjectCategories/cup –annotations /media/sf_VM/caltech101/Annotations/cup –output output/cup_sign_detector.svm

[INFO] gathering images and bounding boxes…

[INFO] training detector…

[INFO] dumping classifier to file…

Hit enter to continue

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp45.png

最後顯示的那張怪異圖片是將Histogram of Oriented Gradients(HOG)資訊視覺化後的圖形,HOG翻成中文是「方向梯度直方圖」,它最重要理念在於:在一幅圖像中,局部目標的表象和形狀(appearance and shape)能夠被梯度或邊緣的方向密度分布很好地描述。(請參考wiki:https://zh.wikipedia.org/wiki/%E6%96%B9%E5%90%91%E6%A2%AF%E5%BA%A6%E7%9B%B4%E6%96%B9%E5%9B%BE)。原理部份若未來我會去瞭解並說明,不過在這裏,我們只要先知道它的意義就可以了。

測試A

訓練好了,我們要怎麼來測試電腦到底是否認得杯子了呢?我們先看看程式碼:


from imutils import paths
import argparse
import dlib
import cv2

ap = argparse.ArgumentParser()
ap.add_argument("-d", "--detector", required=True, help="Path to trained object detector")
ap.add_argument("-t", "--testing", required=True, help="Path to directory of testing images")
args = vars(ap.parse_args())

#載入訓練好的detector
detector = dlib.simple_object_detector(args["detector"])

#載入測試圖片逐張進行
for testingPath in paths.list_images(args["testing"]):
#讀取圖片並執行dector並產生矩形物件以便用於標記辨識出的部份
image = cv2.imread(testingPath)
boxes = detector(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))

#在圖片上繪出該矩形
for b in boxes:
(x, y, w, h) = (b.left(), b.top(), b.right(), b.bottom())
cv2.rectangle(image, (x, y), (w, h), (0, 255, 0), 2)

#顯示圖片
cv2.imshow("Image", image)
cv2.waitKey(0)

該程式需要兩個參數:object detector及testing images,前者是我們剛剛訓練後所匯出的cup_sign_detector.svm,後者是待測試用的圖片檔,我從網路上下載了一些圖片如下,大部份是杯子,另外也特意放了一些盤子和碗的非杯子圖片。

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp69.png

測試訓練的結果

執行:python test_detector.py –detector output/cup_sign_detector.svm –testing /media/sf_VM/cup/

正確:辨識為非杯子

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp47.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp48.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp49.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp50.png

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp51.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp53.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp54.png

可惜:沒有將杯子辨識出來

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp57.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp58.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp59.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp62.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp63.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp64.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp67.png

正確:辨識為杯子

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp55.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp56.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp60.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp61.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp65.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp66.png

很明顯的,我們訓練用的樣本數還是太少,沒有涵蓋到各種杯子的角度和種類。

測試B

我們再試看看,這次讓電腦練習辨識大象這個動物。

這些是Caltech-101提供的大象圖片,在caltech101\101_ObjectCategories\cup目錄下共有64張。

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp43.png

執行訓練:

python train_detector.py –class /media/sf_VM/caltech101/101_ObjectCategories/elephant –annotations /media/sf_VM/caltech101/Annotations/elephant –output output/elephant_sign_detector.svm

顯示HOG圖及產生elephant_sign_detector.svm。

[INFO] gathering images and bounding boxes…

[INFO] training detector…

[INFO] dumping classifier to file…

Hit enter to continue

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp42.png

從網路上隨機下載,for測試用的圖片,主要是大象,另外我特意加上了幾張貓狗及犀牛的圖片。

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp85.png

測試訓練的結果:

正確:辨識為非大象

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp70.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp72.png

可惜:沒有將大象辨識出來

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp73.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp76.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp77.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp78.png

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp80.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp86.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp88.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp89.pngC:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp87.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp82.png

錯誤:將非大象辨識為大象

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp83.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp84.png

正確:辨識為大象

C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp74.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp75.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp79.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp81.png C:\Users\CHE7C6~1.TSE\AppData\Local\Temp\x10sctmp90.png

看來要辨識不同角度不同姿態的大象並非易事,僅僅使用64個樣本來訓練是絕對不夠的。

本文中透過dlib所示範使用的演算法是HOG加上Linear SVM (Support Vector Machine支持向量機),由於使用的是預設的參數,且dlib已經自動替我們處理了底層的演算法計算,因此我們很容易就能完成所有的訓練及測試工作。

另外,我們在程式中用於訓練的Caltech-101影像資料集,雖然它使用了特定工具軟體Matlab的.mat檔案格式來定義annotations,不過如果您細看程式,會發生我們需要的僅是用於定義四方形的起始(x, y)點及width和height這四個資訊,因此如果我們要自己建立訓練用的圖庫,並不一定要沿用Matlab .mat格式,只要讓我們的程式能夠讀入每個影像的annotation這四個數值就可以了。

接下來,我們將試著使用既有的相片而非Caltech範例,並自行加上Annotations資訊,來訓練我們自己想要的物件偵測。

5 Comments

  1. 您是使用Ububtu嗎? 要不要移除boost, 再照下方範例安裝看看?

    $ sudo apt-get install build-essential cmake
    $ sudo apt-get install libgtk-3-dev
    $ sudo apt-get install libboost-all-dev

  2. 請問一下為什麼dlib 我在執行python setup.py install的時候一直顯示boost not found呢?
    boost 也裝了 BOOST_ROOT跟BOOST_LIBRARYDIR也設定了可是還是顯示not found
    查了很多相關問題可是還是沒辦法解決,不知道是否哪個步驟出錯了呢謝謝!

迴響已關閉。