NVIDIA Jetson Nano機器學習應用-你戴口罩了嗎?結合Line通訊平台進行即時監控
*本文由RS components 贊助發表,轉載自DesignSpark部落格原文連結
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中查看
21.點擊 jetsonnano_line 的app方框
22.點擊右上角的setting
23.選擇Send Message右上角的edit
24.修改訊息資訊,變數可以從 Add ingredient選取,有EventName、三個Value以及 OccurredAt ( 最近的時間 ) 可以選擇。
25.回到Webhook的Documentation測試一下結果
到目前就已經完成基本的IFTTT設定了。
對這些參數稍微有一點概念了之後就可以開始寫程式囉!
快速參考指令如下:
[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的形式,下篇會再介紹。
| 作者/攝影 | 張嘉鈞 |
| 難度 |
★★☆☆☆(普通) |
| 材料表 |
|
關於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的形式,下篇會再介紹。
留言 💬 (0)
還沒有留言,來當第一個。