Подход на основе ИИ к решению «проблемы» физического дистанцирования

По мере того, как страны начинают вынашивать идею ослабления норм изоляции, поддержание физического расстояния более 5 футов или выше между людьми, которые наконец выходят на улицу, может сыграть решающую роль в сдерживании распространения Covid-19.

Меня впервые познакомила с этой идеей (Coldewey, 2020) компания по разработке программного обеспечения в Сан-Франциско, Калифорния, Zensors. Эта программа отслеживает и отслеживает толпу в режиме реального времени с помощью видеозаписи с камер видеонаблюдения, высматривая людей или группы, приближающиеся друг к другу менее чем на 5–6 футов. Такие группы обведены красной рамкой, чтобы информировать об этом контролирующие органы.

Человек, постоянно наблюдающий за камерами безопасности, чтобы определить красные блоки для нарушения, может звучать как пустая трата ценных человеческих ресурсов. Таким образом, я интегрировал в программу функцию рассылки, которая мгновенно информирует власти о любых нарушениях дистанцирования, как только обнаруживает их. Определение нарушения может быть установлено в соответствии с критериями, установленными местными властями, которые может варьироваться от 2 человек, идущих вместе, до собрания более 20 человек. Ниже приведен код и объяснение. Он был скомпилирован в Google Collab со средой выполнения GPU.

import time
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email import encoders
from google.colab.patches import cv2_imshow
from google.colab import drive
import pandas as pd
import cv2
import math
import numpy as np
drive.mount(“/GD”)

Я решил использовать очень простой классификатор, а именно каскадные классификаторы Хаара для обнаружения всего тела, который является предварительно обученным классификатором, разработанным (Paul Viola, 2001). Если вы хотите узнать больше о модуле обнаружения на этом классификаторе, вы можете прочитать это здесь. Это доступно в библиотеке OpenCV. Недавние разработки привели к созданию лучших и более быстрых классификаторов, таких как более быстрые R-CNNS и YOLO, которые я попытаюсь использовать в будущих версиях для улучшения этой модели.

