熱門資訊
給圣誕老人一個驚喜:基于樹莓派和深度學(xué)習(xí) AI的圣誕老人檢測機(jī)
來源:3XMaker 發(fā)布時間:2018年12月22日給圣誕老人一個驚喜:基于樹莓派和深度學(xué)習(xí) AI的圣誕老人檢測機(jī)
熱門美劇《硅谷》中的人物創(chuàng)建了一個“不是熱狗”APP,可以確定輸入的照片是“熱狗”還是“不是熱狗”。這篇文章介紹如何使用Keras在Raspberry Pi上運(yùn)行一個識別圣誕老人的深度神經(jīng)網(wǎng)絡(luò),僅僅用130行代碼,成功在圣誕老人來你家時點(diǎn)亮圣誕樹同時播放圣誕歌曲來迎接!來試試看~
今天這篇文章是使用Keras在Raspberry Pi上運(yùn)行深度神經(jīng)網(wǎng)絡(luò)的一個完整指南。
我把這個項目當(dāng)做一個“不是圣誕老人”(Not Santa)檢測器,教你如何實(shí)際地實(shí)現(xiàn)它(并且過程中樂趣無窮)。
第一部分,我們說一下什么是“圣誕老人檢測器”(可能你不熟悉熱播美劇《硅谷》里的“不是熱狗”識別App,現(xiàn)在已經(jīng)有人把它實(shí)現(xiàn)了)。
然后,我們將通過安裝TensorFlow、Keras和其他一些條件來配置樹莓派進(jìn)行深度學(xué)習(xí)。
樹莓派為深度學(xué)習(xí)配置好之后,我們將繼續(xù)構(gòu)建一個Python腳本,它可以:
從磁盤加載Keras模型
訪問樹莓派相機(jī)模塊/usb網(wǎng)絡(luò)攝像頭
應(yīng)用深度學(xué)習(xí)來檢測圣誕老人是否在框內(nèi)
如果發(fā)現(xiàn)圣誕老人,就可以訪問GPIO pin并播放音樂
那么讓我們開始吧!
什么是Not Santa檢測器?
圖1:HBO美劇《硅谷》里的“不是熱狗”識別應(yīng)用程序
“不是圣誕老人”檢測器靈感來自HBO美劇《硅谷》。劇中人物創(chuàng)建了一個App,可以確定輸入的照片是“熱狗”還是“不是熱狗”。這個節(jié)目顯然是在取笑美國硅谷的創(chuàng)業(yè)文化:
對機(jī)器學(xué)習(xí)和深度學(xué)習(xí)的炒作
諷刺大量手機(jī)App都毫無用處(但發(fā)明者相信他們的App將會“改變世界”)。
今天,我們決定做一個“不是圣誕老人”檢測器,它可以檢測出圣誕老人是否在一個圖像/視頻框中。
為那些不熟悉圣誕老人的人簡單說明一下,圣誕老人是一個詼諧、肥胖、白胡子、虛構(gòu)的西方文化人物,會在圣誕前夜給小孩子送禮物。
不過,我們這個App并不完全是為了好玩和諷刺。我們將學(xué)習(xí)一些實(shí)用的技能,包括:
為深度學(xué)習(xí)配置樹莓派
在樹莓派上安裝Keras和TensorFlow
部署一個預(yù)訓(xùn)練的卷積神經(jīng)網(wǎng)絡(luò)到你的樹莓派上
一旦檢測到,就執(zhí)行一個給定的動作
硬件配置
但是在編寫代碼之前,讓我們先來說一下我們需要的硬件。
圖2:“不是圣誕老人”檢測器的設(shè)置包括樹莓派3、揚(yáng)聲器、3D圣誕樹和一個網(wǎng)絡(luò)攝像頭,為了檢測圣誕老人,樹莓派在Python腳本中用Keras實(shí)現(xiàn)LeNet。
遵循這個教程,你需要:
樹莓派3(同時強(qiáng)烈推薦樹莓派3入門套件)
一個樹莓派相機(jī)模塊或一個USB相機(jī)。
適用樹莓派的3D圣誕樹
一組音箱
當(dāng)然,這些不是全部必須的。只要有一個樹莓派+相機(jī)模塊/usb攝像頭,就能全部設(shè)置好(但是必須修改代碼,這樣它就不會試圖訪問GPIO pins或通過音箱播放音樂)。
你的設(shè)置應(yīng)該與上面的圖2相似,把揚(yáng)聲器、3D圣誕樹和網(wǎng)絡(luò)攝像頭連接在一起。我還推薦使用HDMI監(jiān)視器+鍵盤來測試并調(diào)試腳本:
圖3:我的深度學(xué)習(xí)設(shè)置包括樹莓派和組件,以及鍵盤、鼠標(biāo)和一個小的HDMI顯示器。這樣設(shè)置好后,圣誕老人來到我的圣誕樹前放禮物時一定能抓到他。
怎樣在樹莓派上安裝TensorFlow和Keras?
關(guān)于如何使用Kera來訓(xùn)練卷積神經(jīng)網(wǎng)絡(luò),以確定圣誕老人是否處于輸入的圖像中,可以參考[1]:
我們將采用預(yù)訓(xùn)練的模型,并將其部署到樹莓派上。正如我之前提到的,樹莓派不適合訓(xùn)練神經(jīng)網(wǎng)絡(luò)。但是,樹莓派可以部署訓(xùn)練好的神經(jīng)網(wǎng)絡(luò)(當(dāng)然,模型需要能夠適應(yīng)很小的內(nèi)存占用空間)。
我假設(shè)你已經(jīng)在樹莓派上安裝了OpenCV。如果還沒有,可以看[2]的教程。
建議增加樹莓派的交換空間,這能使你能夠使用Raspberry Pi SD卡來增加內(nèi)存(當(dāng)嘗試在內(nèi)存限制的樹莓派上編譯和安裝大型庫時,這是一個關(guān)鍵步驟)。
要增加交換空間,打開 /etc/dphys-swapfile然后編輯CONF_SWAPSIZE變量:
1 2 3 4 | # set size to absolute value, leaving empty (default) then uses computed value # you most likely don't want this, unless you have a special disk situation # CONF_SWAPSIZE=100 CONF_SWAPSIZE=1024 |
我將交換空間從100MB增加到了1024MB。然后,重新啟動交換服務(wù)器:
1 2 | $ sudo /etc/init.d/dphys-swapfile stop $ sudo /etc/init.d/dphys-swapfile start |
注意:增加交換空間容易燒毀存儲卡,因此請確保恢復(fù)這個更改并在完成后重啟交換服務(wù)器。
然后,我們開始配置開發(fā)環(huán)境。
首先,使用Python 2.7創(chuàng)建一個名為not_santa的Python虛擬環(huán)境:
1 | $ mkvirtualenv not_santa -p python2 |
請注意,-p開關(guān)指向python2,指示Python 2.7將用于虛擬環(huán)境。
還要確保你已經(jīng)把cv2.so綁定到not_santa虛擬環(huán)境中:
1 2 | $ cd ~/.virtualenvs/not_santa/lib/python2.7/site-packages $ ln -s /usr/local/lib/python2.7/site-packages/cv2.so cv2.so |
同樣,要再次確認(rèn)已經(jīng)用Python 2.7綁定編譯了OpenCV,還要仔細(xì)檢查cv2.so文件的路徑,以防安裝路徑與我的演示有不同。
如果你編譯了Python 3 + OpenCV綁定,創(chuàng)建了sym-link,然后試圖將cv2導(dǎo)入你的Python shell,你會得到一個令人困惑的路徑回溯,說導(dǎo)入失敗。
重要說明:對于接下來的幾個pip命令,要確保你處于not_santa環(huán)境,否則你會把這些包安裝到樹莓派的系統(tǒng)Python中。
要進(jìn)入環(huán)境,只需在bash提示符下使用workon命令:
1 | $ workon not_santa |
然后,你會在bash提示符開頭看到“(not_santa)”。
確保使用以下命令在not_santa環(huán)境中安裝NumPy:
1 | $ pip install numpy |
由于我們將訪問該項目的GPIO pins,因此需要同時安裝RPi.GPIO和gpiozero:
1 | $ sudo pip install RPi.GPIO gpiozero |
現(xiàn)在在樹莓派上安裝TensorFlow。問題是沒有一個官方的(Google發(fā)布的)TensorFlow發(fā)行版,那就要在樹莓派上從頭開始編寫TensorFlow,參考[3]。
或者我們可以使用預(yù)先編譯的二進(jìn)制文件Sam Abrahams(GitHub上有[4])。
問題是只有兩種類型的預(yù)編譯的TensorFlow二進(jìn)制文件,一個用于Python 2.7,另一個用于Python 3.4。
Raspbian Stretch發(fā)行版附帶了Python 3.5,因此,我們的版本不匹配。為了避免Python 3.4和Python 3.5之間的麻煩,我決定堅持使用Python 2.7安裝。
讓我們繼續(xù),使用以下命令為Python 2.7安裝TensorFlow:
1 2 | $ wget https://github.com/samjabrahams/tensorflow-on-raspberry-pi/releases/download/v1.1.0/tensorflow-1.1.0-cp27-none-linux_armv7l.whl $ pip install tensorflow-1.1.0-cp27-none-linux_armv7l.whl |
TensorFlow編譯和安裝好后(我花了大約一個小時),然后需要安裝HDF5和H5py。這些庫將允許我們從磁盤加載預(yù)訓(xùn)練的模型:
1 2 | $ sudo apt-get install libhdf5-serial-dev $ pip install h5py |
最后,讓我們安裝Keras和這個項目所需的其他條件:
1 2 3 | $ pip install pillow imutils $ pip install scipy --no-cache-dir $ pip install keras |
為了測試你的配置,請打開一個Python shell(在not_santa環(huán)境中)并執(zhí)行以下命令:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | $ workon not_santa $ python >>> import h5py >>> from gpiozero import LEDBoard >>> from gpiozero.tools import random_values >>> import cv2 >>> import imutils >>> import keras Using TesnsorFlow backend. >>> print("OpenCV version: {}".format(cv2.__version__)) '3.3.1' >>> print("Keras version: {}".format(keras.__version__)) '2.0.8' >>> exit() |
如果一切按計劃進(jìn)行,你應(yīng)該看到使用TensorFlow后端導(dǎo)入的Keras。
正如上面的輸出所示,你還應(yīng)該仔細(xì)檢查OpenCV綁定(cv2)是否可以導(dǎo)入。
最后,不要忘記通過以下方式將交換空間從1024MB減到100MB:
打開/etc / dphys-swapfile
重置CONF_SWAPSIZE為100MB。
重新啟動交換服務(wù)器
在樹莓派運(yùn)行Keras + 深度學(xué)習(xí)模型
現(xiàn)在我們準(zhǔn)備使用Keras,TensorFlow和樹莓派來編寫一個Not Santa檢測器。再次,我會假設(shè)你的硬件設(shè)置和我的一樣,如果不一樣,你需要修改下面的代碼。
首先,請打開一個新文件,將其命名為not_santa_detector.py,插入以下代碼:
1 2 3 4 5 6 7 8 9 10 11 12 | # import the necessary packages from keras.preprocessing.image import img_to_array from keras.models import load_model from gpiozero import LEDBoard from gpiozero.tools import random_values from imutils.video import VideoStream from threading import Thread import numpy as np import imutils import time import cv2 import os |
第2-12行處理輸入,特別是:
keras:用于預(yù)處理輸入幀進(jìn)行分類,并從磁盤加載預(yù)訓(xùn)練的模型。
gpiozero:用于訪問3D圣誕樹。
imutils:用于訪問視頻流(無論是樹莓派相機(jī)模塊還是USB)。
threading:用于non-blocking操作,尤其是當(dāng)我們要點(diǎn)亮圣誕樹或播放音樂的同時不阻塞主線程的執(zhí)行。
然后,定義一個函數(shù)來點(diǎn)亮3D圣誕樹:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | def light_tree(tree, sleep=5): # loop over all LEDs in the tree and randomly blink them with # varying intensities for led in tree: led.source_delay = 0.1 led.source = random_values()
# sleep for a bit to let the tree show its Christmas spirit for # santa clause time.sleep(sleep)
# loop voer the LEDs again, this time turning them off for led in tree: led.source = None led.value = 0 |
light_tree函數(shù)接受一個tree參數(shù)(被設(shè)為一個LEDBoard對象)。
首先,我們循環(huán)tree中的所有LED,并隨機(jī)點(diǎn)亮每個LED,以產(chǎn)生“閃爍”效果(17-19行)。
我們讓燈亮一段時間(第23行),然后再次循環(huán)LED,然后把它關(guān)掉(26-28行)。
下面是一個打開3D圣誕樹燈的例子:
圖6:Raspberry Pi的3D圣誕樹
當(dāng)檢測到圣誕老人時,下一步是播放音樂
1 2 3 4 5 | def play_christmas_music(p): # construct the command to play the music, then execute the # command command = "aplay -q {}".format(p) os.system(command) |
在play_christmas_music函數(shù)中,對aplay命令進(jìn)行系統(tǒng)調(diào)用,從而能夠像從命令行那樣播放音樂文件。
然后,讓我們硬編碼將使用的配置:
1 2 3 4 5 6 7 8 9 10 11 12 | # define the paths to the Not Santa Keras deep learning model and # audio file MODEL_PATH = "santa_not_santa.model" AUDIO_PATH = "jolly_laugh.wav"
# initialize the total number of frames that *consecutively* contain # santa along with threshold required to trigger the santa alarm TOTAL_CONSEC = 0 TOTAL_THRESH = 20
# initialize is the santa alarm has been triggered SANTA = False |
第38行和第39行將硬編碼到預(yù)訓(xùn)練的Keras模型和音頻文件的路徑。文末的下載可以獲取音頻文件。
初始化用于檢測的參數(shù),包括TOTAL_CONSEC和TOTAL_THRESH。這兩個值表示包含圣誕老人的幀的數(shù)量以及我們將分別播放音樂和打開樹的閾值(第43行和第44行)。
最后的初始化是SANTA = False,一個boolean(第47行)。我們稍后將在腳本中使用SANTA變量作為狀態(tài)標(biāo)志。
接下來,加載預(yù)訓(xùn)練的Keras模型并初始化圣誕樹:
1 2 3 4 5 6 | # load the model print("[INFO] loading model...") model = load_model(MODEL_PATH)
# initialize the christmas tree tree = LEDBoard(*range(2, 28), pwm=True) |
Keras允許我們將模型保存到磁盤以供將來使用。Not Santa模型已經(jīng)保存到了磁盤上[1],那么我們把它加載到樹莓派上。第51行使用Keras load_model函數(shù)加載了模型。
第54行實(shí)例化tree對象。如圖所示,tree是gpiozero包中的一個LEDBoard對象。
然后初始化視頻流:
1 2 3 4 5 | # initialize the video stream and allow the camera sensor to warm up print("[INFO] starting video stream...") vs = VideoStream(src=0).start() # vs = VideoStream(usePiCamera=True).start() time.sleep(2.0) |
要訪問攝像機(jī),在imutils包中使用VideoStream
重要提示:如果你想在本項目中使用PiCamera模塊(而不是USB攝像頭),只需注釋第58行并取消第59行的注釋即可。
Sleep 兩秒鐘,以便相機(jī)預(yù)熱(第60行),然后開始循環(huán)播放幀:
1 2 3 4 5 6 | # loop over the frames from the video stream while True: # grab the frame from the threaded video stream and resize it # to have a maximum width of 400 pixels frame = vs.read() frame = imutils.resize(frame, width=400) |
第63行,我們開始循環(huán)播放視頻幀,直到滿足停止條件(稍后在腳本中顯示)。
首先,通過調(diào)用vs.read來獲取一個frame(第66行)。
然后調(diào)整frame為width= 400,保持縱橫比(第67行)。在喂入神經(jīng)網(wǎng)絡(luò)模型之前預(yù)處理這個frame。稍后,我們將顯示框架以及文本標(biāo)簽。
然后預(yù)處理圖像,并通過Keras +深度學(xué)習(xí)模型進(jìn)行預(yù)測:
1 2 3 4 5 6 7 8 9 10 11 | # prepare the image to be classified by our deep learning network image = cv2.resize(frame, (28, 28)) image = image.astype("float") / 255.0 image = img_to_array(image) image = np.expand_dims(image, axis=0)
# classify the input image and initialize the label and # probability of the prediction (notSanta, santa) = model.predict(image)[0] label = "Not Santa" proba = notSanta |
第70-73行預(yù)處理圖像并準(zhǔn)備分類。然后,我們查詢model.predict與image作為參數(shù)。這向神經(jīng)網(wǎng)絡(luò)發(fā)送image,返回包含類概率的tuple(第77行)。
我們將label初始化為“Not Santa”,并將概率proba初始化為第78和79行中notSanta的值。
我們來看看圣誕老人是否在圖像中:
1 2 3 4 5 6 7 8 9 10 | # check to see if santa was detected using our convolutional # neural network if santa > notSanta: # update the label and prediction probability label = "Santa" proba = santa
# increment the total number of consecutive frames that # contain santa TOTAL_CONSEC += 1 |
在83行檢查圣誕老人的概率是否大于notSanta。如果是,就繼續(xù)更新label和proba,然后遞增TOTAL_CONSEC(85-90行)。
如果連續(xù)提供了足夠的“Santa”幀,就需要觸發(fā)圣誕老人警報:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | # check to see if we should raise the santa alarm if not SANTA and TOTAL_CONSEC >= TOTAL_THRESH: # indicate that santa has been found SANTA = True
# light up the christmas tree treeThread = Thread(target=light_tree, args=(tree,)) treeThread.daemon = True treeThread.start()
# play some christmas tunes musicThread = Thread(target=play_christmas_music, args=(AUDIO_PATH,)) musicThread.daemon = False musicThread.start() |
如果SANTA為False,并且TOTAL_CONSEC達(dá)到TOTAL_THRESH閾值,就有兩個操作要執(zhí)行:
創(chuàng)建并啟動一個treeThread來閃爍圣誕樹燈(98-100行)。
創(chuàng)建并啟動一個musicThread在后臺播放音樂(103-106行)。
這些線程將獨(dú)立運(yùn)行,不停止腳本的正向執(zhí)行(即非阻塞操作)。
在第95行,我們將我們的SANTA狀態(tài)標(biāo)志設(shè)置為True,意味著我們在輸入框架中找到了圣誕老人。 在循環(huán)的下一個loop中,我們將像第93行那樣查看這個值。
否則(SANTA為True或TOTAL_THRESH未滿足),我們將TOTAL_CONSEC重置為零,并將SANTA重置為False:
1 2 3 4 5 | # otherwise, reset the total number of consecutive frames and the # santa alarm else: TOTAL_CONSEC = 0 SANTA = False |
最后,我們使用生成的文本標(biāo)簽將框架顯示在屏幕上:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | # build the label and draw it on the frame label = "{}: {:.2f}%".format(label, proba * 100) frame = cv2.putText(frame, label, (10, 25), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
# show the output frame cv2.imshow("Frame", frame) key = cv2.waitKey(1) & 0xFF
# if the `q` key was pressed, break from the loop if key == ord("q"): break
# do a bit of cleanup print("[INFO] cleaning up...") cv2.destroyAllWindows() vs.stop() |
概率的值被附加到包含“圣誕老人”或“不是圣誕老人”的label(第115行)。
然后使用OpenCV的cv2.putText,可以在框架頂部顯示標(biāo)簽(以圣誕節(jié)為主題的綠色),然后將框架顯示在屏幕上(116-120行)。
無限while loop 的退出條件是在鍵盤上按下“q”鍵(121-125行)。如果循環(huán)的退出條件滿足,則在腳本退出之前,break并執(zhí)行第129行和第130行的一些清理。
完成!
回頭看看這130行代碼,這個框架/模板也可以很容易地用于樹莓派上的其他深度學(xué)習(xí)項目。
現(xiàn)在,讓我們來抓那個胖胖的,有胡子的,快活的圣誕老人吧!
深度學(xué)習(xí)+ Keras +樹莓派結(jié)果
圖7:我,Adrian Rosebrock,扮成圣誕老人。我將親自測試使用深度學(xué)習(xí),Keras,Python和OpenCV構(gòu)建的“不是圣誕老人”檢測器。
然后,我把相機(jī)朝著客廳里的圣誕樹上的樹莓派:
圖8:圣誕樹將作為測試已經(jīng)部署到樹莓派上的Not Santa深度學(xué)習(xí)模型的背景。
如果圣誕老人來為給我的好孩子們送禮物,我想確保通過閃爍3D圣誕樹燈和播放圣誕歌曲來歡迎他。
然后,我使用以下命令啟動了Not Santa深度學(xué)習(xí)+ Keras檢測器:
1 | $ python not_santa_detector.py |
Not Santa 檢測器啟動并運(yùn)行后,我就開始行動:
親愛的圣誕老人:如果你讀到了這里,要知道我會用樹莓派找到你哦!
參考:
[1]https://www.pyimagesearch.com/2017/12/11/image-classification-with-keras-and-deep-learning
[2]https://www.pyimagesearch.com/2017/10/09/optimizing-opencv-on-the-raspberry-pi
[3]https://github.com/samjabrahams/tensorflow-on-raspberry-pi/blob/master/GUIDE.md
[4]https://github.com/samjabrahams/tensorflow-on-raspberry-pi

南京合越智能,增強(qiáng)智造,增強(qiáng)感知,增強(qiáng)交互!
業(yè)務(wù)合作
(我們會第一時間與您聯(lián)系)網(wǎng)站導(dǎo)航
聯(lián)系方式
- 微信:13815863530(手機(jī)同號)
- QQ:38260484
- 3XMaker@163.com