Micropython玩转ESP32P4:绑定AI相关模块

2025-08-093066
精华项目
AI 快速预览详细 收起
本文介绍了如何在Micropython中使用FireBeetle 2 ESP32-P4开发板实现AI图像识别。首先介绍了开发板的外设接口,然后详细说明了如何绑定EspDL模块和自定义的猫咪识别模型。通过具体的代码示例,展示了如何实现人脸检测、行人检测和猫咪检测。最后提供了固件下载链接,方便用户直接使用。


近期,dfrobot出了一款新的开发板——FireBeetle 2 ESP32-P4,板载ESP32P4,虽然没有内置的WIFI和BLE,但是它的性能十分的高,所以很有幸能体验到这款开发板
1.开发板介绍
FireBeetle 2 ESP32-P4有很多种外设:
  • Type-C USB CDC:Type-C USB烧录、调试接口
  • IO3/LED:板载LED引脚
  • Power LED:主板电源指示灯
  • RST:复位按键
  • IO35/BOOT:IO引脚/BOOT按键
  • MIC: MEMS PDM麦克风
  • HIGH-SPEED USB OTG 2.0: Type-C高速USB OTG 2.0
  • ESP32-P4:ESP32-P4芯片
  • MIPI-DSI: 两通道MIPI-DSI屏幕(兼容树莓派4B DSI屏幕线序)
  • MIPI-CSI: 两通道MIPI-DSI屏幕(兼容树莓派4B CSI摄像头线序)
  • TF Card: TF卡插槽
  • 16MB FLASH: 16MB Flash存储
  • ESP32-C6:ESP32-C6-MINI-1模组,通过SDIO与ESP32-P4连接,用于扩展WiFi、蓝牙

2.绑定AI相关模块
在github上面,有一个大佬分享了一个将EspDL绑定到micropython中,但是还少了一个猫咪识别的模型,所以自己做了一个,仓库地址如下:
接着需要将驱动也绑定进来,修改~/esp/micropython.cmake如下:
  1. include(${CMAKE_CURRENT_LIST_DIR}/micropython_csi_camera/micropython.cmake)
  2. include(${CMAKE_CURRENT_LIST_DIR}/mp_jpeg/src/micropython.cmake)
  3. include(${CMAKE_CURRENT_LIST_DIR}/mp_esp_dl_models/src/micropython.cmake)
