查看原文
其他

声网:基于 TensorFlow 在实时音视频中实现图像识别

TensorFlow 2023-03-08

The following article is from 声网Agora Author 声网Agora

文 / 张乾泽

近两年来,Python 在众多编程语言中的热度一直稳居前五,热门程度可见一斑。Python 拥有很活跃的社区和丰富的第三方库,Web 框架、爬虫框架、数据分析框架、机器学习框架等,开发者无需重复造轮子,可以用 Python 进行 Web 编程、网络编程,开发多媒体应用,进行数据分析,或实现图像识别等应用。其中图像识别是最热门的应用场景之一,也是与实时音视频契合度最高的应用场景之一。


声网 Agora 现已支持 Python 语言,我们将 Python SDK 已经开放至 Github。大家可以利用它将实时音视频通话与人脸识别、图像识别、声纹识别或其它可能用到 Python 库的应用结合起来,玩出不一样的花样。为了方便大家理解如何把它用在自己的项目中,我们还写了一份 Python demo,与最流行的 TensorFlow 结合,在视频通话的场景下实现了图像识别,并已将其开源至 Github。


本文将从 TensorFlow 图像识别原理讲起,然后分析我们是如何实现这个 Demo 的。希望这个小 Demo 可以给希望在视频通话中应用 TensorFlow 或 TensorFlow 的爱好者们起到一些参考作用。接下来,让我们开始吧。



TensorFlow 图片/物体识别

TensorFlow 是 Google 的开源深度学习库,你可以使用这个框架以及 Python 编程语言,构建大量基于机器学习的应用程序。而且还有很多人把 TensorFlow 构建的应用程序或者其他框架,开源发布到 GitHub 上。所以我们今天主要基于 TensorFlow 学习下物体识别。


TensorFlow 提供了用于检测图片或视频中所包含物体的 API

注:物体检测 API 链接

https://github.com/tensorflow/models/tree/master/research/object_detection


物体检测是检测图片中所出现的全部物体并且用矩形 (Anchor Box) 进行标注,物体的类别可以包括多种,例如人、车、动物、路标等。举个例子了解 TensorFlow 物体检测 API 的使用方法,这里使用预训练好的 ssd_mobilenet_v1_coco 模型 (Single Shot MultiBox Detector),从 GitHub 可以获取更多可用的物体检测模型。

注:物体检测模型 链接

https://github.com/tensorflow/models/blob/master/research/object_detection/g3doc/detection_model_zoo.md#coco-trained-models-coco-models

 

加载库:1# -*- coding:utf-8 -*-
2
3import numpy as np
4import tensorflow as tf
5import matplotlib.pyplot as plt
6from PIL import Image
7from utils import label_map_util
8from utils import visualization_utils as vis_util

定义一些常量:

