Как использовать Google Colaboratory для обработки видео

Опубликовано: 4 Января, 2022

Знаете ли вы, что набор компьютерных алгоритмов может обрабатывать видеопоток таким образом, чтобы они могли обнаруживать преступную деятельность, контролировать пробки и даже автоматически обнаруживать события в спортивных трансляциях? Благодаря применению машинного обучения (ML) идея получения такого большого количества данных из простого видео не кажется такой уж нереальной. В этой статье мы обсудим применение готовой логики алгоритма машинного обучения для обнаружения и сегментации объектов к видео.

В частности, мы поговорим о том, как настроить Google Colaboratory для решения задач обработки видео с помощью машинного обучения. Вы узнаете, как использовать этот сервис Google и бесплатный графический процессор NVIDIA Tesla K80, который он предоставляет для достижения ваших собственных целей в обучении нейронных сетей. Эта статья будет полезна людям, которые знакомятся с машинным обучением и рассматривают возможность работы с распознаванием изображений и обработкой видео.

Обработка изображений с ограниченными аппаратными ресурсами

Задача - распознавать людей на видеозаписи с помощью алгоритмов машинного обучения (ML). Мы решили начать с основ. Во-первых, давайте рассмотрим, что на самом деле представляет собой видеозапись.

С технической точки зрения любая видеозапись состоит из серии неподвижных изображений в определенном формате, сжатых с помощью видеокодека. Следовательно, распознавание объектов в видеопотоке сводится к разделению потока на отдельные изображения или кадры и применению к ним предварительно обученного алгоритма распознавания изображений ML.

Для этого мы решили использовать нейронную сеть из репозитория Mask_R-CNN для классификации одиночных изображений. Репозиторий содержит реализацию сверточной нейронной сети на Python3, TensorFlow и Keras. Посмотрим, что получилось из этого плана.

Образец Mask_RCNN

Мы разработали и реализовали простой образец Mask_RCNN, который получает изображение на входе и распознает в нем объекты. Мы создали образец на основе описания demo.ipynb взято из репозитория Mask_R-CNN. Вот код нашего образца:

import os, sys
random import
import math
import numpy as np
import skimage.io
import matplotlib
import matplotlib.pyplot as plt
os.chdir( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )
sys.path.append( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )
# Root directory of the project
ROOT_DIR = os.path.abspath( "." )
# Import Mask RCNN
sys.path.append(ROOT_DIR) # To find local version of the library
from mrcnn import utils
import mrcnn.model as modellib
from mrcnn import visualize
# Import COCO config
sys.path.append(os.path.join(ROOT_DIR, "samples/coco/" )) # To find local version
import coco
# Directory to save logs and trained model
MODEL_DIR = os.path.join(ROOT_DIR, "logs" )
# Local path to trained weights file
COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5" )
# Download COCO trained weights from Releases if needed
if not os.path.exists(COCO_MODEL_PATH):
utils.download_trained_weights(COCO_MODEL_PATH)
# Directory of images to run detection on
IMAGE_DIR = os.path.join(ROOT_DIR, "images" )
class InferenceConfig(coco.CocoConfig):
# Set batch size to 1 since we'll be running inference on
# one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU
GPU_COUNT = 1
IMAGES_PER_GPU = 1
config = InferenceConfig()
config.display()
# Create model object in inference mode.
model = modellib.MaskRCNN(mode = "inference" , model_dir = MODEL_DIR, config = config)
# Load weights trained on MS-COCO
model.load_weights(COCO_MODEL_PATH, by_name = True )
# COCO Class names
# Index of the class in the list is its ID. For example, to get ID of
# the teddy bear class, use: class_names.index('teddy bear')
class_names = [ 'BG' , 'person' , 'bicycle' , 'car' , 'motorcycle' , 'airplane' ,
'bus' , 'train' , 'truck' , 'boat' , 'traffic light' ,
'fire hydrant' , 'stop sign' , 'parking meter' , 'bench' , 'bird' ,
'cat' , 'dog' , 'horse' , 'sheep' , 'cow' , 'elephant' , 'bear' ,
'zebra' , 'giraffe' , 'backpack' , 'umbrella' , 'handbag' , 'tie' ,
'suitcase' , 'frisbee' , 'skis' , 'snowboard' , 'sports ball' ,
'kite' , 'baseball bat' , 'baseball glove' , 'skateboard' ,
'surfboard' , 'tennis racket' , 'bottle' , 'wine glass' , 'cup' ,
'fork' , 'knife' , 'spoon' , 'bowl' , 'banana' , 'apple' ,
'sandwich' , 'orange' , 'broccoli' , 'carrot' , 'hot dog' , 'pizza' ,
'donut' , 'cake' , 'chair' , 'couch' , 'potted plant' , 'bed' ,
'dining table' , 'toilet' , 'tv' , 'laptop' , 'mouse' , 'remote' ,
'keyboard' , 'cell phone' , 'microwave' , 'oven' , 'toaster' ,
'sink' , 'refrigerator' , 'book' , 'clock' , 'vase' , 'scissors' ,
'teddy bear' , 'hair drier' , 'toothbrush' ]
# Load a random image from the images folder
file_names = next (os.walk(IMAGE_DIR))[ 2 ]
image = skimage.io.imread(os.path.join(IMAGE_DIR, random.choice(file_names)))
# Run detection
results = model.detect([image], verbose = 1 )
# Visualize results
r = results[ 0 ]
visualize.display_instances(image, r[ 'rois' ], r[ 'masks' ],
r[ 'class_ids' ],class_names, r[ 'scores' ])