复制代码
再次编译即可使用。
3.体验AI相关模块
首先是人脸检测:
  1. from espdl import FaceDetector
  2. from jpeg import Decoder, Encoder
  3. decoder = Decoder()
  4. # 捕获并处理图像
  5. img = open("human_face.jpg", "rb").read()  # 捕获原始图像(通常是JPEG格式)
  6. wh = decoder.get_img_info(img)# 获取图像的宽度和高度
  7. # 获取图像的宽度和高度
  8. width, height = wh
  9. encoder = Encoder(width=width, height=height, pixel_format="RGB888")
  10. face_detector = FaceDetector(width=width, height=height)
  11. framebuffer = decoder.decode(img)  # 转换为RGB888格式
  12. # 将memoryview转换为bytearray以便修改
  13. framebuffer = bytearray(framebuffer)
  14. # 运行人脸检测
  15. results = face_detector.run(framebuffer)
  16. # 绘制边框
  17. def draw_rectangle(buffer, width, height, x, y, w, h, list1, color=(255, 0, 0)):
  18.     """
  19.     在RGB888格式的图像缓冲区上绘制矩形边框
  20.     :param buffer: 图像缓冲区
  21.     :param width: 图像宽度
  22.     :param height: 图像高度
  23.     :param x: 边框左上角的x坐标
  24.     :param y: 边框左上角的y坐标
  25.     :param w: 边框宽度
  26.     :param h: 边框高度
  27.     :param color: 边框颜色(RGB格式)
  28.     """
  29.     # 辅助函数:设置单个像素的颜色
  30.     def set_pixel(buffer, width, x, y, color):
  31.         offset = (y * width + x) * 3
  32.         buffer[offset] = color[0]  # R
  33.         buffer[offset + 1] = color[1]  # G
  34.         buffer[offset + 2] = color[2]  # B
  35.     # 辅助函数:绘制更大的点
  36.     def draw_large_dot(buffer, width, x, y, color, size=3):
  37.         for i in range(x - size, x + size + 1):
  38.             for j in range(y - size, y + size + 1):
  39.                 if 0 <= i < width and 0 <= j < height:
  40.                     set_pixel(buffer, width, i, j, color)
  41.     # 绘制上边框
  42.     for i in range(x, x + w):
  43.         if 0 <= i < width and 0 <= y < height:
  44.             set_pixel(buffer, width, i, y, color)
  45.     # 绘制下边框
  46.     for i in range(x, x + w):
  47.         if 0 <= i < width and 0 <= y + h < height:
  48.             set_pixel(buffer, width, i, y + h, color)
  49.     # 绘制左边框
  50.     for j in range(y, y + h):
  51.         if 0 <= j < height and 0 <= x < width:
  52.             set_pixel(buffer, width, x, j, color)
  53.     # 绘制右边框
  54.     for j in range(y, y + h):
  55.         if 0 <= j < height and 0 <= x + w < width:
  56.             set_pixel(buffer, width, x + w, j, color)
  57.     # 绘制特征点
  58.     if list1:
  59.         draw_large_dot(buffer, width, list1[0], list1[1], (0, 0, 255), size=2)
  60.         draw_large_dot(buffer, width, list1[2], list1[3], (0, 0, 255), size=2)
  61.         draw_large_dot(buffer, width, list1[4], list1[5], (0, 255, 0), size=2)
  62.         draw_large_dot(buffer, width, list1[6], list1[7], (255, 0, 0), size=2)
  63.         draw_large_dot(buffer, width, list1[8], list1[9], (255, 0, 0), size=2)
  64. if results:
  65.     # 在图像上绘制人脸边框
  66.     for face in results:
  67.         print(face)
  68.         x1, y1, x2, y2 = face['box']
  69.         draw_rectangle(framebuffer, width, height, x1, y1, x2 - x1, y2 - y1, face['features'], color=(255, 0, 0))  # 使用红色边框
  70. # 将带有边框的图像重新编码为JPEG格式并保存
  71. marked_img = encoder.encode(framebuffer)
  72. with open("marked_image.jpg", "wb") as f:
  73.     f.write(marked_img)</span>
复制代码

Micropython玩转ESP32P4:绑定AI相关模块图1
行人检测:
  1. from espdl import HumanDetector
  2. from jpeg import Decoder, Encoder
  3. ​
  4. ​
  5. decoder = Decoder()
  6. encoder = Encoder(width=640, height=480,pixel_format="RGB888")
  7. human_detector = HumanDetector(width=640, height=480)
  8. ​
  9. # 捕获并处理图像
  10. img = open("pedestrian.jpg", "rb").read()  # 捕获原始图像(通常是JPEG格式)
  11. framebuffer = decoder.decode(img)  # 转换为RGB888格式
  12. # 将memoryview转换为bytearray以便修改
  13. framebuffer = bytearray(framebuffer)
  14. # 运行行人检测
  15. results = human_detector.run(framebuffer)
  16. ​
  17. # 绘制边框
  18. def draw_rectangle(buffer, width, height, x, y, w, h, color=(255, 0, 0)):
  19.     """
  20.     在RGB888格式的图像缓冲区上绘制矩形边框
  21.     :param buffer: 图像缓冲区
  22.     :param width: 图像宽度
  23.     :param height: 图像高度
  24.     :param x: 边框左上角的x坐标
  25.     :param y: 边框左上角的y坐标
  26.     :param w: 边框宽度
  27.     :param h: 边框高度
  28.     :param color: 边框颜色(RGB格式)
  29.     """
  30.     # 辅助函数:设置单个像素的颜色
  31.     def set_pixel(buffer, width, x, y, color):
  32.         offset = (y * width + x) * 3
  33.         buffer[offset] = color[0]  # R
  34.         buffer[offset + 1] = color[1]  # G
  35.         buffer[offset + 2] = color[2]  # B
  36. ​
  37.     # 绘制上边框
  38.     for i in range(x, x + w):
  39.         if 0 <= i < width and 0 <= y < height:
  40.             set_pixel(buffer, width, i, y, color)
  41. ​
  42.     # 绘制下边框
  43.     for i in range(x, x + w):
  44.         if 0 <= i < width and 0 <= y + h < height:
  45.             set_pixel(buffer, width, i, y + h, color)
  46. ​
  47.     # 绘制左边框
  48.     for j in range(y, y + h):
  49.         if 0 <= j < height and 0 <= x < width:
  50.             set_pixel(buffer, width, x, j, color)
  51. ​
  52.     # 绘制右边框
  53.     for j in range(y, y + h):
  54.         if 0 <= j < height and 0 <= x + w < width:
  55.             set_pixel(buffer, width, x + w, j, color)
  56. ​
  57. # 在图像上绘制边框
  58. for face in results:
  59.     print(face)
  60.     x1, y1, x2, y2 = face['box']
  61.     draw_rectangle(framebuffer, 640, 480, x1, y1, x2-x1, y2-y1, color=(255, 0, 0))  # 使用红色边框
  62.    
  63. # 将带有边框的图像重新编码为JPEG格式并保存
  64. marked_img = encoder.encode(framebuffer)
  65. with open("marked_image1.jpg", "wb") as f:
  66.     f.write(marked_img)
