看到這張Akai在凌陽盃壘球比賽時英勇的揮棒畫面,我們很容易的在腦海裏反射出這些東西:紅色的襯衫、球棒、好多位坐著的觀眾、放置地上的球棒手套、沙地…但對於電腦來說,要像人類這樣辨識出相片中的影像可是不容易的,但由於近年來電腦視覺技術與機器學習高速的發展,要讓電腦看懂一張相片已經不再是天馬行空的事了。
例如,這張相片在上傳時,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)
(minVal, maxVal, minLoc, (x, y)) = cv2.minMaxLoc(result)
便能簡單快速的在相片中尋找該物體。這個指令會依序的從左上至右下,每個像素依序比對是否有與Template圖片相符合的區域,有的話則認定該物體存在於該相片中。
不過,您應該也看出這個方法的缺點: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就是由她所創立的,。
在下面的示範中,我們將使用她所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張不同的杯子圖片:
執行上述的程式,並分別傳入下方三個藍色字體的參數,由於樣本數目少,因此不用幾分鐘就執行結束了。
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
最後顯示的那張怪異圖片是將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,後者是待測試用的圖片檔,我從網路上下載了一些圖片如下,大部份是杯子,另外也特意放了一些盤子和碗的非杯子圖片。
測試訓練的結果
執行:python test_detector.py –detector output/cup_sign_detector.svm –testing /media/sf_VM/cup/
正確:辨識為非杯子
可惜:沒有將杯子辨識出來
正確:辨識為杯子
很明顯的,我們訓練用的樣本數還是太少,沒有涵蓋到各種杯子的角度和種類。
測試B
我們再試看看,這次讓電腦練習辨識大象這個動物。
這些是Caltech-101提供的大象圖片,在caltech101\101_ObjectCategories\cup目錄下共有64張。
執行訓練:
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
從網路上隨機下載,for測試用的圖片,主要是大象,另外我特意加上了幾張貓狗及犀牛的圖片。
測試訓練的結果:
正確:辨識為非大象
可惜:沒有將大象辨識出來
錯誤:將非大象辨識為大象
正確:辨識為大象
看來要辨識不同角度不同姿態的大象並非易事,僅僅使用64個樣本來訓練是絕對不夠的。
本文中透過dlib所示範使用的演算法是HOG加上Linear SVM (Support Vector Machine支持向量機),由於使用的是預設的參數,且dlib已經自動替我們處理了底層的演算法計算,因此我們很容易就能完成所有的訓練及測試工作。
另外,我們在程式中用於訓練的Caltech-101影像資料集,雖然它使用了特定工具軟體Matlab的.mat檔案格式來定義annotations,不過如果您細看程式,會發生我們需要的僅是用於定義四方形的起始(x, y)點及width和height這四個資訊,因此如果我們要自己建立訓練用的圖庫,並不一定要沿用Matlab .mat格式,只要讓我們的程式能夠讀入每個影像的annotation這四個數值就可以了。
接下來,我們將試著使用既有的相片而非Caltech範例,並自行加上Annotations資訊,來訓練我們自己想要的物件偵測。
您可以search Dlib for iOs 或Android,就可以得到答案了哦。
不好意思又來請教您 若使用這種方法辨識,是有辦法將程式打包到app裡面嗎? 還是只能在server端執行呢
我是使用Windows boost版本我都試過了可是還是顯示not found 還是我哪裡環境沒有建置好呢謝謝您的回答!
您是使用Ububtu嗎? 要不要移除boost, 再照下方範例安裝看看?
$ sudo apt-get install build-essential cmake
$ sudo apt-get install libgtk-3-dev
$ sudo apt-get install libboost-all-dev
請問一下為什麼dlib 我在執行python setup.py install的時候一直顯示boost not found呢?
boost 也裝了 BOOST_ROOT跟BOOST_LIBRARYDIR也設定了可是還是顯示not found
查了很多相關問題可是還是沒辦法解決,不知道是否哪個步驟出錯了呢謝謝!