person_clf = cv2.CascadeClassifier(‘/GD/MyDrive/dataset/haarcascade_fullbody.xml')
# Initiate video capture for video file
cap = cv2.VideoCapture(‘/GD/My Drive/dataset/mall_walking.avi’)
writer = None
OUTPUT=’/GD/My Drive/dataset/output_’+str(YOUROUTPUTFILENAMEHERE)

Здесь экземпляр классификатора был загружен в person_clf, и был установлен выходной каталог для анализируемого видео с отметками нарушений. cv2.VideoCapture используется для загрузки нашего тестового видео и является встроенной вызываемой функцией объекта cv2.

def center(c):
  x_start=d[‘box’+str(c)+’x’]
  y_start=d[‘box’+str(c)+’y’]
  x_end=d[‘box’+str(c)+’x+w’]
  y_end=d[‘box’+str(c)+’y+h’]
  Point=int((x_start+x_end)/2), int((y_start+y_end)/2)
  return Point
def mailer(pic,mail):
  path=”/GD/My Drive/dataset/”+pic
  from = “[YOURMAILHERE]”
  to = "[TARGETMAILHERE]"
  message = MIMEMultipart()
  message[‘From’] = from
  message[‘To’] = to
  message[‘Subject’] = “Violation notification”
  body = “Dear user, pfa for instances of violation of social    distancing”
  msg.attach(MIMEText(body, ‘plain’))
  filename = pic
  attachment = open(path, “rb”)
  p = MIMEBase(‘application’, ‘octet-stream’)
  p.set_payload((attachment).read())
  # encode into base64
  encoders.encode_base64(p)
  p.add_header(‘Content-Disposition’, “attachment; filename= %s” %  filename)
  msg.attach(p)
  s = smtplib.SMTP(‘smtp.gmail.com’, 587)
  s.starttls()
  s.login(from, “YOURPASSWORDHERE”)
  text = msg.as_string()
  s.sendmail(from, to, text)
  s.quit()

Создание функций для вашего проекта — это хороший способ помочь в переносе обучения при выполнении аналогичной работы. Таким образом, я сделал здесь две базовые функции: одну для поиска центров между двумя точками, а другую для отправки почтовых программ цели с вложениями. Ниже я подробно объясню функцию центра. Функция рассыльщика берет имя изображения, которое хранится на моем диске Google, с моментом нарушения, прикрепляет его к письму с телом сообщения и отправляет его адресату. Я нашел эту статью здесь действительно информативной и использовал ее, чтобы включить это.

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

Объяснение кода

i=1
contn_frame_with_detection=0
skipped_frames=0
while cap.isOpened():

Мы вызываем экземпляр шапки, в котором хранится наше входное видео, и открываем его, чтобы мы могли обрабатывать один кадр за раз. Это наш первый цикл while, поэтому весь код будет внутри него. Также начинаем 3 счетчика. «I» для подсчета обрабатываемых кадров, «contn_frame_with_detection» для сохранения количества непрерывных кадров, в которых было обнаружено нарушение, и «skiped_frames» для подсчета кадров между обнаруженными кадрами, в которых не было обнаружено нарушений. Идея пропущенных кадров будет обсуждаться позже.

frame_violator=0
l=[]
d={}
person_id=0
ret,frame = cap.read()
if not ret:
  break

Здесь инициируется еще один счетчик «frame_violator» для подсчета количества обнаруженных нарушений в каждом кадре. Некоторые власти могут захотеть оставить его высоким, если им нужно обнаруживать только большие собрания и игнорировать 2,3 человека, идущих вместе. person_id устанавливается равным 1 в ожидании обнаружения первого человека в первом кадре. ‘cap.read()’ помогает нам прочитать кадр и сохранить его для дальнейшей обработки. Он также получает указание прерываться, когда кадр заканчивается.

frame = cv2.resize(frame, None,fx=0.95, fy=0.95, interpolation = cv2.INTER_LANCZOS4)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
persons = person_clf.detectMultiScale(gray, 1.02, 5)

Сначала нам нужно изменить размер кадра с помощью cv2.resize() примерно до 60%, чтобы вычисления можно было выполнять в реальном времени без ущерба для скорости. Если у вас более быстрые процессоры, чем у Google Collab Gpu, вы можете оставить его выше. cv2.INTER_LANCZOS4 обычно считается лучшим методом интерполяции, но другие методы, такие как INTER_LINEAR, INTER_AREA, также могут использоваться в зависимости от повышения или понижения дискретизации изображения. Метод COLOR_BGR2GRAY используется для преобразования изображения BGR (именно так OpenCV читает изображения), имеющего 3 канала, в оттенки серого, имеющего только 1 канал. Как можно видеть, при выравнивании слоев свертки вычисления выполняются намного ниже в оттенках серого без потери большого количества информации, и, следовательно, их легче обрабатывать машине. Следовательно, мы используем метод detectMutiScale cv2 для обнаружения людей в данном кадре из серого изображения. Следует отметить, что это возвращает начальную и конечную координаты диагонали прямоугольника, внутри которого можно найти обнаруженного человека. Мы сохраняем эти координаты внутри переменной person, чтобы позже перебирать их одну за другой.

for (x,y,w,h) in persons:
  d[‘box’+str(person_id)+’x’]=x
  d[‘box’+str(person_id)+’y’]=y
  d[‘box’+str(person_id)+’x+w’]=x+w
  d[‘box’+str(person_id)+’y+h’]=y+h
  l.append(center(int(person_id)))
  if person_id>0:
    s=0
    feed_detected=0
    for mid in l[:-1]:
      dist = math.sqrt((mid[0] — center(int(person_id))    [0])**2 + (mid[1] — center(int(person_id))[1])**2)
      if dist<=40:
        cv2.rectangle(frame, (d[‘box’+str(s)+’x’], d[‘box’+str(s)+’y’]), (d[‘box’+str(s)+’x+w’], d[‘box’+str(s)+’y+h’]), (0, 0,255), 2)
        cv2.line(frame,(int(mid[0]),int(mid[1])),(center(int(person_id))[0],center(int(person_id))[1]),(0,0,255),(2))
        feed_detected+=1
        frame_violator+=1
        s+=1
     if feed_detected>0:
        cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 0, 255), 2)
   person_id+=1

