如何在TensorFlow Lite官方detect.py示例中提取class_name值
问题描述
在树莓派上使用TensorFlow Lite官方示例提供的detect.py脚本开展目标检测开发时,需要在命令行单独打印被检测对象的类别名称:例如模型检测到医用外科口罩时,命令行可直接输出surgical_mask。
目前直接打印detection_result对象可得到如下结构的检测结果:
detections { bounding_box { origin_x: 135 origin_y: 14 width: 478 height: 457 } classes { index: 0 score: 0.875 class_name: "surgical_mask" } }
但无法单独提取并打印其中的class_name字段,当前使用的detect.py完整代码如下:
# Copyright 2021 The TensorFlow Authors. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. """Main script to run the object detection routine.""" import argparse import sys import time import cv2 from tflite_support.task import core from tflite_support.task import processor from tflite_support.task import vision import utils def run(model: str, camera_id: int, width: int, height: int, num_threads: int, enable_edgetpu: bool) -> None: """Continuously run inference on images acquired from the camera. Args: model: Name of the TFLite object detection model. camera_id: The camera id to be passed to OpenCV. width: The width of the frame captured from the camera. height: The height of the frame captured from the camera. num_threads: The number of CPU threads to run the model. enable_edgetpu: True/False whether the model is a EdgeTPU model. """ # Variables to calculate FPS counter, fps = 0, 0 start_time = time.time() # Start capturing video input from the camera cap = cv2.VideoCapture(camera_id) cap.set(cv2.CAP_PROP_FRAME_WIDTH, width) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, height) # Visualization parameters row_size = 20 # pixels left_margin = 24 # pixels text_color = (0, 0, 255) # red font_size = 1 font_thickness = 1 fps_avg_frame_count = 10 # Initialize the object detection model base_options = core.BaseOptions( file_name=model, use_coral=enable_edgetpu, num_threads=num_threads) detection_options = processor.DetectionOptions( max_results=3, score_threshold=0.3) options = vision.ObjectDetectorOptions( base_options=base_options, detection_options=detection_options) detector = vision.ObjectDetector.create_from_options(options) # Continuously capture images from the camera and run inference while cap.isOpened(): success, image = cap.read() if not success: sys.exit( 'ERROR: Unable to read from webcam. Please verify your webcam settings.' ) counter += 1 image = cv2.flip(image, 1) # Convert the image from BGR to RGB as required by the TFLite model. rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) # Create a TensorImage object from the RGB image. input_tensor = vision.TensorImage.create_from_array(rgb_image) # Run object detection estimation using the model. detection_result = detector.detect(input_tensor) # Draw keypoints and edges on input image image = utils.visualize(image, detection_result) # Calculate the FPS if counter % fps_avg_frame_count == 0: end_time = time.time() fps = fps_avg_frame_count / (end_time - start_time) start_time = time.time() # Show the FPS fps_text = 'FPS = {:.1f}'.format(fps) text_location = (left_margin, row_size) cv2.putText(image, fps_text, text_location, cv2.FONT_HERSHEY_PLAIN, font_size, text_color, font_thickness) print(detection_result) # Stop the program if the ESC key is pressed. if cv2.waitKey(1) == 27: break cv2.imshow('object_detector', image) cap.release() cv2.destroyAllWindows() def main(): parser = argparse.ArgumentParser( formatter_class=argparse.ArgumentDefaultsHelpFormatter) parser.add_argument( '--model', help='Path of the object detection model.', required=False, default='efficientdet_lite0.tflite') parser.add_argument( '--cameraId', help='Id of camera.', required=False, type=int, default=0) parser.add_argument( '--frameWidth', help='Width of frame to capture from camera.', required=False, type=int, default=640) parser.add_argument( '--frameHeight', help='Height of frame to capture from camera.', required=False, type=int, default=480) parser.add_argument( '--numThreads', help='Number of CPU threads to run the model.', required=False, type=int, default=4) parser.add_argument( '--enableEdgeTPU', help='Whether to run the model on EdgeTPU.', action='store_true', required=False, default=False) args = parser.parse_args() run(args.model, int(args.cameraId), args.frameWidth, args.frameHeight, int(args.numThreads), bool(args.enableEdgeTPU)) if __name__ == '__main__': main()
解决方法
detection_result是TFLite Support库定义的结构化Protobuf对象,直接按照对象属性层级访问即可提取class_name字段。
找到代码中print(detection_result)的位置,将其替换为如下代码即可:
# 遍历当前帧所有符合阈值的检测结果 for detection in detection_result.detections: # 单个检测结果的classes列表按置信度从高到低排序,取置信度最高的类别 top_category = detection.classes[0] # 提取类别名并打印,可按需同时打印置信度、边界框坐标等信息 print(top_category.class_name)
补充说明:
- 初始化检测模型时设置了
max_results=3,单帧最多返回3个检测结果,上述循环会打印当前帧内所有检测到的目标类别 - 如果仅需要打印置信度最高的单个目标类别,可直接使用
detection_result.detections[0].classes[0].class_name取值,建议增加空值判断,避免画面中无检测目标时触发索引报错 - 如果需要筛选特定类别(仅打印口罩类),增加
if top_category.class_name == "surgical_mask":判断即可
内容的提问来源于stack exchange,提问作者Carlo Jhon Sario
相关产品推荐
相关产品推荐

