Автор|Марсело Роваи Компилировать|ВКонтакте Источник | К науке о данных
вводить
Как описал Чжэ Цао в своей статье 2017 года, двухмерная оценка позы нескольких человек в режиме реального времени имеет решающее значение для машин, чтобы понимать людей на изображениях и видео.
Однако, что такое оценка позы
Как следует из названия, это метод, используемый для оценки положения тела человека, например, когда он стоит, сидит или лежит. Один из способов получить эту оценку — найти 18 «сочленений тела» или «Ключевых точек», как их называют в области искусственного интеллекта. На изображении ниже показана наша цель — найти эти точки на изображении:
Ключевые точки идут от точки 0 (верхняя часть шеи) вниз к суставам тела, затем обратно к голове и, наконец, к точке 17 (правое ухо).
Первой значимой работой, появившейся с использованием методов искусственного интеллекта, была DeepPose, статья 2014 года Тошева и Зегеди из Google. Предлагается метод оценки позы человека, основанный на глубоких нейронных сетях (ГНС), который сводит оценку позы человека к проблеме регрессии суставов человека на основе ГНС.
Модель состоит из серверной части AlexNet (7 слоев) и дополнительного целевого слоя, который выводит координаты 2k суставов. Важная проблема с этим подходом заключается в том, что, во-первых, модельное приложение должно обнаруживать человека (классическое обнаружение объектов). Поэтому каждое человеческое тело, обнаруженное на изображении, необходимо обрабатывать отдельно, что значительно увеличивает время обработки изображения.
Этот подход называется «сверху вниз», потому что сначала находят тело, а затем находят связанные с ним суставы.
Проблемы оценки позы
Есть несколько проблем с оценкой позы, например:
-
Каждое изображение может содержать неизвестное количество людей, которые могут появиться в любом положении или масштабе.
-
Взаимодействия между людьми могут привести к сложным пространственным нарушениям из-за контакта или суставного сочленения конечностей, что затрудняет ассоциацию суставов.
-
Сложность выполнения увеличивается с увеличением количества людей на изображении, что затрудняет работу в режиме реального времени.
Для решения этих проблем более интересным подходом является OpenPose, который был представлен в 2016 году Чжэ Цао и его коллегами из Института робототехники Университета Карнеги-Меллона.
OpenPose
Метод, предложенный OpenPose, использует непараметрическое представление, называемое Partial Affinity Fields (PAF), для «соединения» каждого сустава тела на изображении, связывая их с человеком.
Другими словами, OpenPose, в отличие от DeepPose, сначала находит все суставы на изображении, а затем ищет «вверху» тело, которое, скорее всего, содержит этот сустав, без использования детектора, который обнаруживает людей (подход «снизу вверх»). . OpenPose может находить ключевые точки на изображении независимо от того, сколько людей находится на изображении. Изображение ниже, полученное из презентации OpenPose на семинаре ILSVRC и COCO 2016, дает нам представление о процессе.
На рисунке ниже показана структура двух многоэтапных моделей CNN, используемых для обучения. Во-первых, сеть прямой связи одновременно прогнозирует набор двумерных карт достоверности для расположения частей тела (аннотации ключевых точек из (набор данных/COCO/аннотации/) и набор двумерных полей частичного сродства (L).
После каждого этапа прогнозы двух ветвей, а также особенности изображения объединяются на следующем этапе. Наконец, жадные рассуждения используются для анализа карты достоверности и области сходства, а также для вывода 2D-ключевых точек всех людей на изображении.
Мы вернемся к некоторым из этих концепций для уточнения по мере продвижения проекта. Тем не менее, настоятельно рекомендуется следить за презентациями семинара OpenPose ILSVRC и COCO 2016 года (image-net.org/challenges/…Видеозапись 2017 года (woohoo.YouTube.com/watch?V=o GQ…
TensorFlow 2 OpenPose (tf-pose-estimation)
Первоначальный OpenPose был разработан с использованием предварительно обученной сети VGG на основе модели и инфраструктуры Caffe. Тем не менее, мы будем следить за реализацией TensorFlow Ильду Кима, подробно описывая его оценку tf-pose.
Ссылка на гитхаб:OO net/typhoon на GitHub.com/IL…
Что такое оценка tf-pose?
tf-pose-estimation — это алгоритм «Openpose», реализованный с использованием Tensorflow. Он также предлагает несколько вариантов с некоторыми изменениями в структуре сети для обработки в реальном времени на процессорах или встроенных устройствах с низким энергопотреблением.
На странице GitHub для оценки tf-pose показаны эксперименты с несколькими разными моделями, такими как:
- cmu: веса предварительно обученной сети VGG на основе модели, описанные в исходной статье, представлены в формате Caffe, который преобразуется и используется в TensorFlow.
- dsconv: Та же архитектура, что и в версии CMU, за исключением разделяемой по глубине свертки мобильной сети.
- mobilenet: На основе документа Mobilenet V1 в качестве слоев выделения признаков используются 12 сверточных слоев.
- mobilenet v2: Похож на мобильную сеть, но использует ее улучшенную версию.
Исследование в этой статье проводится на мобильной сети V1 («mobilenet_thin»), которая имеет умеренную производительность с точки зрения вычислительного бюджета и задержки:
Часть 1. Установка оценки tf-pose
Мы ссылаемся на статью Гунджана Сета «Оценка позы с помощью TensorFlow 2.0» (medium.com/@sethi2409…
- Заходим в терминал и создаем рабочую директорию (например, "Pose_Estimation") и перемещаемся туда:
mkdir Pose_Estimation
cd Pose_Estimation
- Создайте виртуальную среду (например, Tf2_Py37)
conda create --name Tf2_Py37 python=3.7.6 -y
conda activate Tf2_Py37
- Установить ТФ2
pip install --upgrade pip
pip install tensorflow
- Установите базовые пакеты, которые будут использоваться во время разработки:
conda install -c anaconda numpy
conda install -c conda-forge matplotlib
conda install -c conda-forge opencv
- Скачать оценку tf-pose:
git clone https://github.com/gsethi2409/tf-pose-estimation.git
- Перейдите в папку tf-pose-estimation и установите требования.
cd tf-pose-estimation/
pip install -r requirements.txt
На следующем этапе устанавливается SWIG — компилятор интерфейса, который связывает программы, написанные на C и C++, с такими языками сценариев, как Python. Он работает, беря объявления, найденные в заголовочных файлах C/C++, и используя их для генерации кода-оболочки, который необходим языку сценариев для доступа к базовому коду C/C++.
conda install swig
- Используя SWIG, создайте библиотеку C++ для постобработки.
cd tf_pose/pafprocess
swig -python -c++ pafprocess.i && python3 setup.py build_ext --inplace
- Теперь установите библиотеку tf-slim, облегченную библиотеку для определения, обучения и оценки сложных моделей в TensorFlow.
pip install git+https://github.com/adrianc-a/tf-slim.git@remove_contrib
это все! Теперь необходим быстрый тест. Вернитесь в домашний каталог tf-pose-estimation.
Если вы следуете порядку, вы должны находиться внутри tf_pose/pafprocess. В противном случае используйте соответствующую команду для изменения каталога.
cd ../..
В каталоге tf-pose-estimation есть скрипт python.run.py, запустим его со следующими параметрами:
-
model=mobilenet_thin
-
resize=432x368 (размер изображения при препроцессинге)
-
image=./images/ski.jpg (пример изображения в каталоге изображений)
python run.py --model=mobilenet_thin --resize=432x368 --image=./images/ski.jpg
Обратите внимание, что в течение нескольких секунд ничего не произойдет, но примерно через минуту терминал должен отобразить что-то похожее на изображение ниже:
Но, что более важно, изображение появится в отдельном окне OpenCV:
Очень хороший! Эти фотографии доказывают, что все правильно установлено и работает хорошо! Подробности мы рассмотрим в следующем разделе.
Однако, чтобы быстро объяснить, что означают эти четыре изображения, скажем, что верхний левый угол («Результат») — это скелет определения позы, нарисованный с исходным изображением (в данном случае — ski.jpg) в качестве фона. Верхнее правое изображение представляет собой «тепловую карту», показывающую «обнаруженные компоненты» (S), а оба нижних изображения показывают ассоциации компонентов (L). «Результат» — соединить S и L.
Следующий тест — живое видео:
Если на компьютере установлена только одна камера, используйте: camera=0
python run_webcam.py --model=mobilenet_thin --resize=432x368 --camera=1
Если все пойдет хорошо, появится окно с реальным видео, как на скриншоте ниже:
Часть 2. Глубокое погружение в оценку позы на изображениях
В этом разделе мы более подробно рассмотрим нашу реализацию оценки позы TensorFlow. Рекомендуется следовать этой статье и попытаться воспроизвести блокнот Jupyter: 10_Pose_Estimation_Images, который можно загрузить из проекта GitHub:GitHub.com/MJ RO V Love/TF2…
Для справки, этот проект находится на MacPro (2.9Hhz Quad-Core i7 16GB 2133Mhz RAM) разработан на .
библиотека импорта
import sys
import time
import logging
import numpy as np
import matplotlib.pyplot as plt
import cv2
from tf_pose import common
from tf_pose.estimator import TfPoseEstimator
from tf_pose.networks import get_graph_path, model_wh
Определение модели и создание оценщика TfPose
Можно использовать модели, расположенные в подкаталоге model/graph, например mobilenet_v2_large или cmu (предварительно обученная модель VGG).
Для cmu файлы *.pb не загружаются при установке, так как они большие. Чтобы использовать его, запустите bash-скрипт download.sh, расположенный в подкаталоге /cmu.
В этом проекте используется mobilenet_thin (MobilenetV1), учитывая, что все используемые изображения должны быть уменьшены до 432x368.
параметр:
model='mobilenet_thin'
resize='432x368'
w, h = model_wh(resize)
Создайте оценщик:
e = TfPoseEstimator(get_graph_path(model), target_size=(w, h))
Для простоты анализа давайте загрузим простое изображение человека. OpenCV используется для чтения изображения. Изображения хранятся в формате RGB, но внутри OpenCV работает с BGR. Нет проблем с отображением изображения с помощью OpenCV, поскольку оно будет преобразовано из BGR в RGB перед отображением изображения в определенном окне (как показано в ski.jpg в предыдущем разделе).
Как только изображение будет напечатано на устройстве Jupyter, вместо OpenCV будет использоваться Matplotlib. Поэтому перед отображением изображение нужно преобразовать вот так:
image_path = ‘./images/human.png’
image = cv2.imread(image_path)
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(image)
plt.grid();
Обратите внимание, что форма этого изображения 567x567. Когда OpenCV считывает изображение, он автоматически преобразует его в массив, где каждое значение находится в диапазоне от 0 до 255, где 0 означает «белый», а 255 означает «черный».
Когда изображение представляет собой массив, его размер легко проверить с помощью формы:
image.shape
Результатом будет (567567, 3), где форма (ширина, высота, цветовой канал).
Хотя с помощью OpenCV можно читать изображения, мы будем использовать функцию read_imgfile(image_path) из библиотеки tf_pose.common, чтобы предотвратить любые проблемы с цветовыми каналами.
image = common.read_imgfile(image_path, None, None)
Когда у нас есть изображения в виде массива, мы можем применить вывод метода к оценщику (оценщику, e), взяв массив изображений в качестве входных данных.
humans = e.inference(image, resize_to_default=(w > 0 and h > 0), upsample_size=4.0)
Выполнив указанную выше команду, давайте изучим массив e.heatmap. Форма массива (184, 216, 19), где 184 — h/2, 216 — w/2, 19 связано с конкретным пикселем, принадлежащим одному из 18 суставов (от 0 до 17) + 1 (18). :none) связанные с вероятностью. Например, при проверке верхнего левого пикселя должно появиться «нет»:
Последнее значение этого массива может быть проверено
Это самое большое значение, понятно, что с вероятностью 99,6% этот пиксель не принадлежит ни к одному из 18 суставов.
Попробуем найти основание шеи (середину между плечами). Он находится в середине исходного изображения примерно на 20% ширины (0,5*w=108) и высоты, начиная сверху/снизу (0,2*h=37). Итак, давайте проверим этот конкретный пиксель:
Легко понять, что максимальное значение в позиции 1 равно 0,7059... (или путем вычисления e.heatMat[37][108].max() ), что означает, что конкретный пиксель имеет 70%-й шанс оказаться " шея". На изображении ниже показаны все 18 клавиш COCO (или «суставы тела»), показывая, что «1» соответствует «нижней части грифа».
Для каждого пикселя можно нарисовать цвет, представляющий его максимальное значение. Таким образом, волшебно появляется тепловая карта, показывающая ключевые точки:
max_prob = np.amax(e.heatMat[:, :, :-1], axis=2)
plt.imshow(max_prob)
plt.grid();
Теперь мы рисуем ключевые точки на скорректированном исходном изображении:
plt.figure(figsize=(15,8))
bgimg = cv2.cvtColor(image.astype(np.uint8), cv2.COLOR_BGR2RGB)
bgimg = cv2.resize(bgimg, (e.heatMat.shape[1], e.heatMat.shape[0]), interpolation=cv2.INTER_AREA)
plt.imshow(bgimg, alpha=0.5)
plt.imshow(max_prob, alpha=0.5)
plt.colorbar()
plt.grid();
Таким образом, на изображении можно увидеть ключевые точки, потому что значение, отображаемое на цветовой полосе, означает: чем желтый цвет темнее, тем выше вероятность.
Чтобы получить L, наиболее вероятные соединения (или «кости») между ключевыми точками (или «суставами»), мы можем использовать результирующий массив e.pafMat. Его форма (184, 216, 38), где 38 (2x19) относится к вероятности того, что этот пиксель является частью горизонтального (x) или вертикального (y) соединения с одним из 18 конкретных суставов + ни одного.
Функция для рисования приведенного выше графика есть в Блокноте.
Используйте метод draw_human для рисования костей
Используя результат метода e.inference() для передачи списка human, можно нарисовать скелет с помощью метода draw_human:
image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False)
Результат выглядит следующим образом:
Вы можете просто нарисовать скелет, если хотите, вот так (давайте повторно запустим весь код для проверки):
image = common.read_imgfile(image_path, None, None)
humans = e.inference(image, resize_to_default=(w > 0 and h > 0), upsample_size=4.0)
black_background = np.zeros(image.shape)
skeleton = TfPoseEstimator.draw_humans(black_background, humans, imgcopy=False)
plt.figure(figsize=(15,8))
plt.imshow(skeleton);
plt.grid();
plt.axis(‘off’);
Получить координаты ключевой точки (соединения)
Оценка позы может использоваться в ряде приложений, таких как робототехника, игры или медицина. Для этого может быть интересно получить физические координаты характерной точки из изображения для использования другими приложениями.
Просмотр созданного e.inference()humanСписок, который можно проверить как список с одним элементом, строкой. В этой строке каждая ключевая точка отображается со своими относительными координатами и соответствующей вероятностью. Например, для используемого в данный момент портрета имеем:
Например:
BodyPart:0-(0.49, 0.09) score=0.79
BodyPart:1-(0.49, 0.20) score=0.75
...
BodyPart:17-(0.53, 0.09) score=0.73
Из этого списка мы можем извлечь массив (размером 18), содержащий фактические координаты относительно формы исходного изображения:
keypoints = str(str(str(humans[0]).split('BodyPart:')[1:]).split('-')).split(' score=')
keypts_array = np.array(keypoints_list)
keypts_array = keypts_array*(image.shape[1],image.shape[0])
keypts_array = keypts_array.astype(int)
Нарисуем этот массив на исходном изображении (ключевым моментом является индекс массива). Результат выглядит следующим образом:
plt.figure(figsize=(10,10))
plt.axis([0, image.shape[1], 0, image.shape[0]])
plt.scatter(*zip(*keypts_array), s=200, color='orange', alpha=0.6)
img = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.imshow(img)
ax=plt.gca()
ax.set_ylim(ax.get_ylim()[::-1])
ax.xaxis.tick_top()
plt.grid();
for i, txt in enumerate(keypts_array):
ax.annotate(i, (keypts_array[i][0]-5, keypts_array[i][1]+5)
Создайте функции для быстрого воспроизведения исследований общих изображений:
Блокнот показывает весь код, разработанный на данный момент, «инкапсулированный» в виде функций. Например, давайте посмотрим на другое изображение:
image_path = '../images/einstein_oxford.jpg'
img, hum = get_human_pose(image_path)
keypoints = show_keypoints(img, hum, color='orange')
img, hum = get_human_pose(image_path, showBG=False)
keypoints = show_keypoints(img, hum, color='white', showBG=False)
изображение нескольких человек
До сих пор изучались только изображения, содержащие одного человека. Как только алгоритм будет разработан для одновременного захвата всех суставов (S) и PAF (L) с изображения, мы найдем наиболее вероятные соединения для простоты. Таким образом, код для получения результата тот же; например, только если мы получим результат («человек»), размер списка будет соответствовать количеству людей на изображении.
Например, давайте используем изображение с пятью людьми:
image_path = './images/ski.jpg'
img, hum = get_human_pose(image_path)
plot_img(img, axis=False)
Алгоритм находит, что все S и L связаны с этими 5 людьми. Получилось здорово!
Все, от чтения пути к изображению до отрисовки результата, занимает менее 0,5 секунды, независимо от количества людей, найденных на изображении.
Усложним, посмотрим на картину людей, танцующих вместе более «смешанно»:
image_path = '../images/figure-836178_1920.jpg
img, hum = get_human_pose(image_path)
plot_img(img, axis=False)
Результаты тоже кажутся неплохими. Мы рисуем только ключевые точки, каждая своим цветом:
plt.figure(figsize=(10,10))
plt.axis([0, img.shape[1], 0, img.shape[0]])
plt.scatter(*zip(*keypoints_1), s=200, color='green', alpha=0.6)
plt.scatter(*zip(*keypoints_2), s=200, color='yellow', alpha=0.6)
ax=plt.gca()
ax.set_ylim(ax.get_ylim()[::-1])
ax.xaxis.tick_top()
plt.title('Keypoints of all humans detected\n')
plt.grid();
Часть 3: Оценка позы в видео и живых камерах
Процесс получения оценок позы в видео такой же, как и в случае с изображениями, потому что видео можно просматривать как серию изображений (кадров). Рекомендуется следовать этому разделу и попытаться скопировать Jupyter Notebook:20_Pose_Estimation_Video:GitHub.com/MJ RO V Love/TF2…
OpenCV отлично справляется с видео.
Итак, давайте возьмем видео .mp4 и захватим его кадры с помощью OpenCV:
video_path = '../videos/dance.mp4
cap = cv2.VideoCapture(video_path)
Теперь давайте создадим цикл для захвата каждого кадра. Имея этот кадр, мы применим e.inference(), а затем отрисуем скелет на основе результата, точно так же, как мы сделали это с изображением. Также включен код в конце для остановки видео при нажатии клавиши (например, "q").
Вот необходимый код:
fps_time = 0
while True:
ret_val, image = cap.read()
humans = e.inference(image,
resize_to_default=(w > 0 and h > 0),
upsample_size=4.0)
if not showBG:
image = np.zeros(image.shape)
image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False)
cv2.putText(image, "FPS: %f" % (1.0 / (time.time() - fps_time)), (10, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow('tf-pose-estimation result', image)
fps_time = time.time()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
Результат хороший, но немного медленный. Первоначально фильм будет работать со скоростью 30 кадров в секунду, а в «медленной камере» - со скоростью около 3 кадров в секунду.
Тест с живой камерой
Рекомендуется следовать этому разделу и попытаться скопировать блокнот Jupyter: 30_Pose_Estimation_Camera(GitHub.com/MJ RO V Love/TF2…
Код, необходимый для запуска живой камеры, почти такой же, как код, используемый для видео, за исключением того, что метод OpenCV videoCapture() получает в качестве входного параметра целое число, представляющее реальную используемую камеру. Например, используйте «0» для внутренней камеры и «1» для внешней камеры. Кроме того, камера должна быть настроена на захват кадра «432x368», используемого моделью.
Инициализация параметра:
camera = 1
resize = '432x368' # 处理图像之前调整图像大小
resize_out_ratio = 4.0 # 在热图进行后期处理之前调整其大小
model = 'mobilenet_thin'
show_process = False
tensorrt = False # for tensorrt process
cam = cv2.VideoCapture(camera)
cam.set(3, w)
cam.set(4, h)
Циклическая часть кода должна быть очень похожа на ту, что используется в видео:
while True:
ret_val, image = cam.read()
humans = e.inference(image,
resize_to_default=(w > 0 and h > 0),
upsample_size=resize_out_ratio)
image = TfPoseEstimator.draw_humans(image, humans, imgcopy=False)
cv2.putText(image, "FPS: %f" % (1.0 / (time.time() - fps_time)), (10, 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
cv2.imshow('tf-pose-estimation result', image)
fps_time = time.time()
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cam.release()
cv2.destroyAllWindows()
Точно так же стандартный захват видео со скоростью 30 кадров в секунду снижается примерно до 10% при использовании алгоритма.
Вот полное видео для лучшего взгляда на отставание. Тем не менее, результат очень хороший!
видео:youtu.be/Ha0fx1M3-B4
в заключении
Как всегда, я надеюсь, что этот пост вдохновит других найти свой путь в этом удивительном мире ИИ!
Весь код, используемый в этой статье, доступен для скачивания в проекте GitHub:GitHub.com/MJ RO V Love/TF2…
Оригинальная ссылка:к data science.com/realtime-wood…
Добро пожаловать на сайт блога Panchuang AI:panchuang.net/
sklearn машинное обучение китайские официальные документы:sklearn123.com/
Добро пожаловать на станцию сводки ресурсов блога Panchuang:docs.panchuang.net/