--- tags: MaixPy, 測試報告, K210, MaixDuinom robots: K210, MaixDuinom, MaixPy, 影像辨識, 人臉辨識, 人臉偵測 lang: zh-tw --- # MaixPy+MaixDuino 範例測試 ## 前置作業 1. 安裝韌體燒錄軟體 [KFlash]() 1. 安裝 [MaixPy 韌體](https://dl.sipeed.com/MAIX/MaixPy/release/master/) 3. 首先需要下載 [MaixPy 範例檔](https://github.com/sipeed/MaixPy_scripts)。 :::info MaixPy 是從 OpenMV 改過來的, 所以有許多基本功能在 [MainxPy 的文件](https://maixpy.sipeed.com/zh/)是沒有詳細說明的, 要找 [OpenMV 的文件](http://docs.openmv.io/)。 ::: ## 人臉偵測 - 原始文章為 [MaixPy run face detection (tiny yolo v2)](https://blog.sipeed.com/p/675.html)。 - 精簡版 MaixPy 韌體及訓練後 model [maixpy_yolo2](https://en.bbs.sipeed.com/uploads/default/original/1X/b29f5206df383ebad3b2e5c62f2870862a106994.zip) 下載: ``` PS D:\temp\maixpy_yolo2> dir Directory: D:\temp\maixpy_yolo2 Mode LastWriteTime Length Name ---- ------------- ------ ---- -a--- 2019/3/23 下午 07:39 336534 face_3M.kfpkg -a--- 2019/3/24 上午 01:13 1116352 maixpy_yolo2.bin ``` 1. 燒錄韌體檔, MaixPy 的範例常常會因為要載入的 Model 檔比較大, 所以搭配精簡版的 MainPy 韌體, 不過這裡我燒錄跟著 model 一起的韌體會有問題, 所以直接燒錄完整版的 MaixPy 韌體, 裡面已經在指定位址放有人臉偵測所需要的 model 檔了: ![](https://i.imgur.com/Ybe72QL.png) 1. 燒錄 model 檔: ![](https://i.imgur.com/85yOU52.png) :::info .kfpkg 檔不需要指定位址, 直接燒錄即可。 ::: 1. 開啟 machine_vision\demo_find_face.py 範例檔: ```python=1 #refer to http://blog.sipeed.com/p/675.html import sensor import image import lcd import KPU as kpu lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.run(1) task = kpu.load(0x300000) # you need put model(face.kfpkg) in flash at address 0x300000 # task = kpu.load("/sd/face.kmodel") anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) a = kpu.init_yolo2(task, 0.5, 0.3, 5, anchor) while(True): img = sensor.snapshot() code = kpu.run_yolo2(task, img) if code: for i in code: print(i) a = img.draw_rectangle(i.rect()) a = lcd.display(img) a = kpu.deinit(task) ``` :::info MaixPy 的範例不知道為什麼很喜歡接收傳回值, 範例中的 a 其實都不會再用到, 但是都會在叫用函式或是方法實用 a 接收傳回值, 如果不喜歡, 也可以改掉。 ::: :::info 如果你覺得燒錄 model 檔, 在程式中以指定位址載入 model 資料很麻煩, 可以把程式中的第 12 行: ```python=11 task = kpu.load(0x300000) # you need put model(face.kfpkg) in flash at address 0x300000 ``` 改掉, 先將 .kmodel 格式的 model 檔放在 MicroSD 卡的根路徑下, 插入控制板, 即可用以下程式載入 model: ```python=11 task = kpu.load("/sd/face.kmodel") ``` ::: 1. 執行後即可偵測人臉: ![](https://i.imgur.com/jR0o2pN.png) ## 物件分類 - 原始文章:[MaixPy Run 20-classes object detection based on tiny-yolov2 in 30 lines~](https://blog.sipeed.com/p/677.html) - 韌體、範例、模型下載 [maixpy_20class.zip](https://en.bbs.sipeed.com/uploads/default/original/1X/fb175ec3815db07fc98a4f250b8ba7e2fef53c3c.zip) 1. 燒錄 model 檔: ![](https://i.imgur.com/l9hoNKw.png) 2. 此範例可沿用韌體, 不用特別去燒錄隨 model 檔下載的精簡版韌體, 開啟範例後有地方要修改一下: ```python=24 if code: for i in code: a=img.draw_rectangle(i.rect()) a = lcd.display(img) for i in code: lcd.draw_string(i.x(), i.y(), classes[i.classid()], lcd.RED, lcd.WHITE) lcd.draw_string(i.x(), i.y()+12, '%f1.3'%i.value(), lcd.RED, lcd.WHITE) else: a = lcd.display(img) ``` 原來程式第 28 這裡應該是多了迴圈, 把迴圈去掉, 只需要把辨識出來的物件名稱和信心指數秀出來就可以了。另外, 這裡是單獨將上述資訊顯示在 LCD 上, IDE 的即時畫面看不到, 因此也一併修改成先將辨識結果的資訊寫到 img 上, 最後在將 img 顯示在 LCD 上。修正過的程式如下: ```python=1 import sensor,image,lcd,time import KPU as kpu lcd.init(freq=15000000) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_vflip(1) sensor.run(1) clock = time.clock() classes = ['aeroplane', 'bicycle', 'bird', 'boat', 'bottle', 'bus', 'car', 'cat', 'chair', 'cow', 'diningtable', 'dog', 'horse', 'motorbike', 'person', 'pottedplant', 'sheep', 'sofa', 'train', 'tvmonitor'] task = kpu.load(0x500000) anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) kpu.init_yolo2(task, 0.5, 0.3, 5, anchor) while(True): clock.tick() img = sensor.snapshot() code = kpu.run_yolo2(task, img) print(clock.fps()) if code: for i in code: img.draw_rectangle(i.rect()) img.draw_string(i.x(), i.y(), classes[i.classid()], (255,0,0)) img.draw_string(i.x(), i.y()+12, '%f1.3'%i.value(), (255,0,0)) lcd.display(img) kpu.deinit(task) ``` :::warning 如果修改程式碼要重新執行程式, 會出現記憶體不足的錯誤: ![](https://i.imgur.com/oIR3MBk.png) 只能按一下板子上的 `RESET` 鈕, 在 IDE 中重新連線後再執行。 ::: 1. 執行後會再找到的物件標示方框, 並在方框左上角顯示物件名稱與信心指數: ![](https://i.imgur.com/VSDmmQY.png) [展示影片](https://www.youtube.com/watch?v=A1f3IDwHGMU) ## 手寫數字辨識 - 原文 [Run MNIST on MaixPy in 30 lines code](https://blog.sipeed.com/p/668.html) - 模型、範例檔案 [mnist maixpy.zip](https://en.bbs.sipeed.com/uploads/default/original/1X/117fd26dce539def92e28a6cea5a907368ed6df8.zip) 1. 燒錄 model 檔: ![](https://i.imgur.com/wWeIDOF.png) 2. 複製原文出處的程式檔執行: ```python import sensor,lcd,image import KPU as kpu lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_windowing((224, 224)) #set to 224x224 input sensor.set_hmirror(0) #flip camera task = kpu.load(0x200000) #load model from flash address 0x200000 sensor.run(1) while True: img = sensor.snapshot() lcd.display(img,oft=(0,0)) #display large picture img1=img.to_grayscale(1) #convert to gray img2=img1.resize(28,28) #resize to mnist input 28x28 a=img2.invert() #invert picture as mnist need a=img2.strech_char(1) #preprocessing pictures, eliminate dark corner lcd.display(img2,oft=(224,32)) #display small 28x28 picture a=img2.pix_to_ai(); #generate data for ai fmap=kpu.forward(task,img2) #run neural network model plist=fmap[:] #get result (10 digit's probability) pmax=max(plist) #get max probability max_index=plist.index(pmax) #get the digit lcd.draw_string(224,0,"%d: %.3f"%(max_index,pmax),lcd.WHITE,lcd.BLACK) #show result a = img.draw_rectangle(5,0,70,12,(0,0,0), fill=True) a = img.draw_string(10,0,"%d: %.3f"%(max_index,pmax),(255,255,255)) #show result #a = lcd.display(img) #display large picture ``` 執行結果: ![](https://i.imgur.com/l3fGmQn.png) ![](https://i.imgur.com/Yih2FnB.png) ![](https://i.imgur.com/nPDqaZk.png) ![](https://i.imgur.com/Qn3jOyE.png) ![](https://i.imgur.com/bp1zxgj.png) ![](https://i.imgur.com/B9Z7ilO.png) 辨識失敗的結果: ![](https://i.imgur.com/cgcuUFL.png) ![](https://i.imgur.com/1EYiaCN.png) [展示影片](https://www.youtube.com/watch?v=jX0bXy5m5jY) ## 人臉即時辨識 - 原文在[MaixPy實現人臉識別](https://blog.sipeed.com/p/1338.html#more-1338) - 下載 [key_gen](https://en.bbs.sipeed.com/uploads/default/original/1X/bca0832bed92a1ada63bd05327688784e2ef14d1.zip) 韌體 1. 燒錄 key_gen 韌體後重新開機, 即可在序列埠終端機視窗中看到序號: ![](https://i.imgur.com/mjmBbyB.png) 2. 到 [Maix AIOT 平台](https://www.maixhub.com/)註冊帳號後, 進入善心人士貢獻的[人臉辨識模式頁面](https://www.maixhub.com/index.php/index/index/detail/id/235.html)捲到最底下按下載鈕: ![](https://i.imgur.com/4t5rpi6.png) 在頁面中輸入剛剛看到的序號: ![](https://i.imgur.com/XqMJD69.png) 按下提交後必須等待一段時間 (約 30 秒) 才會開始下載。 1. 燒錄剛剛下載取得的 .kfpkg 檔: ![](https://i.imgur.com/qpPQhUQ.png) 1. 開啟 MaixPy 範例檔中 machine_vision\demo_face_recognition.py 檔案, 不過這份程式有誤, 程式中只有 10 個人名代號, 但是在按下板子上的 `BOOT` 鈕記錄人臉時, 並不會檢查是否已經超過 10 個人臉, 所以會導致第 11 張臉時程式掛掉。另外, 也沒有處理按鈕的 debounce: ```python=16 def check_key(): global last_key_state global key_pressed val=key_gpio.value() if last_key_state == 1 and val == 0: key_pressed=1 else: key_pressed=0 last_key_state = val ``` ```python=93 if key_pressed == 1: key_pressed = 0 record_ftr = feature record_ftrs.append(record_ftr) break ``` 因此, 我把程式改掉了: ```python=1 # Download model from: https://www.maixhub.com/index.php/index/index/detail/id/235 import sensor,image,lcd import KPU as kpu import time from Maix import FPIOA,GPIO task_fd = kpu.load(0x200000) task_ld = kpu.load(0x300000) task_fe = kpu.load(0x400000) clock = time.clock() key_pin=16 fpioa = FPIOA() fpioa.set_function(key_pin,FPIOA.GPIO7) key_gpio=GPIO(GPIO.GPIO7,GPIO.IN) last_key_state=1 key_pressed=0 def check_key(): global last_key_state global key_pressed val=key_gpio.value() print(val) key_pressed=0 if last_key_state == 1 and val == 0: time.sleep(0.02) val=key_gpio.value() if val == 0: key_pressed=1 last_key_state = val lcd.init() sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_hmirror(1) sensor.set_vflip(1) sensor.run(1) anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) #anchor for face detect dst_point = [(44,59),(84,59),(64,82),(47,105),(81,105)] #standard face key point position a = kpu.init_yolo2(task_fd, 0.5, 0.3, 5, anchor) img_lcd=image.Image() img_face=image.Image(size=(128,128)) a=img_face.pix_to_ai() record_ftr=[] record_ftrs=[] names = ['Mr.1', 'Mr.2', 'Mr.3', 'Mr.4', 'Mr.5', 'Mr.6', 'Mr.7', 'Mr.8', 'Mr.9' , 'Mr.10'] while(1): check_key() img = sensor.snapshot() clock.tick() code = kpu.run_yolo2(task_fd, img) if code: for i in code: # Cut face and resize to 128x128 a = img.draw_rectangle(i.rect()) face_cut=img.cut(i.x(),i.y(),i.w(),i.h()) face_cut_128=face_cut.resize(128,128) a=face_cut_128.pix_to_ai() #a = img.draw_image(face_cut_128, (0,0)) # Landmark for face 5 points fmap = kpu.forward(task_ld, face_cut_128) plist=fmap[:] le=(i.x()+int(plist[0]*i.w() - 10), i.y()+int(plist[1]*i.h())) re=(i.x()+int(plist[2]*i.w()), i.y()+int(plist[3]*i.h())) nose=(i.x()+int(plist[4]*i.w()), i.y()+int(plist[5]*i.h())) lm=(i.x()+int(plist[6]*i.w()), i.y()+int(plist[7]*i.h())) rm=(i.x()+int(plist[8]*i.w()), i.y()+int(plist[9]*i.h())) a = img.draw_circle(le[0], le[1], 4) a = img.draw_circle(re[0], re[1], 4) a = img.draw_circle(nose[0], nose[1], 4) a = img.draw_circle(lm[0], lm[1], 4) a = img.draw_circle(rm[0], rm[1], 4) # align face to standard position src_point = [le, re, nose, lm, rm] T=image.get_affine_transform(src_point, dst_point) a=image.warp_affine_ai(img, img_face, T) a=img_face.ai_to_pix() #a = img.draw_image(img_face, (128,0)) del(face_cut_128) # calculate face feature vector fmap = kpu.forward(task_fe, img_face) feature=kpu.face_encode(fmap[:]) reg_flag = False scores = [] for j in range(len(record_ftrs)): score = kpu.face_compare(record_ftrs[j], feature) scores.append(score) max_score = 0 index = 0 for k in range(len(scores)): if max_score < scores[k]: max_score = scores[k] index = k if max_score > 85: a = img.draw_string(i.x(),i.y(), ("%s :%2.1f" % (names[index], max_score)), color=(0,255,0),scale=2) else: a = img.draw_string(i.x(),i.y(), ("X :%2.1f" % (max_score)), color=(255,0,0),scale=2) if key_pressed == 1: key_pressed = 0 if len(record_ftrs) < len(names): print("record feature %d" % len(record_ftrs)) record_ftr = feature record_ftrs.append(record_ftr) break fps =clock.fps() #print("%2.1f fps"%fps) a = lcd.display(img) #kpu.memtest() #a = kpu.deinit(task_fe) #a = kpu.deinit(task_ld) #a = kpu.deinit(task_fd) ``` 執行後若看到有找到臉的五點特徵, 就可以按 `BOOT` 記錄, 之後就會跟記錄的特徵比對, 來判別是哪一張臉。 [展示影片](https://www.youtube.com/watch?v=-gzSJug8_fM) :::warning 這程式沒有很穩, 跑一跑很容易當掉: :::