---
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 檔了:

1. 燒錄 model 檔:

:::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. 執行後即可偵測人臉:

## 物件分類
- 原始文章:[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 檔:

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
如果修改程式碼要重新執行程式, 會出現記憶體不足的錯誤:

只能按一下板子上的 `RESET` 鈕, 在 IDE 中重新連線後再執行。
:::
1. 執行後會再找到的物件標示方框, 並在方框左上角顯示物件名稱與信心指數:

[展示影片](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 檔:

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://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 韌體後重新開機, 即可在序列埠終端機視窗中看到序號:

2. 到 [Maix AIOT 平台](https://www.maixhub.com/)註冊帳號後, 進入善心人士貢獻的[人臉辨識模式頁面](https://www.maixhub.com/index.php/index/index/detail/id/235.html)捲到最底下按下載鈕:

在頁面中輸入剛剛看到的序號:

按下提交後必須等待一段時間 (約 30 秒) 才會開始下載。
1. 燒錄剛剛下載取得的 .kfpkg 檔:

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
這程式沒有很穩, 跑一跑很容易當掉:
:::