Преобразовать пользовательский вывод Vision в визуализацию API обнаружения объектов Tensorflow?

Я создал модель с использованием Azure Custom Vision и экспортировал ее как Tensorflow - SavedModel. Модель используется локально с помощью вспомогательного кода, который был включен в экспорт. Однако он немного изменен для чтения из захвата видео в реальном времени с использованием OpenCV VideoCapture () / Read () в цикле.

Мое приложение хорошо обнаруживает потоки видео в реальном времени, так как я могу правильно видеть результаты, выводимые на консоль, но у меня возникают проблемы с правильным отображением точных ограничивающих рамок в выходном видеопотоке. В выходных данных консоли отображается массив результатов прогнозов модели Azure Custom Vision, и я вижу массив координат ограничивающей рамки в том, что кажется нормализованными значениями.

До использования Azure Custom Vision я мог использовать существующие модели из Model Zoo, а помощники по визуализации Python API обнаружения объектов могли правильно отображать ограничивающие прямоугольники на дисплее канала.

Однако координаты, возвращаемые из Azure Custom Vision, по-видимому, отличаются от координат, возвращаемых моделями SSD COCO по умолчанию?

Мне нужно преобразовать координаты ограничивающей рамки, возвращаемые из Azure Custom Vision, в значения, понятные помощникам визуализации API обнаружения объектов Tensorflow.

Исходный код с использованием API обнаружения объектов и модели SSD COCO (работает!):

output_dict = run_inference_for_single_image(image_resize, graph)
                #Visualization of the results of a detection.
                vis_util.visualize_boxes_and_labels_on_image_array(
                    image_np,
                    output_dict['detection_boxes'],
                    output_dict['detection_classes'],
                    output_dict['detection_scores'],
                    category_index,
                    instance_masks=output_dict.get('detection_masks'),
                    use_normalized_coordinates=True,
                    line_thickness=2)
                cv2.imshow('object_detection', cv2.resize(image_np, (640, 480)))

В версии Azure Custom Vision не отображаются поля правильно:

    image_resize = cv2.resize(image_np, (512, 512))

    predictions = od_model.predict_image(Image.fromarray(image_resized))

    if len(predictions) > 0:
        print(predictions)                    
        output_dict = {}
        output_dict['detection_boxes'] = []
        output_dict['detection_boxes'] = [???]  <-- Populate with compatible shape!!!?????
        output_dict['detection_scores'] = np.asarray([ sub['probability'] for sub in predictions ])                
        output_dict['detection_classes'] = np.asarray([ sub['tagId'] for sub in predictions ])
        output_dict['detection_class_names'] = np.asarray([ sub['tagName'] for sub in predictions ])
        vis_util.visualize_boxes_and_labels_on_image_array(image_np,
              output_dict['detection_boxes'],
              output_dict['detection_classes'],
              output_dict['detection_scores'],
              category_index,
              instance_masks=output_dict.get('detection_masks'),
              use_normalized_coordinates=True,
              line_thickness=2)

-->  Console showing Custom Vision Model Response:
         {'probability': 0.95146583, 'tagId': 1, 'tagName': 'MyObject', 'boundingBox': {'left': 0.11083871, 'top': 0.65143364, 'width': 0.05332406, 'height': 0.04930339}}
         {'probability': 0.92589812, 'tagId': 0, 'tagName': 'OtherObject', 'boundingBox': {'left': 0.24750886, 'top': 0.68784532, 'width': 0.54308632, 'height': 0.17839652}}

Используя модель Azure Custom Vision, я не могу правильно отображать ограничивающие рамки. Мне удалось преобразовать Custom Vision boundingBox в ту же форму, которую ожидает визуализация, но прямоугольник никогда не будет иметь правильные координаты. Я думал, что это может быть потому, что системы координат между тензором возврата COCO SSD и тензором отклика предсказания Custom Vision рассчитываются по-разному? Или, может быть, координаты двух фигур находятся в другом порядке?

Кто-нибудь уже решил этот перевод? Я что делаю неправильно? Заранее спасибо!


person E E Mindlin    schedule 27.06.2020    source источник


Ответы (1)


Что ж, отвечая на мой собственный вопрос ... смог получить это грубой силой ... теперь все мои ответы Custom Vision переводятся в вывод COCO SSD Tensorflow Object Detection API. Это сводится к двум вещам:

  1. Создайте совместимый файл .pbtxt, соответствующий порядку файла .txt, экспортированного из Custom Vision Portal «Экспорт». Я использую SavedModel ... Обратите внимание, что файлы .pbtxt начинаются с 1 индекса, в то время как tagId, возвращаемый в моделях Custom Vision, основан на нуле. Это было легко решить, просто добавив +1 к tagId при назначении ключа detect_classes в словаре и позволив TF OD API сделать все остальное, назначив удобочитаемые метки ограничивающим прямоугольникам в прямых трансляциях.

  2. Граничная рамка с координатами кунг-фу ...! После того, как я переместил результаты из Custom Vision API в «массив массивов», соответствующий исходной модели TF, и вычислил xmax и ymax .., я обнаружил, что биты визуализации API обнаружения объектов в конечном итоге преобразованы в «коробку» в форме значений xmin, ymin, xmax, ymax в этом порядке (не пытайтесь использовать xmin, xmax, ymin, ymax, например, при преобразовании). Ответ Custom Vision API возвращает xmin, ymin, ширину и высоту ограничивающей рамки. Я видел это в нескольких ответах здесь, но обычно в контексте чего-то еще. Модели ImageNet / Resnet по умолчанию также возвращают разные формы. Я не отвечаю на этот вопрос здесь, потому что в настоящее время мне это не нужно, но я уверен, что аналогичный подход грубой силы будет работать с этой моделью, если это необходимо.

В любом случае ... какой-то код ...

        ret, image_np = cap.read()
        if image_np is None:
            continue

        predictions = od_model.predict_image(Image.fromarray(image_np))
        
        if len(predictions) > 0:                
            output_dict = {}            
            output_dict['detection_boxes'] = []

            output_dict['detection_scores'] = np.asarray([ sub['probability'] for sub in predictions ])                
            output_dict['detection_classes'] = np.asarray([ sub['tagId'] for sub in predictions ]) **+ 1**
            output_dict['detection_class_names'] = np.asarray([ sub['tagName'] for sub in predictions ])

            for p in predictions:
                print(p)        #for debugging purposes...            
                box_left = p['boundingBox']['left']
                box_top = p['boundingBox']['top']
                box_height = p['boundingBox']['height'] 
                box_width = p['boundingBox']['width']
                output_dict['detection_boxes'].append(np.asarray(( box_top, box_left, box_top+box_height, box_left + box_width)))
                
            output_dict['detection_boxes'] = np.asarray(output_dict['detection_boxes'])

            vis_util.visualize_boxes_and_labels_on_image_array(
                    image_np,
                    output_dict['detection_boxes'],
                    output_dict['detection_classes'],
                    output_dict['detection_scores'],
                    category_index,
                    min_score_thresh=0.949,                        
                    instance_masks=output_dict.get('detection_masks'),
                    use_normalized_coordinates=True,
                    line_thickness=2)
        cv2.imshow('object_detection', cv2.resize(image_np, (VID_W, VID_H)))
person E E Mindlin    schedule 02.07.2020