复制代码

Micropython玩转ESP32P4:绑定AI相关模块图2
猫咪检测:
  1. from espdl import CatDetector
  2. from jpeg import Decoder, Encoder
  3. ​
  4. decoder = Decoder()
  5. # 捕获并处理图像
  6. img = open("cat.jpg", "rb").read()  # 捕获原始图像(通常是JPEG格式)
  7. wh = decoder.get_img_info(img)# 获取图像的宽度和高度
  8. # 获取图像的宽度和高度
  9. width, height = wh
  10. encoder = Encoder(width=width, height=height, pixel_format="RGB888")
  11. cat_detector = CatDetector(width=width, height=height)
  12. ​
  13. ​
  14. framebuffer = decoder.decode(img)  # 转换为RGB888格式
  15. # 将memoryview转换为bytearray以便修改
  16. framebuffer = bytearray(framebuffer)
  17. # 运行猫咪检测
  18. results = cat_detector.run(framebuffer)
  19. ​
  20. # 绘制边框
  21. def draw_rectangle(buffer, width, height, x, y, w, h, list1, color=(255, 0, 0)):
  22.     """
  23.     在RGB888格式的图像缓冲区上绘制矩形边框
  24.     :param buffer: 图像缓冲区
  25.     :param width: 图像宽度
  26.     :param height: 图像高度
  27.     :param x: 边框左上角的x坐标
  28.     :param y: 边框左上角的y坐标
  29.     :param w: 边框宽度
  30.     :param h: 边框高度
  31.     :param color: 边框颜色(RGB格式)
  32.     """
  33.     # 辅助函数:设置单个像素的颜色
  34.     def set_pixel(buffer, width, x, y, color):
  35.         offset = (y * width + x) * 3
  36.         buffer[offset] = color[0]  # R
  37.         buffer[offset + 1] = color[1]  # G
  38.         buffer[offset + 2] = color[2]  # B
  39. ​
  40.     # 辅助函数:绘制更大的点
  41.     def draw_large_dot(buffer, width, x, y, color, size=3):
  42.         for i in range(x - size, x + size + 1):
  43.             for j in range(y - size, y + size + 1):
  44.                 if 0 <= i < width and 0 <= j < height:
  45.                     set_pixel(buffer, width, i, j, color)
  46. ​
  47.     # 绘制上边框
  48.     for i in range(x, x + w):
  49.         if 0 <= i < width and 0 <= y < height:
  50.             set_pixel(buffer, width, i, y, color)
  51. ​
  52.     # 绘制下边框
  53.     for i in range(x, x + w):
  54.         if 0 <= i < width and 0 <= y + h < height:
  55.             set_pixel(buffer, width, i, y + h, color)
  56. ​
  57.     # 绘制左边框
  58.     for j in range(y, y + h):
  59.         if 0 <= j < height and 0 <= x < width:
  60.             set_pixel(buffer, width, x, j, color)
  61. ​
  62.     # 绘制右边框
  63.     for j in range(y, y + h):
  64.         if 0 <= j < height and 0 <= x + w < width:
  65.             set_pixel(buffer, width, x + w, j, color)
  66. ​
  67.     # 绘制特征点
  68.     if list1:
  69.         draw_large_dot(buffer, width, list1[0], list1[1], (0, 0, 255), size=2)
  70.         draw_large_dot(buffer, width, list1[2], list1[3], (0, 0, 255), size=2)
  71.         draw_large_dot(buffer, width, list1[4], list1[5], (0, 255, 0), size=2)
  72.         draw_large_dot(buffer, width, list1[6], list1[7], (255, 0, 0), size=2)
  73.         draw_large_dot(buffer, width, list1[8], list1[9], (255, 0, 0), size=2)
  74. if results:
  75.     # 在图像上绘制边框
  76.     for face in results:
  77.         print(face)
  78.         x1, y1, x2, y2 = face['box']
  79.         draw_rectangle(framebuffer, width, height, x1, y1, x2 - x1, y2 - y1, None, color=(255, 0, 0))  # 使用红色边框
  80. ​
  81. # 将带有边框的图像重新编码为JPEG格式并保存
  82. marked_img = encoder.encode(framebuffer)
  83. with open("marked_image4.jpg", "wb") as f:
  84.     f.write(marked_img)