В этом примере / content / drive / My Drive / Colab Notebooks / MRCNN_pure - это путь к нашему репозиторию с Mask_R-CNN. В результате мы получили следующее:

Эта часть демонстрационного кода просматривает папку изображений, случайным образом выбирает изображение и загружает его в нашу модель нейронной сети для классификации:

# Load a random image from the images folder
file_names = next (os.walk(IMAGE_DIR))[ 2 ]
image = skimage.io.imread(os.path.join(IMAGE_DIR, random.choice(file_names)))
# Run detection
results = model.detect([image], verbose = 1 )

Давайте изменим образец Mask_R-CNN, чтобы он распознавал все изображения в папке изображений:

# Load a random image from the images folder
file_names = next (os.walk(IMAGE_DIR))[ 2 ]
for file_name in file_names:
image = skimage.io.imread(os.path.join(IMAGE_DIR, file_name))
# Run detection
results = model.detect([image], verbose = 1 )
# Visualize results
r = results[ 0 ]
visualize.display_instances(image, r[ 'rois' ], r[ 'masks' ],
r[ 'class_ids' ],class_names, r[ 'scores' ])

После запуска демонстрационного кода в течение пяти минут консоль отобразила следующий вывод:


Processing 1 images
image shape: (415, 640, 3) min: 0.00000 max: 255.00000 uint8
molded_images shape: (1, 1024, 1024, 3) min: -123.70000 max: 151.10000 float64
image_metas shape: (1, 93) min: 0.00000 max: 1024.00000 float64
anchors shape: (1, 261888, 4) min: -0.35390 max: 1.29134 float32
Segmentation fault (core dumped)



Первоначально мы запускали демонстрационный код на компьютере с Intel Core i5 и 8 ГБ ОЗУ без дискретной видеокарты. Код падал каждый раз в разных местах, но чаще всего он падал в фреймворке TensorFlow во время выделения памяти. Более того, любые попытки запустить какое-либо другое программное обеспечение во время процесса распознавания изображений замедляли работу компьютера до такой степени, что становились бесполезными.

Таким образом, мы столкнулись с серьезной проблемой: любые эксперименты по знакомству с ML требовали мощной видеокарты и большего количества аппаратных ресурсов. Без этого мы не могли бы запускать другие задачи при распознавании большого количества изображений.

Расширение наших аппаратных ресурсов с помощью Google Colaboratory

