工程筆記本 / NVIDIA

NVIDIA

NVIDIA Jetson Nano機器學習應用-你戴口罩了嗎?結合Line通訊平台進行即時監控

鄭 建彥📅 2021-05-20👁 174
*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結
作者/攝影 張嘉鈞
難度

★★☆☆☆(普通)

材料表 RK-NVIDIA® Jetson Nano™ Developer Kit B01 套件

關於IFTTT

IFTTT 的全名為「If This Then That」,及是觸發了A事件之後就會做出B動作,基本上不用寫程式,也可以有幾百個服務可以進行串接,目前有三個免費API的額度,如果使用三個以上的API就要開始收費了。

釐清思緒

在開始之前先來確認一下本次目標,我們希望當辨識到特定物品的時候使用LINE進行即時通知。以IFTTT的角度來說就是「if 辨識到東西 then 傳送訊息到Line」,但是IFTTT沒辦法進行AI辨識,必須透過工具:Webhook, Webhook的功能是當特定網頁有被觸及的時候就會提醒對方,我可以在辨識到特定物品的時候觸及特定網頁並且上傳數值,這時候Webhook會收到回饋,啟動Line的傳送訊息功能,而Line的傳送訊息功能也可以接收剛剛上傳的數值。

申請IFTTT & 創建Applet

1.進入IFTTT首頁,選擇登入帳號或申請新帳號 2.請選擇一種帳號進行登入 3.右上角選擇選擇Create新服務 4.點選Add,進入服務設定。 5.搜尋 Webhooks 服務並點選該圖示 6.點擊 Receive a web request 7.創建事件名稱並點擊Create trigger 啟動輸入觸發。 8.接著點擊Then That 的 Add。 9.搜尋Line並且點擊LINE的icon 10.點擊Send Message 11.因為要連接到 LINE,需要進行登入LINE 的動作。 12.IFTTT透過 LINE Notify 的通知進行推播,選擇同意並連動 連動後會在LINE上彈出這段訊息 13.設定傳送 LINE 訊息的內容 可以選擇要推播到特定群組,或是一對一的 LINE Notify,再來是訊息格式,1個 Webhooks 可以傳送3個數值,後續會教大家怎麼修改。 14.點擊 Continue 15.輸入app的標題簡述,接著可以按Finish 16.完成之後的畫面如下,接著要點擊Webhook的圖標 17.點擊左上角的IFTTT圖案回到首頁,並且點擊Create by me就可以看到剛剛創建的APP 18.點擊右上角的 Documentation 19.進到文件狀態後修改內容進行測試,event欄位為剛剛Webhook創建的名稱 ( jetsonnano_line ),value隨意輸入。 執行結果可以到 Line Notify中查看

編輯Line的訊息格式

20.回到APP的頁面,點擊LINE的圖標 21.點擊 jetsonnano_line 的app方框 22.點擊右上角的setting 23.選擇Send Message右上角的edit 24.修改訊息資訊,變數可以從 Add ingredient選取,有EventName、三個Value以及 OccurredAt ( 最近的時間 ) 可以選擇。 25.回到Webhook的Documentation測試一下結果 到目前就已經完成基本的IFTTT設定了。

使用Python程式連動Line

解析Webhook

開始之前我們先解析一下剛剛在Webhook的Documentation。

Make a POST or GET web request to:

代表我們可以使用POST或GET的方式去觸及Webhook,其中GET通常是下載網頁資訊而POST則是上傳資料,但是在這邊是都可以通用的。

With an optional JSON body of:

他可以使用自定義的參數但是需要使用JSON格式的內容,強制使用類似Python的字典形式,Key的位置是固定的所以寫程式的時候要注意,Key後面的內容則是可以隨機定義的,而這部分就是可以更換成我們辨識的結果。 對這些參數稍微有一點概念了之後就可以開始寫程式囉!

實作Python Code

