oet 发表于 2024-10-18 20:52

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

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

<div>&nbsp;</div>

<div>上一贴介绍了设计PCB和调试BME280,给OPENMV增加了显示模块和传感器。本帖介绍人脸分辨程序的设计过程。</div>

<div>基于OPENMV的人脸分辨程序设计在星瞳官网有一个专门的教程,链接如下:</div>

<div><a href="https://book.openmv.cc/image/face.html">https://book.openmv.cc/image/face.html</a></div>

<div>里面还有对应的视频,将原理讲解的比较明白。主要是使用OPENMV系统自带的LBP算法实现人脸分辨。</div>

<div>最开始我使用官网例程进行学习,请家人做模特照相,调试程序。如下图是试验的文件。</div>

<div></div>

<div>效果基本和官网视频介绍的相当,但是需要手工在TF卡上建立文件,然后分别录入图片,整个操作流程繁琐,结构松散,想整合到我这次作品中,有点无从下手。</div>

<div>思虑后我打算参考例程自己从新写个程序,实现我这次特定的功能。我先把程序需求想好了,然后备忘就在记事本上记下来了。恰好当时正在给孩子处理作业的事情,使用Kimi找算术题,造句等,借助AI给孩子辅导作业很方便。这个弄完我突然想到,何不让AI帮我写程序呢,试试又不花钱,说干就干。</div>

<div>我把之前写好的需求直接输入Kimi,经过它的一通查询,果然给我弄出一篇代码,我仔细读后发现有些问题,开始手动修改代码。然后出来第一版能凑合运行的框架程序,但是距离能用还差很远。</div>

<div>本来打算放弃了,但是又有点不甘心,就又尝试告诉Kimi,指明它生成的代码有哪些不足,让它自己修改,然后我就发现它果然能改好,这让我大喜,我就按照和同事沟通一样,不停的多次沟通,它就不停的迭代生成的代码。如下图是某次沟通截图。</div>

<div></div>

<div>使用Kimi关键是文字需求描述要清晰准确,下图是我三次更改描述语句,让Kimi进行程序生成。</div>

<div></div>

<div>经过七次大版本迭代,终于搞出一版在程序结构,功能实现上基本都能满足要求的代码。下图是我保存的历次大版本代码。</div>

<div></div>

<div>直接生成的代码,在编译运行时还是有些问题的,下面是直接生成的代码,大家可以看看有什么问题。</div>

<div>代码1:</div>

<div>
<pre>
<code class="language-python">#带显示功能
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()
            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 &lt; min_diff:
                  min_diff = diff
                  recognized = folder
    if min_diff &lt; 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()
            if cmd == 'r':
                face_recognition()
            elif cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)

if __name__ == '__main__':
    main()</code></pre>

<p>&nbsp;</p>
</div>

<div>经过我的修改,最终能运行的代码:</div>

<div>代码2:</div>

<div>
<pre>
<code class="language-python">#带显示功能
#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("startok")
# 阈值设置
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()
            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 &lt; min_diff:
                  min_diff = diff
                  recognized = folder
                  print(min_diff,recognized)
                  img_temp = img
            else:
                print("no dir:"+template_file)
    if min_diff &lt; 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()
            if cmd == 'r':
                face_recognition()
            elif cmd.isdigit() and int(cmd) in range(1, 7):
                capture_face(cmd)

if __name__ == '__main__':
    main()
</code></pre>

<p>&nbsp;</p>
</div>

<div>代码编辑好后就是做实验了。这个时候再找家人不停地拍照太麻烦了,我就想直接从网上找现成的照片进行测试也一样啊。经过资料查找,最终确定使用《CK表情分类数据集》。这个数据集中,包含多个人的各种表情图片,每种表情记录了几张到十几张图片不等,其中每个人图片总数都在几十张以上,我选取了7个人,使用每个人部分图片作为训练对比参考,剩余的作为测试图片,这样一下子解决了需要不同人拍照问题。</div>

<div>我只需在另外一个显示器上显示参考或测试图片,把摄像头调整好距离,就能完美测试了。下图是实际调试拍照,测试效果很好。</div>

<div></div>

<div>在OpenMV IDE输出调试信息显示程序运行正确无误。</div>

<div></div>

<div>在串口终端也完全实现了预期的发送指令和接收结果的功能。</div>

<div></div>

<div>通过以上测试,确认这个AI生成的程序完全实现了预期的功能。</div>

<div>从此之后,我又多了一个好帮手,编写简单程序,只需要把需求写清楚,让Kimi帮忙实现,不但效率高,还省脑细胞!</div>

<p><!--importdoc--></p>

JOEYCH 发表于 2024-10-20 13:42

<p>实时性好吗?</p>

<p>&nbsp;</p>

oet 发表于 2024-10-20 20:00

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

&nbsp;

<p>一秒以内识别完成,速度还可以</p>

chejm 发表于 2024-10-23 20:53

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

oet 发表于 2024-10-24 00:06

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

<p>这个做着玩的,没打算销售<img height="52" src="https://bbs.eeworld.com.cn/static/editor/plugins/hkemoji/sticker/facebook/titter.gif" width="48" /></p>

<p>如果是用于销售的,最好是去过一下认证,市场适用范围更广。</p>
页: [1]
查看完整版本: 【DigiKey创意大赛】家庭共享智能药盒04+人脸分辨程序设计