Мы решили расширить наши аппаратные ресурсы с помощью службы Colaboratory от Google, также известной как Colab. Google Colab - это бесплатная облачная служба, которая обеспечивает использование ЦП и ГП, а также предварительно настроенного экземпляра виртуальной машины. В частности, Google предлагает графический процессор NVIDIA Tesla K80 с 12 ГБ выделенной видеопамяти, что делает Colab идеальным инструментом для экспериментов с нейронными сетями.

Прежде чем объяснять, как работать с этой службой Google, мы хотели бы выделить другие полезные функции Colaboratory.

Выбрав Colab для своих экспериментов с машинным обучением, вы получите:

- поддержка Python 2.7 и Python 3.6, чтобы вы могли улучшить свои навыки программирования;
- возможность работать с блокнотом Jupyter, чтобы вы могли создавать, редактировать и публиковать свои файлы .ipynb;
- возможность подключиться к среде выполнения Jupyter с вашего локального компьютера;
- множество предустановленных библиотек, включая TensorFlow, Keras и OpenCV, а также возможность взаимодействия с вашими пользовательскими библиотеками в Google Colaboratory;
- возможность загрузки, чтобы вы могли добавить свою обученную модель;
- интеграция с GitHub, чтобы вы могли загружать общедоступные записные книжки GitHub или сохранять копию файла Colab на GitHub;
- простая визуализация с помощью таких популярных библиотек, как matplotlib;
- формы, которые можно использовать для параметризации кода;
- возможность хранить записные книжки Google Colab на вашем Google Диске.

Чтобы начать использовать графический процессор Google Colab, вам просто нужно предоставить доступ к вашему скрипту .ipynb, который реализован в контейнере Docker. Контейнер Docker закреплен за вами только на 12 часов. Все созданные вами скрипты по умолчанию хранятся на вашем Google Диске в разделе Colab Notebooks, который создается автоматически при подключении к Colaboratory. По истечении 12 часов все ваши данные в контейнере будут удалены. Вы можете избежать этого, установив свой Google Диск в свой контейнер и работая с ним. В противном случае файловая система образа Docker будет доступна только в течение ограниченного периода времени.

Настройка Google Colab

Давайте сначала объясним, как создать записную книжку .ipynb. Откройте здесь Google Colaboratory, выберите раздел Google Drive и нажмите НОВЫЙ НОУТБУК PYTHON 3:

Переименуйте записную книжку, как хотите, щелкнув имя файла. Теперь вам нужно выбрать свое оборудование. Для этого просто перейдите в раздел «Редактировать», найдите «Настройки ноутбука», выберите «GPU» в качестве аппаратного ускорителя и сохраните изменения, нажав «СОХРАНИТЬ».

После сохранения новых настроек вам станет доступен контейнер Docker с дискретной видеокартой. Вы будете уведомлены об этом сообщением «Подключено» в правом верхнем углу страницы:

Если вы не видите это сообщение, выберите «Подключиться к размещенной среде выполнения».

Теперь вы можете подключить свой Google Диск к этому контейнеру, чтобы переместить исходный код и сохранить результаты своей работы в контейнере. Для этого просто скопируйте приведенный ниже код в первую ячейку таблицы и нажмите кнопку Play (или Shift + Enter).

Смонтируйте Google Диск, запустив этот код:

# from google.colab import drive
drive.mount( '/content/drive' )

Вы получите запрос на авторизацию. Щелкните ссылку, авторизуйтесь, скопируйте код подтверждения, вставьте его в текстовое поле в своем скрипте .ipynb и нажмите Enter. Если авторизация прошла успешно, ваш Google Диск будет смонтирован по пути / content / drive / My Drive. Чтобы следить за деревом файлов, выберите «Файлы» в левом меню.

Теперь у вас есть контейнер Docker с графическим процессором Tesla K80, ваш Google Диск в качестве хранилища файлов и записная книжка .ipynb для выполнения скриптов.

Использование Google Colab для распознавания объектов

Теперь мы опишем, как запустить наш пример Mask_R-CNN для распознавания объектов в Google Colab. Мы загружаем репозиторий Mask_RCNN на наш Google Диск по пути / content / drive / My Drive / Colab Notebooks /.