這邊需要使用到Python的套件 Request,來完成與網頁互動的功能。首先,我們先撰寫了一個副函式叫「send_to_webhook」,並且給予所有能夠修改的參數,像是網址的部分就要包含「事件名稱」、「金鑰」,而後面的引數總共有三個「數值」;利用post或get都可以只要能觸發Webhook的事件即可,我們可以使用”status_code”做個判斷,如果成功的話會回傳response 200,也可以直接使用“codes.ok”。 [pastacode lang="python" manual="import%20requests%0A%0Adef%20send_to_webhook(event%3D''%2C%20key%3D''%2C%20val_1%3D''%2C%20val_2%3D''%2C%20val_3%3D'')%3A%20%20%20%0A%20%20%20%20%0A%20%20%20%20trg_url%20%3D%20('https%3A%2F%2Fmaker.ifttt.com%2Ftrigger%2F%7Bevent%7D%2Fwith%2Fkey%2F%7Bkey%7D'.format(event%3Devent%2C%20key%3Dkey))%0A%20%20%20%20%0A%20%20%20%20trg_params%20%3D%20%7B%0A%20%20%20%20%20%20%20%20'value1'%3A%20f'%7Bval_1%7D'%2C%0A%20%20%20%20%20%20%20%20'value2'%3A%20f'%7Bval_2%7D'%2C%0A%20%20%20%20%20%20%20%20'value3'%20%3A%20f'%7Bval_3%7D'%0A%20%20%20%20%20%20%20%20%7D%0A%0A%20%20%20%20req%20%3D%20requests.post(trg_url%2C%20trg_params)%0A%0A%20%20%20%20if%20req.status_code%20%3D%3D%20requests.codes.ok%3A%0A%20%20%20%20%20%20%20%20print('%E5%82%B3%E9%80%81%E6%88%90%E5%8A%9F')%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20print('%E5%82%B3%E9%80%81%E5%A4%B1%E6%95%97')" message="" highlight="" provider="manual"/] 接著就可以在外部修改參數了: [pastacode lang="python" manual="if%20__name__%20%3D%3D%20'__main__'%3A%0A%0A%20%20%20%20event%20%3D%20'jetsonnano_line'%0A%20%20%20%20key%20%3D%20'i3_S_gIAsOty30yvIg4vg'%0A%0A%20%20%20%20val_1%20%3D%20'%E4%BD%BF%E7%94%A8'%0A%20%20%20%20val_2%20%3D%20'Python'%0A%20%20%20%20val_3%20%3D%20'%E9%80%A3%E5%8B%95'%0A%0A%20%20%20%20ret%20%3D%20send_to_webhook(event%2C%20key%2C%20val_1%2C%20val_2%2C%20val_3)" message="" highlight="" provider="manual"/]

結合簡易的AI辨識

這部分可以結合各種形式,像是YOLOv4、Jetson Inference等API,再稍微修改一下即可,這邊我提供一個更簡單且我們常用的方法 Teachable Machine,這邊就不介紹太多了,他是一個線上的AI體驗工具。 除了線上訓練之外還可以提供Tensorflow、Tensorflow Lite以及Coral的模型,這邊我順便教大家怎麼去安裝 Tensorflow以及Tensorflow Lite。

使用Teachable Machine訓練

匯出Tensorflow模型

我們直接使用Keras模型即可,選擇Tensorflow並選擇Model conversion type為Keras,點選Download my model即可進行轉換與下載:

在JetsonNano中運行即時影像辨識