1PATH_TO_CKPT = 'ssd_mobilenet_v1_coco_2017_11_17/frozen_inference_graph.pb'
2PATH_TO_LABELS = 'ssd_mobilenet_v1_coco_2017_11_17/mscoco_label_map.pbtxt'
3NUM_CLASSES = 90
加载预训练好的模型:1detection_graph = tf.Graph()
2with detection_graph.as_default():
3  od_graph_def = tf.GraphDef()
4  with tf.gfile.GFile(PATH_TO_CKPT, 'rb'as fid:
5    od_graph_def.ParseFromString(fid.read())
6    tf.import_graph_def(od_graph_def, name='')

加载分类标签数据:

1label_map = label_map_util.load_labelmap(PATH_TO_LABELS)
2categories = label_map_util.convert_label_map_to_categories(label_map,max_num_classes=NUM_CLASSES, use_display_name=True)
3category_index = label_map_util.create_category_index(categories)

一个将图片转为数组的辅助函数,以及测试图片路径:

1def load_image_into_numpy_array(image):
2  (im_width, im_height) = image.size
3  return np.array(image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8)
4
5TEST_IMAGE_PATHS = ['test_images/image1.jpg''test_images/image2.jpg']

使用模型进行物体检测:

1with detection_graph.as_default():
2  with tf.Session(graph=detection_graph) as sess:
3      image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
4      detection_boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
5      detection_scores = detection_graph.get_tensor_by_name('detection_scores:0')
6      detection_classes = detection_graph.get_tensor_by_name('detection_classes:0')
7      num_detections = detection_graph.get_tensor_by_name('num_detections:0')
8      for image_path in TEST_IMAGE_PATHS:
9        image = Image.open(image_path)
10        image_np = load_image_into_numpy_array(image)
11        image_np_expanded = np.expand_dims(image_np, axis=0)
12        (boxes, scores, classes, num) = sess.run(
13          [detection_boxes, detection_scores, detection_classes, num_detections], 
14          feed_dict={image_tensor: image_np_expanded})
15
16        vis_util.visualize_boxes_and_labels_on_image_array(image_np, np.squeeze(boxes), np.squeeze(classes).astype(np.int32), np.squeeze(scores), category_index, use_normalized_coordinates=True, line_thickness=8)
17        plt.figure(figsize=[128])
18        plt.imshow(image_np)
19        plt.show()
检测结果如下,第一张图片检测出了两只狗狗



实时音视频场景下 TensorFlow 物体识别

既然 TensorFlow 在静态图片的物体识别已经相对成熟,那在现实场景中,大量的实时音视频互动场景中,如何来做物体识别?我们现在基于声网实时视频的 SDK,阐述如何做物体识别。


首先我们了解视频其实就是由一帧一帧的图像组合而成,所以从这个层面来说,视频中的目标识别就是从每一帧图像中做目标识别,从这个层面上讲,二者没有本质区别。在理解这个前提的基础上,我们就可以相对简单地做实时音视频场景下 TensorFlow 物体识别。

(1)读取 Agora 实时音视频,截取远端视频流的图片

1   def onRenderVideoFrame(uid, width, height, yStride,
2                            uStride, vStride, yBuffer, uBuffer, vBuffer,
3                            rotation, renderTimeMs, avsync_type):

4         # 用 isImageDetect 字段判断前一帧图像是否已完成识别,若完成置为True,执行以下代码,执行完置为false
5        if EventHandlerData.isImageDetect:
6            y_array = (ctypes.c_uint8 * (width * height)).from_address(yBuffer)
7            u_array = (ctypes.c_uint8 * ((width // 2) * (height // 2))).from_address(uBuffer)
8            v_array = (ctypes.c_uint8 * ((width // 2) * (height // 2))).from_address(vBuffer)
9
10            Y = np.frombuffer(y_array, dtype=np.uint8).reshape(height, width)
11            U = np.frombuffer(u_array, dtype=np.uint8).reshape((height // 2, width // 2)).repeat(2, axis=0).repeat(2, axis=1)
12            V = np.frombuffer(v_array, dtype=np.uint8).reshape((height // 2, width // 2)).repeat(2, axis=0).repeat(2, axis=1)
13            YUV = np.dstack((Y, U, V))[:height, :width, :]
14            # AI模型中大多数模型都是RGB格式训练,声网提供的视频回调数据源是YUV格式,我们做下格式转换
15            RGB = cv2.cvtColor(YUV, cv2.COLOR_YUV2RGB, 3)
16            EventHandlerData.image = Image.fromarray(RGB)
17            EventHandlerData.isImageDetect = False

(2)TensorFlow 对截取图片进行物体识别

1class objectDetectThread(QThread):
2    objectSignal = pyqtSignal(str)
3    def __init__(self):
4        super().__init__()
5    def run(self):
6        detection_graph = EventHandlerData.detection_graph
7        with detection_graph.as_default():
8            with tf.Session(graph=detection_graph) as sess:
9                (im_width, im_height) = EventHandlerData.image.size
10                image_np = np.array(EventHandlerData.image.getdata()).reshape((im_height, im_width, 3)).astype(np.uint8)
11                image_np_expanded = np.expand_dims(image_np, axis=0)
12                image_tensor = detection_graph.get_tensor_by_name('image_tensor:0')
13                boxes = detection_graph.get_tensor_by_name('detection_boxes:0')
14                scores = detection_graph.get_tensor_by_name('detection_scores:0')
15                classes = detection_graph.get_tensor_by_name('detection_classes:0')
16                num_detections = detection_graph.get_tensor_by_name('num_detections:0')
17                (boxes, scores, classes, num_detections) = sess.run(
18                    [boxes, scores, classes, num_detections],
19                    feed_dict={image_tensor: image_np_expanded})
20                objectText = []
21                # 如果识别概率大于百分之四十,我们就在文本框内显示所识别物体
22                for i, c in enumerate(classes[0]):
23                    if scores[0][i] > 0.4
24                        object = EventHandlerData.category_index[int(c)]['name']
25                        if object not in objectText:
26                            objectText.append(object)
27                    else:
28                        break
29                self.objectSignal.emit(', '.join(objectText))
30                EventHandlerData.detectReady = True
31                # 本帧图片识别完,isImageDetect 字段置为True,再次开始读取并转换Agora远端实时音视频
32                EventHandlerData.isImageDetect = True
我们已经将这个 Demo 以及 Agora Python SDK 上传至 Github,大家可以直接下载使用。
  • Agora Python TensorFlow Demo

    https://github.com/AgoraIO-Community/Agora-Python-Tensorflow-Demo

  • Agora Python SDK

    https://github.com/AgoraIO-Community/Agora-Python-SDK 


请注意,这个 Demo 仅作为演示使用,从获取到远端实时视频画面,到 TensorFlow 进行识别处理,再到显示出识别效果,期间需要 2 至 4 秒。不同网络情况、设备性能、算法模型,其识别的效率也不同。感兴趣的开发者可以尝试更换自己的算法模型,来优化识别的延时。


最后秀一下 Demo 实现的效果。左图是对端的视频图像,右下角是我们本地的视频图像,在识别对端图像后,右侧的文本框中会显示出识别结果。注意,这个🙂贴纸只是后期 P 上去的,我们在 Demo 中还没有加入贴图的功能,如果你感兴趣,可以试着在 Demo 基础上做改进,丰富功能。



展望

接下来,我们也会继续尝试使用视频目标检测算法,在视频中动态标出 bounding box 的同时,针对一些特殊物品能做预警或特殊处理,如果小伙伴们在实时音视频领域的物体识别场景有更多有意思的想法,也欢迎小伙伴可以联系我们。

注:如果 Demo 运行中遇到问题,请在 RTC 开发者社区中反馈、交流,或在 Github 提 issue。




您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存