Затем мы добавляем наш пример кода в скрипт .ipynb. Когда вы это сделаете, не забудьте изменить свой путь к папке Mask_RCNN следующим образом:

os.chdir( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )
sys.path.append( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )

Если вы все сделаете правильно, результаты выполнения кода предоставят вам изображение, на котором обнаружены и распознаны все объекты.

Вы также можете изменить пример кода, чтобы он обрабатывал все тестовые изображения:

import os, sys
import random
import math
import numpy as np
import skimage.io
import matplotlib
import matplotlib.pyplot as plt
os.chdir( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )
sys.path.append( "/content/drive/My Drive/Colab Notebooks/MRCNN_pure" )
# Root directory of the project
ROOT_DIR = os.path.abspath( "." )
# Import Mask RCNN
sys.path.append(ROOT_DIR) # To find local version of the library
from mrcnn import utils
import mrcnn.model as modellib
from mrcnn import visualize
# Import COCO config
sys.path.append(os.path.join(ROOT_DIR, "samples/coco/" )) # To find local version
import coco
# Directory to save logs and trained model
MODEL_DIR = os.path.join(ROOT_DIR, "logs" )
# Local path to trained weights file
COCO_MODEL_PATH = os.path.join(ROOT_DIR, "mask_rcnn_coco.h5" )
# Download COCO trained weights from Releases if needed
if not os.path.exists(COCO_MODEL_PATH):
utils.download_trained_weights(COCO_MODEL_PATH)
# Directory of images to run detection on
IMAGE_DIR = os.path.join(ROOT_DIR, "images" )
class InferenceConfig(coco.CocoConfig):
# Set batch size to 1 since we'll be running inference on
# one image at a time. Batch size = GPU_COUNT * IMAGES_PER_GPU
GPU_COUNT = 1
IMAGES_PER_GPU = 1
config = InferenceConfig()
config.display()
# Create model object in inference mode.
model = modellib.MaskRCNN(mode= "inference" , model_dir=MODEL_DIR, config=config)
# Load weights trained on MS-COCO
model.load_weights(COCO_MODEL_PATH, by_name=True)
# COCO Class names
# Index of the class in the list is its ID. For example, to get ID of
# the teddy bear class, use: class_names.index('teddy bear')
class_names = [ 'BG' , 'person' , 'bicycle' , 'car' , 'motorcycle' , 'airplane' ,
'bus' , 'train' , 'truck' , 'boat' , 'traffic light' ,
'fire hydrant' , 'stop sign' , 'parking meter' , 'bench' , 'bird' ,
'cat' , 'dog' , 'horse' , 'sheep' , 'cow' , 'elephant' , 'bear' ,
'zebra' , 'giraffe' , 'backpack' , 'umbrella' , 'handbag' , 'tie' ,
'suitcase' , 'frisbee' , 'skis' , 'snowboard' , 'sports ball' ,
'kite' , 'baseball bat' , 'baseball glove' , 'skateboard' ,
'surfboard' , 'tennis racket' , 'bottle' , 'wine glass' , 'cup' ,
'fork' , 'knife' , 'spoon' , 'bowl' , 'banana' , 'apple' ,
'sandwich' , 'orange' , 'broccoli' , 'carrot' , 'hot dog' , 'pizza' ,
'donut' , 'cake' , 'chair' , 'couch' , 'potted plant' , 'bed' ,
'dining table' , 'toilet' , 'tv' , 'laptop' , 'mouse' , 'remote' ,
'keyboard' , 'cell phone' , 'microwave' , 'oven' , 'toaster' ,
'sink' , 'refrigerator' , 'book' , 'clock' , 'vase' , 'scissors' ,
'teddy bear' , 'hair drier' , 'toothbrush' ]
# Load a random image from the images folder
file_names = next(os.walk(IMAGE_DIR))[2]
for file_name in file_names:
image = skimage.io.imread(os.path.join(IMAGE_DIR, file_name))
# Run detection
results = model.detect([image], verbose=1)
# Visualize results
r = results[0]
visualize.display_instances(image, r[ 'rois' ], r[ 'masks' ],
r[ 'class_ids' ],class_names, r[ 'scores' ])