首先需要安裝Tensorflow,我們可以直接到這裡照個原廠推薦的方法操作,由於我的Nano 是JetPack 4.4.1,所以要找到 Python3.6 + JetsonPack 4.4的位置: 快速參考指令如下: [pastacode lang="python" manual="%24%20sudo%20apt-get%20install%20libhdf5-serial-dev%20hdf5-tools%20libhdf5-dev%20zlib1g-dev%20zip%20libjpeg8-dev%20liblapack-dev%20libblas-dev%20gfortran%0A%24%20sudo%20apt-get%20install%20python3-pip%0A%24%20sudo%20pip3%20install%20-U%20pip%0A%24%20sudo%20pip3%20install%20-U%20pip%20testresources%20setuptools%20numpy%3D%3D1.16.1%20future%3D%3D0.17.1%20mock%3D%3D3.0.5%20h5py%3D%3D2.9.0%20keras_preprocessing%3D%3D1.0.5%20keras_applications%3D%3D1.0.8%20gast%3D%3D0.2.2%20futures%20protobuf%20pybind11%0A%23%20TF-2.x%0A%0A%24%20sudo%20pip3%20install%20--pre%20--extra-index-url%20https%3A%2F%2Fdeveloper.download.nvidia.com%2Fcompute%2Fredist%2Fjp%2Fv44%20tensorflow%3D%3D2.3.1%2Bnv20.12%0A" message="" highlight="" provider="manual"/] 安裝完之後我們需要使用Teachable Machine匯出的位置下方有提供範例程式,我稍微修改了一下。首先載入相關套件: [pastacode lang="python" manual="import%20tensorflow.keras%0Aimport%20numpy%20as%20np%0Aimport%20cv2%0Aimport%20time%0Aimport%20platform%20as%20plt" message="" highlight="" provider="manual"/] 由於標籤檔是一個文字檔,我寫了一個程式去解析內容並儲存成一個字典: [pastacode lang="python" manual="def%20get_label(label_path)%3A%0A%0A%20%20%20%20label%20%3D%20%7B%7D%0A%20%20%20%20with%20open(label_path)%20as%20f%3A%0A%20%20%20%20%20%20%20%20for%20line%20in%20f.readlines()%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20idx%2Cname%20%3D%20line.strip().split('%20')%0A%20%20%20%20%20%20%20%20%20%20%20%20label%5Bint(idx)%5D%20%3D%20name%0A%20%20%20%20return%20label" message="" highlight="" provider="manual"/] 接著進入主程式,設定np顯示的格式、載入神經網路模型與標籤;data是設定輸入資料形狀 (1, 224, 224, 3);最後fps用來計算即時影像每秒會有幾幀,通常fps越高越好,到了60對於人眼就幾乎感受不到延遲了;cap是儲存攝影機設備: [pastacode lang="python" manual="print('Setting%20...')%0Anp.set_printoptions(suppress%3DTrue)%0A%0Aprint('Load%20Model%20%26%20Labels%20...')%0Amodel%20%3D%20tensorflow.keras.models.load_model('keras_models%2Fmodel.h5')%0Alabel%20%3D%20get_label('keras_models%2Flabels.txt')%0Adata%20%3D%20np.ndarray(shape%3D(1%2C%20224%2C%20224%2C%203)%2C%20dtype%3Dnp.float32)%0A%0Aprint('Start%20Stream%20...')%0Afps%20%3D%20-1%0Acap%20%3D%20cv2.VideoCapture(0)" message="" highlight="" provider="manual"/] 使用While不斷讀取最近一次的影像;t_start用於計算fps;使用cap.read()會獲取兩個參數,第一個通常被用來代表是否擷取成功 ( 布林值 ),第二個則是影像陣列;接著將圖片丟入模型前還需要進行前處理,縮放大小至224x224,正規化,以及修改成輸入資料的格式: [pastacode lang="python" manual="while(True)%3A%0A%0A%20%20%20%20t_start%20%3D%20time.time()%0A%0A%20%20%20%20ret%2C%20frame%20%3D%20cap.read()%0A%0A%20%20%20%20size%20%3D%20(224%2C%20224)%0A%20%20%20%20frame_resize%20%3D%20cv2.resize(frame%2C%20size)%0A%20%20%20%20%0A%20%20%20%20frame_norm%20%3D%20(frame_resize.astype(np.float32)%20%2F%20127.0)%20-%201%0A%0A%20%20%20%20data%5B0%5D%20%3D%20frame_norm%0A" message="" highlight="" provider="manual"/] 接著使用predict即可完成推論,我們先取得到數值最大的欄位idx,並設定預計要顯示在畫面上的資訊 (result) 再使用 putText將資訊繪製到影像上,最後顯示出來 (imshow),標題可以自己修改;當按下q的時候可以離開,最後釋放攝影機物件並刪除所有視窗: [pastacode lang="python" manual="%E3%80%80%E3%80%80prediction%20%3D%20model.predict(data)%5B0%5D%20%20%20%20%0A%E3%80%80%E3%80%80%0A%E3%80%80%E3%80%80idx%20%3D%20int(np.argmax(prediction))%0A%0A%20%20%20%20result%20%3D%20'%7B%7D%20%3A%20%7B%3A.3f%7D%2C%20FPS%20%7B%7D'.format(label%5Bidx%5D%2C%20prediction%5Bidx%5D%2C%20fps)%0A%0A%20%20%20%20cv2.putText(frame%2C%20result%2C%20(10%2C40)%2C%20cv2.FONT_HERSHEY_SIMPLEX%2C%201%2C%20(0%20%2C%200%2C%20255)%2C%201)%0A%0A%20%20%20%20cv2.imshow(win_title%2C%20frame)%0A%0A%20%20%20%20if%20cv2.waitKey(1)%20%3D%3D%20ord('q')%3A%0A%20%20%20%20%20%20%20%20break%0A%0A%20%20%20%20fps%20%3D%20int(1%2F(time.time()%20-%20t_start))%0A%0Acap.release()%0Acv2.destroyAllWindows()%0A%0Aprint('Quit%20...')" message="" highlight="" provider="manual"/] 執行結果如下: 可以看到FPS只有4,不過準確度還蠻高的!但是TensorFlow在JetsonNano上開啟需要一段時間,所以我會推薦轉換成TensorRT的形式,下篇會再介紹。

將辨識結果傳送給Line

剛剛程式當中已經取得了結果 ( results ),我們只需要將這個結果上傳到Line即可,稍早我們寫的ifttt程式將其儲存為ifttt.py方便導入,首先設定事件名稱與金鑰,status用來手動設定辨識結果對應的傳送內容;pre_idx則是用來儲存前一個辨識的結果: [pastacode lang="python" manual="import%20ifttt%0A%0Adef%20main(win_title%3D'test')%3A%0A%0A%20%20%20%20%0A%23%20%E8%A8%AD%E5%AE%9A%E3%80%8CLine%E8%A8%8A%E6%81%AF%E3%80%8D%E8%B3%87%E8%A8%8A%0A%0A%20%20%20%20event%20%3D%20'jetsonnano_line'%0A%20%20%20%20key%20%3D%20'i3_S_gIAsOty30yvIg4vg'%0A%20%20%20%20status%20%3D%20%7B%20%200%3A%5B'%E6%98%AF%E6%9C%AC%E4%BA%BA'%2C%20'%E7%A2%BA%E5%AE%9A%E6%9C%89%E5%81%9A%E5%A5%BD%E9%98%B2%E7%96%AB%E5%B7%A5%E4%BD%9C'%5D%2C%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%201%3A%5B'%E6%98%AF%E6%9C%AC%E4%BA%BA'%2C%20'%E6%B3%A8%E6%84%8F%EF%BC%8C%E5%B7%B2%E6%88%90%E7%82%BA%E9%98%B2%E7%96%AB%E7%A0%B4%E5%8F%A3'%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%202%3A%5B'%E9%9B%A2%E9%96%8B%E4%BD%8D%E7%BD%AE'%2C%20''%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%203%3A%5B'%E9%9D%9E%E6%9C%AC%E4%BA%BA'%2C%20'%E6%B3%A8%E6%84%8F%E6%82%A8%E7%9A%84%E8%B2%A1%E7%94%A2'%5D%20%20%20%20%7D%0A%20%20%20%20pre_idx%20%3D%20-1" message="" highlight="" provider="manual"/] 接著將程式碼放到prediction的後面,send_to_webhook詳細說明請往上翻找: [pastacode lang="python" manual="%23%20%E5%88%A4%E6%96%B7%E6%98%AF%E5%90%A6%E8%B7%9F%E4%B8%8A%E6%AC%A1%E8%BE%A8%E8%AD%98%E4%B8%80%E6%A8%A3%E7%9A%84%E7%B5%90%E6%9E%9C%EF%BC%8C%E5%A6%82%E6%9E%9C%E4%B8%8D%E5%90%8C%E5%89%87%E9%80%B2%E8%A1%8C%E4%B8%8A%E5%82%B3%0A%0Aif%20pre_idx%20!%3D%20idx%3A%0A%0A%20%20%20%20ifttt.send_to_webhook(%20%20event%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20key%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20'%E7%92%B0%E5%A2%83%E8%AE%8A%E5%8B%95'%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20status%5Bidx%5D%5B0%5D%2C%20%0A%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20%20status%5Bidx%5D%5B1%5D%20if%20status%5Bidx%5D%5B1%5D%20else%20'')%0A%20%20%20%20%0A%20%20%20%20pre_idx%20%3D%20idx" message="" highlight="" provider="manual"/]

執行結果

可以注意到如果沒有傳送資料的時候,FPS都還可以落在4左右,一旦傳送資料就會整co https://youtu.be/GxbscxqupbQ

結論

我們已經學會怎麼將JetsonNano與Line結合的方式了,下一篇我們將帶大家嘗試去將整個影像體驗的效果提升。   *本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結(本篇文章完整範例程式請至原文下載)

相關文章 📎

留言 💬 (0)

還沒有留言,來當第一個。