本帖最后由 zoey不种土豆 于 2024-10-16 15:03 编辑  
 
一、Mediapipe介绍 
MediaPipe Solutions 提供了一套库和工具,可帮助您在您的应用中快速应用人工智能 (AI) 和机器学习 (ML) 技术。您可以立即将这些解决方案插入到您的应用中,根据需要对其进行自定义,并在多个开发平台上使用。MediaPipe Solutions 是 MediaPipe 开源项目的一部分,因此您可以进一步自定义解决方案代码以满足您的应用需求。 
借助 MediaPipe Object Detector 任务,您可以检测图片或视频中多类对象的存在和位置。例如,对象检测器可以定位图片中的狗。此任务使用机器学习 (ML) 模型对图片数据执行操作,接受静态数据或连续视频串流作为输入并输出检测结果列表。每个检测结果代表图片或视频中出现的一个对象。 
Mediapipe所用模型介绍 
①EfficientDet-Lite0 模型介绍 
EfficientDet-Lite0 模型使用具有 320x320 输入大小和 BiFPN 特征网络的 EfficientNet-Lite0 骨干网络。该模型是使用 COCO 数据集训练的,COCO 数据集是一种大型对象检测数据集,其中包含 150 万个对象实例和 80 个对象标签。请参阅支持的标签的完整列表。EfficientDet-Lite0 提供 int8、float16 或 float32。推荐使用此模型,因为它能够在延迟时间和准确率之间取得平衡。它既准确又轻量,对于许多使用场景来说都足够。 
②EfficientDet-Lite2 模型介绍 
EfficientDet-Lite2 模型使用具有 448x448 输入大小和 BiFPN 特征网络的 EfficientNet-Lite2 骨干网络。该模型是使用 COCO 数据集训练的,COCO 数据集是一种大型对象检测数据集,其中包含 150 万个对象实例和 80 个对象标签。请参阅支持的标签的完整列表。EfficientDet-Lite2 作为 int8、float16 或 float32 模型提供。此模型通常比 EfficientDet-Lite0 更准确,但速度也更慢且内存占用量更大。此模型适用于准确性比速度和规模更重要的用例。 
③SSD MobileNetV2 模型介绍 
SSD MobileNetV2 模型使用具有 256x256 输入大小和 SSD 功能网络的 MobileNetV2 骨干网络。该模型是使用 COCO 数据集训练的,COCO 数据集是一种大型对象检测数据集,其中包含 150 万个对象实例和 80 个对象标签。请参阅支持的标签的完整列表。SSD MobileNetV2 提供 int8 和 float 32 模式。此模型比 EfficientDet-Lite0 更快、更轻量,但通常也不太准确。此模型适用于需要快速、轻量级模型(牺牲一定程度的准确度)的用例。 
④自定义模型 
如果您决定构建用于此任务的模型,本部分介绍了自定义模型的要求。自定义模型必须采用 TensorFlow Lite 格式,并且必须包含描述模型操作参数的元数据。 
 
 
行空板硬件介绍 
行空板是一款专为Python学习和使用设计的新一代国产开源硬件,采用单板计算机架构,集成LCD彩屏、WiFi蓝牙、多种常用传感器和丰富的拓展接口。同时,其自带Linux操作系统和Python环境,还预装了常用的Python库,让广大师生只需两步就能进行Python教学。 
 
行空板是一款基于RK3308 Arm 64位四核处理器的开发板,主频达到1.2GHz,配备512MB DDR3内存和16GB eMMC硬盘,运行Debian 10操作系统。此外,它支持2.4G Wi-Fi和蓝牙4.0,采用RTL8723DS芯片。行空板还集成了GD32VF103C8T6 RISC-V协处理器,主频108MHz,具备64KB Flash和32KB SRAM。 
行空板拥有多种板载元件,包括Home按键、A/B按键,2.8英寸可触控彩色屏幕,分辨率为240x320。设备还配备了电容式硅麦克风、PT0603光敏三极管光线传感器、无源蜂鸣器和蓝色LED。此外,它还内置了ICM20689六轴传感器,包括三轴加速度和三轴陀螺仪。 
在接口方面,行空板提供了多种连接选项。具有USB Type-C接口,用于将CPU与PC连接进行编程或为主板供电。还有USB TYPE-A接口,用于连接外部USB设备。此外,板上还有microSD卡接口用于扩展存储空间,3Pin I/O支持3路10位PWM和2路12位ADC,独立的4Pin I2C接口,以及与micro:bit兼容的19路独立I/O金手指,支持多种通信协议和功能。 
 