Используя обнаружение объектов в Google Colab, мы быстро получали результаты с распознанными объектами, в то время как наш компьютер продолжал работать, как обычно, даже во время процесса распознавания изображений.

Использование Google Colab для обработки видео

Посмотрим, как мы применили этот метод для распознавания людей в видеопотоке. Мы загрузили тестовый видеофайл на наш Google Диск. Чтобы обучить наш скрипт работе с видеопотоком, мы использовали OpenCV, популярную библиотеку компьютерного зрения с открытым исходным кодом.

Нам не нужен весь код, который считывает и реализует модель распознавания на одном изображении. Поэтому вместо того, чтобы открывать видеофайл, мы запускаем видеопоток и перемещаем его указатель на 1000-й кадр, поскольку во вступлении к записи нет объектов для распознавания.

import cv2
...
VIDEO_STREAM = "/content/drive/My Drive/Colab Notebooks/Millery.avi"
VIDEO_STREAM_OUT = "/content/drive/My Drive/Colab Notebooks/Result.avi"
...
# initialize the video stream and pointer to output video file
vs = cv2.VideoCapture(VIDEO_STREAM)
writer = None
vs.set(cv2.CAP_PROP_POS_FRAMES, 1000);

Затем мы обрабатываем 20 000 кадров с помощью нашей модели нейронной сети. Объект OpenCV позволяет нам получать изображения по кадрам из видеофайла с помощью метода read (). Полученное изображение передается в метод model.detect (), а результаты визуализируются с помощью функции visualize.display_instances ().

Однако мы столкнулись с проблемой: функция display_instances () из репозитория Mask_RCNN отражает обнаруженные объекты на изображении, но изображение не возвращается. Мы решили упростить функцию display_instances () и заставить ее возвращать изображение с отображаемыми объектами:

def display_instances(image, boxes, masks, ids, names, scores):
"""
take the image and results and apply the mask, box, and Label
"""
n_instances = boxes.shape[ 0 ]
colors = visualize.random_colors(n_instances)
if not n_instances:
print ( 'NO INSTANCES TO DISPLAY' )
else :
assert boxes.shape[ 0 ] = = masks.shape[ - 1 ] = = ids.shape[ 0 ]
for i, color in enumerate (colors):
if not np. any (boxes[i]):
continue
y1, x1, y2, x2 = boxes[i]
label = names[ids[i]]
score = scores[i] , scores is not None else None if scores is not None else None
caption = '{} {:.2f}' . format (label, score) if score else label
mask = masks[:, :, i]
image = visualize.apply_mask(image, mask, color)
image = cv2.rectangle(image, (x1, y1), (x2, y2), color, 2 )
image = cv2.putText(
image, caption, (x1, y1), cv2.FONT_HERSHEY_COMPLEX, 0.7 , color, 2
)
return image

После обработки кадры должны быть снова связаны в новый видеофайл. Мы также можем сделать это с помощью библиотеки OpenCV. Все, что нам нужно сделать, это выделить объект VideoWriter из библиотеки OpenCV:

fourcc = cv2.VideoWriter_fourcc( * "XVID" )
writer = cv2.VideoWriter(VIDEO_STREAM_OUT, fourcc, 30 ,
(masked_frame.shape[ 1 ], masked_frame.shape[ 0 ]), True )

используя тип видео, который мы предоставили для ввода. Тип видеофайла получаем с помощью команды ffprobe :

ffprobe Result.avi

Duration: N/A, start: 0.000000, bitrate: N/A
Stream #0:0: Video: mpeg4 (Simple Profile) (XVID / 0x44495658), yuv420p, 640×272 [SAR 1:1 DAR 40:17], 30 fps, 30 tbr, 30 tbn, 30 tbc

Полученный объект можно использовать для покадровой записи: writer.write (masked_frame).

В начале скрипта нам нужно указать пути к целевым видеофайлам для обработки: VIDEO_STREAM и VIDEO_STREAM_OUT.

Вот полный сценарий, который мы разработали для распознавания видео: