[经验分享] 【DigiKey创意大赛】家庭共享智能药盒04+人脸分辨程序设计

oet   2024-10-18 20:52 楼主
 
上一贴介绍了设计PCB和调试BME280,给OPENMV增加了显示模块和传感器。本帖介绍人脸分辨程序的设计过程。
基于OPENMV的人脸分辨程序设计在星瞳官网有一个专门的教程,链接如下:
里面还有对应的视频,将原理讲解的比较明白。主要是使用OPENMV系统自带的LBP算法实现人脸分辨。
最开始我使用官网例程进行学习,请家人做模特照相,调试程序。如下图是试验的文件。
wd_205050m5htu7xt77h5hcuh.png
效果基本和官网视频介绍的相当,但是需要手工在TF卡上建立文件,然后分别录入图片,整个操作流程繁琐,结构松散,想整合到我这次作品中,有点无从下手。
思虑后我打算参考例程自己从新写个程序,实现我这次特定的功能。我先把程序需求想好了,然后备忘就在记事本上记下来了。恰好当时正在给孩子处理作业的事情,使用Kimi找算术题,造句等,借助AI给孩子辅导作业很方便。这个弄完我突然想到,何不让AI帮我写程序呢,试试又不花钱,说干就干。
我把之前写好的需求直接输入Kimi,经过它的一通查询,果然给我弄出一篇代码,我仔细读后发现有些问题,开始手动修改代码。然后出来第一版能凑合运行的框架程序,但是距离能用还差很远。
本来打算放弃了,但是又有点不甘心,就又尝试告诉Kimi,指明它生成的代码有哪些不足,让它自己修改,然后我就发现它果然能改好,这让我大喜,我就按照和同事沟通一样,不停的多次沟通,它就不停的迭代生成的代码。如下图是某次沟通截图。
wd_205051dv5nv9n26cdyej2y.png
使用Kimi关键是文字需求描述要清晰准确,下图是我三次更改描述语句,让Kimi进行程序生成。
wd_205051s4w0h5c5r3r0rx13.png
经过七次大版本迭代,终于搞出一版在程序结构,功能实现上基本都能满足要求的代码。下图是我保存的历次大版本代码。
wd_205051acjsjcqpnsj427r7.png
直接生成的代码,在编译运行时还是有些问题的,下面是直接生成的代码,大家可以看看有什么问题。
代码1:
#带显示功能
import sensor, image, time, pyb, os
from fpioa_manager import fm, board_info
from Maix import GPIO
from display import SPIDisplay

# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
sensor.set_auto_gain(False)  # 关闭自动增益
sensor.set_auto_whitebal(False)  # 关闭自动白平衡

# 初始化SD卡
uos.mount(sdcard, '/sd')

# 初始化LED灯
led = pyb.LED(1)

# 初始化串口
uart3 = pyb.UART(3, 115200)

# 初始化显示屏
lcd = SPIDisplay(width=132, height=132, bgr=True)
lcd.init()

# 阈值设置
THRESHOLD = 50

# 录入人脸图片并计算LBP特征
def capture_face(index):
    if not os.path.exists('/sd/{}'.format(index)):
        os.mkdir('/sd/{}'.format(index))
    for i in range(10):
        img = sensor.snapshot()
        img = img.resize(128, 128)  # 调整图像大小
        lcd.display(img)  # 显示调整大小后的图像
        lbp = img.find_lbp((0, 0, img.width(), img.height()))
        lbp.save('/sd/{}/face_{}.lbp'.format(index, i))
        led.on()
        time.sleep(100)
        led.off()
        time.sleep(900)

# 接收指令并录入人脸
def receive_and_capture():
    while True:
        data = uart3.read()
        if data:
            cmd = data.decode()[0]
            if cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)
            elif cmd == 'r':
                face_recognition()

# 启动人脸识别
def face_recognition():
    img = sensor.snapshot()
    img = img.resize(128, 128)  # 调整图像大小
    lcd.display(img)  # 显示调整大小后的图像
    lbp = img.find_lbp((0, 0, img.width(), img.height()))
    min_diff = 999999
    recognized = None
    for folder in range(1, 7):
        for i in range(10):
            template_file = '/sd/{}/face_{}.lbp'.format(folder, i)
            if os.path.exists(template_file):
                template = image.load(template_file)
                diff = image.match_descriptors(lbp, template)
                if diff < min_diff:
                    min_diff = diff
                    recognized = folder
    if min_diff < THRESHOLD:
        uart3.write('{}\n'.format(recognized))
    else:
        uart3.write('0\n')
    # 显示识别结果
    img.draw_string(10, 10, "Recognizing...", color=(255), scale=2)
    if recognized:
        img.draw_string(10, 40, "Match Found!", color=(255), scale=2)
    else:
        img.draw_string(10, 40, "No Match Found", color=(255), scale=2)
    lcd.display(img)  # 显示带有识别结果的图像

# 主循环
def main():
    while True:
        data = uart3.read()
        if data:
            cmd = data.decode()[0]
            if cmd == 'r':
                face_recognition()
            elif cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)

if __name__ == '__main__':
    main()

 