在行空板上运行Mediapipe 
在行空板上运行MediaPipe的尝试具有重要意义,主要体现在以下几个方面: 
1.教育与实践:行空板是一款专为Python学习和使用设计的国产开源硬件,预装了常用的Python库,适合广大师生进行Python教学和实践。通过在行空板上运行MediaPipe,可以让学生和开发者更直观地理解和应用人工智能和机器学习技术。 
2.高效开发:MediaPipe提供了一套高效的库和工具,能够快速实现AI和ML应用的开发。行空板集成了LCD彩屏、WiFi、蓝牙和多种传感器,提供了丰富的开发环境和硬件支持,使得在其上运行MediaPipe可以快速验证和展示AI应用。 
3.硬件性能:行空板基于RK3308 Arm 64位四核处理器,配备512MB DDR3内存和16GB eMMC硬盘,性能足以支持MediaPipe的简单模型运行。其内置的六轴传感器、麦克风和其他传感器也为AI应用提供了丰富的数据输入源。 
4.开源和定制化:MediaPipe作为开源项目,允许用户根据需求进行深度定制。而行空板的开源硬件设计也支持用户进行硬件和软件的定制和扩展,两者结合可以满足不同应用场景的需求。 
5.便携性和集成度:行空板体积小巧,功能齐全,适合便携式AI应用开发和展示。在其上运行MediaPipe,可以实现实时的对象检测和其他AI功能,适用于物联网设备、智能家居、教育机器人等多种场景。 
通过在行空板上运行MediaPipe,可以充分利用其硬件资源和软件环境,快速实现和展示AI应用,为教育、研究和开发提供强有力的支持。 
本文将演示如何在行空板上部署Mediapipe三个小型物体检测模型,主要分为以下几部分: 
- 行空板上运行Mediapipe的环境准备;
 - 进行行空板上使用Mediapipe物体检测的代码运行;
 - 使用int8量化版本的模型对运行速度进行加速;
 - 测试不同分辨率图片对这几个模型性能的影响。
 
  二、准备:运行Mediapipe的环境配置 
step 1 下载mini conda 
在终端输入:wget https://github.com/conda-forge/m ... e3-Linux-aarch64.sh 
 下载完后终端显示:已保存 “Miniforge3-Linux-aarch64.sh” 
 step 2 安装mini conda 
在终端输入: 
sudo bash Miniforge3-Linux-aarch64.sh 过程中遇到需要输入ENTER键或者yes键的照做。最后终端显示:Added mamba to /root/.bashrc 
==> For changes to take effect, close and re-open your current shell. <== 
Thank you for installing Miniforge3!   
在终端输入: 
source ~/.bashrc 
 安装完成,在终端输入:conda 
 终端显示: 
  
Step 3 激活conda 
在终端输入:conda activate 可以看到终端的显示由 
  
变成 
  
说明已经成功激活了conda 
Step 4 在conda中建立MediaPipe环境 
名字叫yolo,python版本选择3.10。在终端输入:conda create -n mediap python==3.10 过程中显示: 
  
输入y 
环境建立完终端显示: 
  
Step 5 激活mediapipe环境 
在终端中输入:conda activate mediapipe   
可以看到终端显示由 
  
变成 
  
说明激活mediapipe环境成功 
Step 6 安装mediapipe 
在终端输入:pip install mediapipe   
完成后终端显示: 
  
三、快速开始:Mediapipe模型的运行  
Step 1 激活mediapipe环境 
在终端中输入:conda activate mediapipe   
可以看到终端显示由 
  
变成 
  
说明激活mediapipe环境成功 
Step 2 创建目录mediapipe 
在终端输入: 
mkdir mediapipe 
 创建mediapipe目录,然后终端输入: 
cd mediapipe 
 进入目录。 