Приведенный выше код формирует логическое ядро ​​этого алгоритма. Сначала мы начинаем перебирать каждого человека индивидуально(для цикла A)и сохраняем координаты прямоугольника в словаре python, названном в формате ['box-person_id-x']: значение. Затем мы вызываем нашу функцию center, чтобы найти центр масс этого человека и сохранить его в списке. Функция center принимает идентификатор person_id, центр масс которого необходимо вычислить, извлекает его данные из словаря начальной и конечной точек и вычисляет координату центра. Теперь в соответствии с нашей иерархией инициализируется второй цикл(для цикла B), когда person_id в кадре больше 0 (фактически означает более двух человек), его расстояние от каждого из предыдущих центр масс обнаруженного человека вычисляется по простой формуле евклидова расстояния. Если обнаружено нарушение, значение параметра feed_detector увеличивается на единицу, указывая на то, что входящий фид имеет нарушение. Обнаруженные нарушения обводятся красной рамкой, а cv2.rectangle сохраняет размер цвета (0,0,255), что указывает на красный цвет. для формата BGR, который используется cv2.

if frame_violator>0 and skipped_frames<4:
  contn_frame_with_detection+=1
  skipped_frames=0
else:
  skipped_frames+=1
if skipped_frames>=4:
  contn_frame_with_detection=0
  skipped_frames=0
i+=1

Счетчик пропущенных кадров введен для учета ложных отрицательных результатов нашей модели. Между двумя обнаруженными кадрами нарушения будет много кадров, где классификатор HAAR может быть не в состоянии даже обнаружить всех людей. Это приведет к ложной идентификации кадра как отсутствия нарушения. Таким образом, когда мы видим количество непрерывных кадров, в которых было обнаружено нарушение, мы также должны видеть, удерживаются ли пропущенные кадры ниже определенного числа. Если skipped_frame больше, чем, скажем, 5, это может означать, что кадры, в которых ранее происходило нарушение, на самом деле могли быть просто ложными срабатываниями, и мы должны снова, таким образом, установить для Continuous_frame_counter значение 0, а для skipped_frames — 0, чтобы снова начать подсчет.

if contn_frame_with_detection>25:
  contn_frame_with_detection=0
  skipped_frames=0
  name=”pic”+str(i)+”.jpg”
  cv2.imwrite(‘/GD/My Drive/dataset/’+name,frame)
  mailer(name)

Чтобы закрепить обнаружение как истинное срабатывание, мы рассматриваем серьезное нарушение расстояния только тогда, когда Continuous_frame_counter превышает 25 (или выше, в зависимости от потребностей пользователя).

мы делаем снимок в этот момент, вызывая функцию cv2.imwrite и вызывая нашу предопределенную функцию рассылки, чтобы передать имя изображения jpg. Таким образом, эта функция почтовой программы мгновенно отправляет письмо целевому пользователю, информируя его о ситуации.

if writer is None:
   vid_write= cv2.VideoWriter_fourcc(*”XVID”)
   writer = cv2.VideoWriter(OUTPUT, vid_write, 35,(frame.shape[1],    frame.shape[0]), True)
writer.write(frame)

Наконец, мы создаем экземпляр cv2.VideoWriter и сохраняем наш видеофайл в формате XviD, по одному кадру за раз.

#this will outside main while loop
writer.release()
cap.release()
cv2.destroyAllWindows()

После достижения конца кадров мы отпускаем средство записи, закрываем и уничтожаем все окна с помощью cv2.destroyAllWindows(), чтобы компьютер не зависал. Ниже приведен пример вывода программы.

Итак, это довольно много циклов, чтобы понять их за один день. Я пытался создать каждую функцию с нуля и реализовать все это с помощью логики, таким образом, эти сложные циклы. Я буду публиковать информацию о том, как развернуть это в Интернете, используя, возможно, экземпляр EC2 Azure ml. Надеюсь, вам понравилась интуиция, стоящая за программой, и вы смогли оценить различные счетчики и циклы, использованные для ее создания. Любой, у кого есть какие-либо идеи, чтобы, возможно, добавить какую-то функцию в эту программу или ускорить ее работу, определенно может обратиться ко мне. До тех пор, живите долго и с наукой о данных.

ИСТОЧНИКИ

Колдеви, Д. (2020, апрель). https://techcrunch.com/activity-monitoring-startup-zensors-repurposes-its-tech-to-help-coronavirus-response. Получено с сайта Techcrunch: https://techcrunch. com/2020/04/02/активность-мониторинг-запуск-zensors-перепрофилирование-его-технология-помощь-коронавирус-ответ/

Джонс, PV (2001). opencv. Получено с Github: https://github.com/opencv/opencv/tree/master/data/haarcascades

Пол Виола, MJ (2001). Быстрое обнаружение объектов с помощью расширенного каскада простых функций. www.cs.cmu.edu.