经过我的修改,最终能运行的代码:
代码2:
#带显示功能
#import sensor, image, time, pyb, os
#from fpioa_manager import fm, board_info
#from Maix import GPIO
#from display import SPIDisplay

import time, os, pyb
import display
import sensor, image, machine

# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
#sensor.set_framesize(sensor.QVGA)
#sensor.set_pixformat(sensor.RGB565)  # or sensor.GRAYSCALE
sensor.set_framesize(sensor.B128X128)  # 128x160大小的特定液晶屏。
sensor.skip_frames(time=200)
sensor.set_auto_gain(False)  # 关闭自动增益
sensor.set_auto_whitebal(False)  # 关闭自动白平衡

# 初始化SD卡
#os.mount(sdcard, '/sd')

# 初始化LED灯
led = pyb.LED(1)

# 初始化串口
uart3 = pyb.UART(3, 115200)

# 初始化显示屏
lcd = display.SPIDisplay( width=132, height=132,bgr=True)
#lcd = SPIDisplay(width=132, height=132, bgr=True)
#lcd.init()
print("start  ok")
# 阈值设置
THRESHOLD = 2600

# 录入人脸图片并计算LBP特征
def capture_face(index):
    if not '{}'.format(index) in os.listdir():
        os.mkdir('{}'.format(index))  # 新建一个新的文件夹
        print("mkdir ok")

    for i in range(10):
        led.on()
        time.sleep_ms(100)
        img = sensor.snapshot()
        lcd.write(img)  # 拍照并显示图像。
        img.save('/{}/face_{}.pgm'.format(index, i))
        print('/{}/face_{}.pgm'.format(index, i))
        led.off()
        time.sleep_ms(900)

# 接收指令并录入人脸
def receive_and_capture():
    while True:
        data = uart3.read()
        if data:
            cmd = data.decode()[0]
            if cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)
            elif cmd == 'r':
                face_recognition()

# 启动人脸识别
def face_recognition():
    img = sensor.snapshot()
    lcd.write(img)  # 拍照并显示图像。
    lbp = img.find_lbp((0, 0, img.width(), img.height()))
    min_diff = 999999
    recognized = None
    img_temp = img
    for folder in range(1, 7):
        for i in range(10):
            if '{}'.format(folder) in os.listdir():
                template_file = '/{}/face_{}.pgm'.format(folder, i)
                img = image.Image(template_file)
                template  = img.find_lbp((0, 0, img.width(), img.height()))
                diff = image.match_descriptor(lbp, template)
                if diff < min_diff:
                    min_diff = diff
                    recognized = folder
                    print(min_diff,recognized)
                    img_temp = img
            else:
                print("no dir:"+template_file)
    if min_diff < THRESHOLD:
        uart3.write('{}\n'.format(recognized))
        print('{}\n'.format(recognized))
        img_temp.draw_string(5, 120, "Match Found!", color=(255), scale=1)
    else:
        uart3.write('0\n')
        print('0\n')
        img_temp.draw_string(5, 120, "No Match Found", color=(255), scale=1)
    # 显示识别结果
    lcd.write(img_temp)  # 显示带有识别结果的图像

# 主循环
def main():
    img = sensor.snapshot()
    lcd.write(img)  # 拍照并显示图像。
    while True:
        data = uart3.read()
        if data:
            cmd = data.decode()[0]
            if cmd == 'r':
                face_recognition()
            elif cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)

if __name__ == '__main__':
    main()

 

代码编辑好后就是做实验了。这个时候再找家人不停地拍照太麻烦了,我就想直接从网上找现成的照片进行测试也一样啊。经过资料查找,最终确定使用《CK表情分类数据集》。这个数据集中,包含多个人的各种表情图片,每种表情记录了几张到十几张图片不等,其中每个人图片总数都在几十张以上,我选取了7个人,使用每个人部分图片作为训练对比参考,剩余的作为测试图片,这样一下子解决了需要不同人拍照问题。
我只需在另外一个显示器上显示参考或测试图片,把摄像头调整好距离,就能完美测试了。下图是实际调试拍照,测试效果很好。
wd_205051yxxrms4jqv9hysms.jpg
在OpenMV IDE输出调试信息显示程序运行正确无误。
wd_205051aapiu7h9vipupqji.png
在串口终端也完全实现了预期的发送指令和接收结果的功能。
wd_205051qg4gzgrf4tyifgds.png
通过以上测试,确认这个AI生成的程序完全实现了预期的功能。
从此之后,我又多了一个好帮手,编写简单程序,只需要把需求写清楚,让Kimi帮忙实现,不但效率高,还省脑细胞!

本帖最后由 oet 于 2024-10-18 20:57 编辑

回复评论 (4)

实时性好吗?

 

点赞  2024-10-20 13:42
引用: JOEYCH 发表于 2024-10-20 13:42 实时性好吗?  

一秒以内识别完成,速度还可以

点赞  2024-10-20 20:00

请教楼主,你的产品如果售卖是否需要进行3C认证啊

点赞  2024-10-23 20:53

5楼 oet 

引用: chejm 发表于 2024-10-23 20:53 请教楼主,你的产品如果售卖是否需要进行3C认证啊

这个做着玩的,没打算销售

如果是用于销售的,最好是去过一下认证,市场适用范围更广。

点赞  2024-10-24 00:06
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复