Step 3 下载模型文件 
可以在下面网址下载所要运行的模型: 
https://ai.google.dev/edge/mediapipe/solutions/vision/object_detector/index?hl=zh-cn#models 
如Introduction中所介绍,官方提供了三个物体检测模型 
EfficientDet-Lite0 
EfficientDet-Lite2 
SSDMobileNet-V2 
可以分别下载这三个模型进行运行。 
Step 4 准备图片 
这里仍然使用bus.jpg如果想下载,可以在终端输入: 
  
  
Step 5 编写代码 
新建文件test_pic.py,并编写以下代码: 
			
			
			- import numpy as np
 - import mediapipe as mp
 - from mediapipe.tasks import python
 - from mediapipe.tasks.python import vision
 - import cv2
 - import time
 - 
 - # Define color mappings
 - COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]  # Red, Green, Blue
 - DEFAULT_COLOR = (255, 255, 255)  # White for other categories
 - 
 - def visualize(original_image, detection_result, scale_ratio) -> np.ndarray:
 -     """Draws bounding boxes on the input image and return it.
 -     Args:
 -       original_image: The original input RGB image.
 -       detection_result: The list of all "Detection" entities to be visualized.
 -       scale_ratio: The ratio of the resized image size to the original image size.
 -     Returns:
 -       Image with bounding boxes.
 -     """
 -     # Dictionary to store category-color mappings
 -     category_color_map = {}
 - 
 -     for detection in detection_result.detections:
 -         # Get the category of the object
 -         category = detection.categories[0]
 -         category_name = category.category_name
 - 
 -         # Assign a color to the category if not already assigned
 -         if category_name not in category_color_map:
 -             if len(category_color_map) < len(COLORS):
 -                 category_color_map[category_name] = COLORS[len(category_color_map)]
 -             else:
 -                 category_color_map[category_name] = DEFAULT_COLOR
 - 
 -         color = category_color_map[category_name]
 - 
 -         # Draw bounding box
 -         bbox = detection.bounding_box
 -         start_point = int(bbox.origin_x / scale_ratio), int(bbox.origin_y / scale_ratio)
 -         end_point = int((bbox.origin_x + bbox.width) / scale_ratio), int((bbox.origin_y + bbox.height) / scale_ratio)
 -         cv2.rectangle(original_image, start_point, end_point, color, 3)
 - 
 -         # Draw label and score
 -         probability = round(category.score, 2)
 -         result_text = category_name + ' (' + str(probability) + ')'
 -         text_location = (int((MARGIN + bbox.origin_x) / scale_ratio),
 -                          int((MARGIN + ROW_SIZE + bbox.origin_y) / scale_ratio))
 -         cv2.putText(original_image, result_text, text_location, cv2.FONT_HERSHEY_PLAIN,
 -                     FONT_SIZE, color, FONT_THICKNESS)
 - 
 -     return original_image
 - 
 - def detect_objects(model_path, image_path, target_width, output_path, show_image):
 -     """Detect objects in an image and save/display the result.
 -     Args:
 -       model_path: Path to the model file.
 -       image_path: Path to the input image file.
 -       target_width: The width to resize the image for inference.
 -       output_path: Path to save the annotated image.
 -       show_image: Boolean flag to display the image after processing.
 -     """
 -     # STEP 1: Import the necessary modules.
 -     base_options = python.BaseOptions(model_asset_path=model_path)
 -     options = vision.ObjectDetectorOptions(base_options=base_options,
 -                                            score_threshold=0.5)
 -     detector = vision.ObjectDetector.create_from_options(options)
 - 
 -     # STEP 2: Create an ObjectDetector object.
 -     global MARGIN, ROW_SIZE, FONT_SIZE, FONT_THICKNESS
 -     MARGIN = 10  # pixels
 -     ROW_SIZE = 10  # pixels
 -     FONT_SIZE = 1
 -     FONT_THICKNESS = 1
 - 
 -     # STEP 3: Read the local image
 -     original_image = cv2.imread(image_path)
 -     if original_image is None:
 -         print("Error: Could not read image.")
 -         return
 - 
 -     # Resize the image to a smaller size to speed up inference
 -     scale_ratio = target_width / original_image.shape[1]
 -     target_height = int(original_image.shape[0] * scale_ratio)
 -     resized_image = cv2.resize(original_image, (target_width, target_height))
 - 
 -     # Convert the image to the format required by MediaPipe.
 -     mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=resized_image)
 - 
 -     # STEP 4: Detect objects in the image.
 -     start_time = time.time()
 -     detection_result = detector.detect(mp_image)
 -     end_time = time.time()
 - 
 -     # Print inference time
 -     inference_time = end_time - start_time
 -     print(f'Inference time: {inference_time:.2f} seconds')
 - 
 -     # STEP 5: Process the detection result. In this case, visualize it.
 -     annotated_image = visualize(original_image, detection_result, scale_ratio)
 - 
 -     # Save the result
 -     cv2.imwrite(output_path, annotated_image)
 -     print(f'Result saved to {output_path}')
 - 
 -     # Display the result if needed
 -     if show_image:
 -         cv2.imshow('Object Detection', annotated_image)
 -         cv2.waitKey(0)
 -         cv2.destroyAllWindows()
 - 
 - # Example call
 - detect_objects(
 -     model_path='efficientdet_lite0.tflite',
 -     image_path='bus.jpg',
 -     target_width=640,
 -     output_path='bus_640.jpg',
 -     show_image=False
 - )
 
  复制代码
  