复制代码

Micropython玩转ESP32P4:绑定AI相关模块图3
yolo11分类:
  1. from espdl import CocoDetector
  2. from jpeg import Decoder, Encoder
  3. from myufont import CustomBMFont
  4. from machine import Pin,SDCard
  5. import os
  6. sd = SDCard(slot=0,width=4, sck=43, cmd=44, data=(39, 40, 41, 42))
  7. os.mount(sd, '/sd')
  8. decoder = Decoder()
  9. encoder = Encoder(width=405, height=540,pixel_format="RGB888")
  10. face_detector = CocoDetector(width=405, height=540)
  11. MSCOCO_CLASSES = [
  12.     "人", "自行车", "汽车", "摩托车", "飞机", "公共汽车", "火车", "卡车", "船", "交通灯",
  13.     "消防栓", "消防水带", "停车计时器", "长椅", "鸟", "猫", "狗", "马", "羊", "牛",
  14.     "大象", "熊", "斑马", "长颈鹿", "背包", "伞", "手提包", "领带", "行李箱", "飞盘",
  15.     "滑雪板", "滑雪杖", "滑板", "冲浪板", "网球拍", "瓶子", "酒杯", "杯子", "刀叉", "碗",
  16.     "香蕉", "苹果", "三明治", "橙子", "西兰花", "胡萝卜", "热狗", "披萨", "甜甜圈", "蛋糕",
  17.     "椅子", "沙发", "盆栽", "床", "餐桌", "马桶", "电视", "笔记本电脑", "鼠标", "遥控器",
  18.     "键盘", "手机", "微波炉", "烤箱", "烤面包机", "水槽", "冰箱", "书", "时钟", "花瓶",
  19.     "剪刀", "泰迪熊", "吹风机", "牙刷"
  20. ]
  21. font = CustomBMFont('/sd/text_full_16px_2312.v3.bmf')
  22. # 捕获并处理图像
  23. img = open("bus.jpg", "rb").read()  # 捕获原始图像(通常是JPEG格式)
  24. framebuffer = decoder.decode(img)  # 转换为RGB888格式
  25. # 将memoryview转换为bytearray以便修改
  26. framebuffer = bytearray(framebuffer)
  27. # 运行人脸检测
  28. results = face_detector.run(framebuffer)
  29. ​
  30. # 绘制边框
  31. def draw_rectangle(buffer, width, height, x, y, w, h,font,label, color=(255, 0, 0)):
  32.     """
  33.     在RGB888格式的图像缓冲区上绘制矩形边框
  34.     :param buffer: 图像缓冲区
  35.     :param width: 图像宽度
  36.     :param height: 图像高度
  37.     :param x: 边框左上角的x坐标
  38.     :param y: 边框左上角的y坐标
  39.     :param w: 边框宽度
  40.     :param h: 边框高度
  41.     :param color: 边框颜色(RGB格式)
  42.     """
  43.     # 辅助函数:设置单个像素的颜色
  44.     def set_pixel(buffer, width, x, y, color):
  45.         offset = (y * width + x) * 3
  46.         buffer[offset] = color[0]  # R
  47.         buffer[offset + 1] = color[1]  # G
  48.         buffer[offset + 2] = color[2]  # B
  49.     def is_chinese(ch):
  50.         """判断一个字符是否为中文字符"""
  51.         if '\u4e00' <= ch <= '\u9fff' or \
  52.            '\u3400' <= ch <= '\u4dbf' or \
  53.            '\u20000' <= ch <= '\u2a6df':
  54.             return True
  55.         return False
  56.     def text(font, text, x_start, y_start, color,spacing=0, line_spacing=0, max_width=width):
  57.         font_size = font.font_size
  58.         bytes_per_row = (font_size + 7) // 8  # 每行占用的字节数
  59.         x, y = x_start, y_start
  60.         
  61.         for char in text:
  62.             # 处理换行符
  63.             if char == '\n':
  64.                 y += font_size + line_spacing
  65.                 x = x_start
  66.                 continue
  67.             if char == '\r':
  68.                 x += 2*font_size
  69.                 continue
  70.             # 获取字符宽度(中文字符全宽,ASCII字符半宽)
  71.             char_width = font_size if is_chinese(char) else font_size // 2
  72.             
  73.             # 检查是否需要换行
  74.             if max_width is not None and x + char_width > x_start + max_width:
  75.                 y += font_size + line_spacing
  76.                 x = x_start
  77.             
  78.             # 获取字符位图
  79.             bitmap = font.get_char_bitmap(char)
  80.             
  81.             # 绘制字符
  82.             for row in range(font_size):
  83.                 for col in range(char_width if not is_chinese(char) else font_size):
  84.                     byte_idx = row * bytes_per_row + col // 8
  85.                     bit_mask = 0x80 >> (col % 8)
  86.                     
  87.                     if byte_idx < len(bitmap) and (bitmap[byte_idx] & bit_mask):
  88.                         set_pixel(framebuffer,max_width,x + col, y + row, color)
  89.             
  90.             # 移动到下一个字符位置
  91.             x += char_width + spacing
  92.     # 绘制上边框
  93.     for i in range(x, x + w):
  94.         if 0 <= i < width and 0 <= y < height:
  95.             set_pixel(buffer, width, i, y, color)
  96. ​
  97.     # 绘制下边框
  98.     for i in range(x, x + w):
  99.         if 0 <= i < width and 0 <= y + h < height:
  100.             set_pixel(buffer, width, i, y + h, color)
  101. ​
  102.     # 绘制左边框
  103.     for j in range(y, y + h):
  104.         if 0 <= j < height and 0 <= x < width:
  105.             set_pixel(buffer, width, x, j, color)
  106. ​
  107.     # 绘制右边框
  108.     for j in range(y, y + h):
  109.         if 0 <= j < height and 0 <= x + w < width:
  110.             set_pixel(buffer, width, x + w, j, color)
  111.     text(font,label, x, y-20, color)
  112. ​
  113. # 在图像上绘制人脸边框
  114. for face in results:
  115.     #print(face)
  116.     x1, y1, x2, y2 = face['box']
  117.     label = MSCOCO_CLASSES[face['category']]+":"+str(int(face['score']*100))+"%"
  118.     draw_rectangle(framebuffer, 405, 540, x1, y1, x2-x1, y2-y1,font,label)  # 使用红色边框
  119.     print(label)
  120. # 将带有边框的图像重新编码为JPEG格式并保存
  121. marked_img = encoder.encode(framebuffer)
  122. with open("marked_image2.jpg", "wb") as f:
  123.     f.write(marked_img)
复制代码

Micropython玩转ESP32P4:绑定AI相关模块图4
Micropython玩转ESP32P4:绑定AI相关模块图5

创作许可协议

本项目采用 None(不开放任何权利,保留所有权利) 进行许可。

评论(0)
- 没有更多了 -