这里使用上一步下载的 efficientdet_lite0.tflite 模型 
Step 6 运行代码并查看结果 
运行后终端显示: 
  
可以看出,efficientdet_lite0 模型处理640分辨率的图片时间为2.62s。 
处理后的图片结果如下 
  
再使用efficientdet_lite2模型,耗时为8.47秒: 
  
  
再使用 ssd_mobilenet_v2 运行,耗时为1.88秒: 
  
  
小结 
不同的模型效果和速度有所不同: 
efficientdet_lite0 的准确性一般; 
ssd_mobilenet_v2 的速度和准确性都较好。 
  
四、优化:使用int8量化的模型 
我们可以使用官方提供的int8模型进行加速。步骤如下: 
Step 1 下载官方int8模型 
直接到下载官方的int8模型即可。地址如下: 
EfficientDet-Lite0 (int8) 
EfficientDet-Lite2 (int8) 
SSDMobileNet-V2 (int8) 
分别保存为: 
efficientdet_lite0_int8.tflite 
efficientdet_lite2_int8.tflite 
ssd_mobilenet_v2_int8.tflite 
Step 2 修改代码 
将上一步中的代码中的模型替换成上面下载的int8模型,如:- import numpy as np
 - import mediapipe as mp
 - from mediapipe.tasks import python
 - from mediapipe.tasks.python import vision
 - import cv2
 - import time
 - 
 - # Define color mappings
 - COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]  # Red, Green, Blue
 - DEFAULT_COLOR = (255, 255, 255)  # White for other categories
 - 
 - def visualize(original_image, detection_result, scale_ratio) -> np.ndarray:
 -     (... ...)
 - 
 - def detect_objects(model_path, image_path, target_width, output_path, show_image):
 -     (... ...)
 - 
 - # Example call
 - detect_objects(
 -     model_path='efficientdet_lite0_int8.tflite',
 -     image_path='bus.jpg',
 -     target_width=640,
 -     output_path='bus_640.jpg',
 -     show_image=False
 - )
 
  复制代码 Step 3 运行代码并查看结果 
efficientdet_lite0_int8.tflite 模型运行耗时1.43秒: 
  
  
efficientdet_lite2_int8.tflite 模型运行耗时4.03秒: 
  
  
ssd_mobilenet_v2_int8.tflite 模型运行耗时1.82秒: 
  
  
小结 
量化后,det两个模型速度有明显提升,mobilenet变化不大;准确性都保持的很好。 
 
 
五、进一步测试:不同的输入图片尺寸 
为了进一步加快速度,我们还可以缩小推理图片的尺寸。步骤如下: 
Step 1 修改代码 
修改上面代码的Example call部分,例如对于efficientdet_lite0_int8.tflite 模型: 
- import numpy as np
 - import mediapipe as mp
 - from mediapipe.tasks import python
 - from mediapipe.tasks.python import vision
 - import cv2
 - import time
 - 
 - <strong># Define color mappings</strong>
 - COLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]  # Red, Green, Blue
 - DEFAULT_COLOR = (255, 255, 255)  # White for other categories
 - 
 - def visualize(original_image, detection_result, scale_ratio) -> np.ndarray:
 -     (... ...)
 - 
 - def detect_objects(model_path, image_path, target_width, output_path, show_image):
 -     (... ...)
 - 
 - <strong># Example call</strong>
 - 
 - for r in [640, 448, 320, 256, 128, 64]:
 -     print(r) 
 -     detect_objects(
 -     model_path='efficientdet_lite0_int8.tflite', 
 -     image_path='bus.jpg', 
 -     target_width=r, 
 -     output_path=f'bus_det_l2_{r}_int8.jpg', 
 -     show_image=False)</code></pre></div><span data-lark-record-data="{"rootId":"H1QFdiICyo9ed2xHbeBcNUr5nxf","text":{"initialAttributedTexts":{"text":{"0":"import numpy as np\nimport mediapipe as mp\nfrom mediapipe.tasks import python\nfrom mediapipe.tasks.python import vision\nimport cv2\nimport time\n\n# Define color mappings\nCOLORS = [(255, 0, 0), (0, 255, 0), (0, 0, 255)]  # Red, Green, Blue\nDEFAULT_COLOR = (255, 255, 255)  # White for other categories\n\ndef visualize(original_image, detection_result, scale_ratio) -> np.ndarray:\n    (... ...)\n\ndef detect_objects(model_path, image_path, target_width, output_path, show_image):\n    (... ...)\n\n# Example call\n\nfor r in [640, 448, 320, 256, 128, 64]:\n    print(r) \n    detect_objects(\n    model_path='efficientdet_lite0_int8.tflite', \n    image_path='bus.jpg', \n    target_width=r, \n    output_path=f'bus_det_l2_{r}_int8.jpg', \n    show_image=False)"},"attribs":{"0":"*0|7+3z*0*1+n*0|a+8y*0*1+e*0|9+63*0+l"}},"apool":{"numToAttrib":{"0":["author","7360571945601384452"],"1":["bold","true"]},"nextNum":2}},"type":"text","referenceRecordMap":{},"extra":{"channel":"saas","pasteRandomId":"6d2e8d82-caef-41a8-9a3d-95f5b148996c","mention_page_title":{},"external_mention_url":{}},"isKeepQuoteContainer":false,"isFromCode":true,"selection":[{"id":210,"type":"text","selection":{"start":0,"end":742},"recordId":"QgWRdUfmsoKwLgxNoADcO3kNnmh"}],"payloadMap":{},"isCut":false}" data-lark-record-format="docx/text" class="lark-record-clipboard"></span>
 
  复制代码 Step 2 运行代码并查看结果 
对于 efficientdet_lite0.tflite 模型: 
   
对于 efficientdet_lite0_int8.tflite  模型: 
   
对于 efficientdet_lite2.tflite 模型: 
   
对于 efficientdet_lite2_int8.tflite 模型: 
   
对于 ssd_mobilenet_v2.tflite 模型: 
   
对于 ssd_mobilenet_v2_int8.tflite 模型: 
   
小结 
可以看到,随着输入尺寸的减小,模型的速度并没有明显变快。 
并且,这三个模型训练的分辨率是固定的: 
efficientdet_lite0.tflite:320 
efficientdet_lite2.tflite:448 
ssd_mobilenet_v2.tflite:256 
输入的图片尺寸大反而对准确性有一定降低。 
这儿有点反常的是,虽然 ssd_mobilenet_v2.tflite 的训练分辨率最低,但是其对于高分辨率图片的适应力还是较好的。 
 
六、结论 
1.可以在行空板运行Mediapipe的目标检测模型 
本文详细介绍了如何在行空板上部署Mediapipe,并对几个常见模型进行了测试。  
2.在行空板上,两个模型的int8量化可以带来显著的速度提升 
对于 efficientdet_lite0 和 efficientdet_lite2 模型,int8量化有显著的速度提升,而且精度表现没有明显下降;对于 ssd_mobilenet_v2 模型,int8量化并没有带来速度提升(不确定官方的模型是否正确)。 
3.在行空板上使用Mediapipe进行目标检测时的模型推荐 
随着输入尺寸的减小,模型的速度并没有明显变快;有的模型,随着输入图片尺寸变大,性能反而下降。对于中小分辨率的图片(128-448),推荐使用 efficientdet_lite0_int8.tflite 模型;对于较大分辨率的图片(>448),推荐使用 ssd_mobilenet_v2.tflite 模型。 
4.较小分辨率时,模型 efficientdet_lite0_int8.tflite 准确率最好;较大分辨率时,模型 efficientdet_lite2_int8.tflite 准确率较好。 
5.接下来会有更多测试,请持续关注! 
 
 |