NTA

Контроль масочного режима среди определенной категории людей с помощью инструментов Computer Vision

В условиях пандемия COVID-19 регулирующие государственные органы устанавливают обязательные требования по ношению средств индивидуальной защиты сотрудниками организаций, обслуживающих клиентов.

Несоблюдение сотрудниками защитных мер по ношению масок приводит к штрафным санкциям со стороны регулятора и остановке бизнеса в связи с заболеванием сотрудников.

Методы Computer Vision позволяет эффективно контролировать соблюдение масочного режима в массовых точках обслуживания клиентов.

В предыдущей статье мы рассказывали, как с помощью асинхронных http-запросов увеличить скорость загрузки скриншотов с серверов телевизионных систем видеонаблюдения (https://newtechaudit.ru/asinhronnye-http-zaprosy/). Сегодня расскажем, как анализировать скриншоты - находить на изображении человека, классифицировать его, как сотрудника, находить лицо и классифицировать – есть на нем маска или нет.

Существующие практики решений похожих задач не учитывают следующие особенности:

· Распознавание маски только на определенной категории людей. В данном случае рассматриваются сотрудники компании, чей стиль одежды визуально отличается от клиентов этой компании.

· Работа с изображениями различного качества, иногда очень низкого.

Решение нашей задачи возможно с использованием нейронных сетей двух типов для детекции и классификации.

Мы использовали комплекс из 4-х нейронных сетей 3-х различных архитектур:

- YOLOv3 - для детекции людей на изображении,

- MTCNN - для детекции лиц,

- ResNet101- для классификации.

Классификаторы архитектуры ResNet101 дополнительно были дообучены на данных, полученных с серверов вендора Trassir. Для обучения классификатора «сотрудник»-«клиент» использовали dataset из 5000 фотографий: по 2500 сотрудников и клиентов. Для обучения классификатора «в маске»-«без маски» dataset из 400 фотографий: 200 – в масках, 200 – без масок.

В качестве loss функции взята кросс энтропия, оптимизатор – Adam с параметрами: , , , , планировщик – StepLR с параметрами: step_size = 20, gamma = 0,5. Значения функций потерь в зависимости от количества эпох приведены на рисунках ниже.

Рисунок 1 – Графики функций потерь для классификатора "сотрудник"-"клиент"

Рисунок 2 – Графики функций потерь для классификатора "маска"-"не маска"

Все приведенные выше модели запускаются скриптом (https://github.com/Vitaliy1234/mask_reco_v1), написанном на языке Python3. Код обучения также расположен по этой ссылке.

Схема работы комплекса следующая:

1. Исходные изображения подвергаются предобработке и подаются на вход YOLOv3. После отработки этой сети мы получим координаты всех обнаруженных объектов, а также разбиение этих объектов на классы. Из всех детектированных объектов нам нужны только объекты класса «человек», поэтому выбираем только изображения с людьми. Ниже показан фрагмент функции detection_loop().

def detection_loop(im_batches, CUDA, model, confidence, num_classes, nms_thresh, im_list, batch_size, classes): write = 0 for i, batch in enumerate(im_batches): # load the image start = time.time() if CUDA: batch = batch.cuda() with torch.no_grad(): prediction = model(Variable(batch), CUDA)

2. Следующий этап – классификация людей на сотрудников и клиентов. Эту задачу решает бинарный классификатор, использующий архитектуру ResNet101. На вход ему подается фрагмент исходного изображения, на котором находится человек.

def empl_cl_classifier(model_ft, out_yolo, ims_transformed, data_transforms): """ Evaluate employee-client classifier :param model_ft: employee-client classifier :param out_yolo: people detections from yolov3 :param ims_transformed: images transformed to pytorch format :param data_transforms: torch transforms for images :return result: list with relative (person is employee) yolo detections """ result = [] result_cl = 0 with torch.no_grad(): for output in out_yolo: c1 = tuple(output[1:3].int()) c2 = tuple(output[3:5].int()) img = ims_transformed[int(output[0])] # crop person from image person = img[c1[1]:c2[1], c1[0]:c2[0]] if person.shape[0] == 0 or person.shape[1] == 0: continue person_tr = data_transforms(Image.fromarray(person)).unsqueeze(0) person_tr = person_tr.cuda() start_empl_cl = time.time() output_person = model_ft(person_tr) _, preds = torch.max(output_person, 1) print('Employee/client classifier took:', time.time() - start_empl_cl, preds) if preds == 1: # if person is employee result.append(output) else: result_cl += 1 return result, result_cl

3. Дальше изображения сотрудников подаются на вход нейронной сети архитектуры MTCNN, которая ищет лицо. По результатам детекции мы получаем координаты всех обнаруженных лиц, а также соответствующие значения confidence. Фильтруем лица по confidence, чтобы отсеять неверно детектированные объекты.

def start_mtcnn(model_mtcnn, employees, ims_transformed): """ Starts mtcnn for face detection :param model_mtcnn: mtcnn model :param employees: detections from yolo with only employees :param ims_transformed: images transformed to pytorch format :return result: list with tuples (detection with employee, bounding box with face) """ result = [] with torch.no_grad(): for empl_detection in employees: c1 = tuple(empl_detection[1:3].int()) c2 = tuple(empl_detection[3:5].int()) employee = ims_transformed[int(empl_detection[0])][c1[1]:c2[1], c1[0]:c2[0]] start_time = time.time() try: result_face_detect = model_mtcnn.detect(employee) except: continue print('MTCNN took', time.time() - start_time) if result_face_detect[0] is not None: # if face was found indx = argmax(result_face_detect[1]) max_conf = result_face_detect[1][indx] b_box_max = result_face_detect[0][indx] # bbox with max confidence if max_conf >= FACE_CONFIDENCE: # filter faces through threshold result.append((empl_detection, b_box_max)) return result

4. И, наконец, изображения лиц подаются на вход второму бинарному классификатору архитектуры ResNet101, который определяет – лицо в маске или нет.

def start_mask_classifier(model_mask, empl_faces, ims_transformed, data_transforms): """ Starting mask classifier :param model_mask: :param empl_faces: :param ims_transformed: :return result: list of tuples (employee_detection, face_bounding_box) """ result_detections = [] result_b_boxes = [] with torch.no_grad(): for empl_detection, b_box_max in empl_faces: c1 = tuple(empl_detection[1:3].int()) c2 = tuple(empl_detection[3:5].int()) cur_index = int(empl_detection[0]) employee = ims_transformed[cur_index][c1[1]:c2[1], c1[0]:c2[0]] x1_face, y1_face = max(int(b_box_max[0]), 0), max(int(b_box_max[1]), 0) x2_face, y2_face = max(int(b_box_max[2]), 0), max(int(b_box_max[3]), 0) face_img = employee[y1_face:y2_face, x1_face:x2_face] face_tr = data_transforms(Image.fromarray(face_img)).unsqueeze(0) face_tr = face_tr.cuda() start = time.time() output_mask = model_mask(face_tr) print('Mask model took:', time.time() - start) _, preds_mask = torch.max(output_mask, 1) if preds_mask == 1: # if class is "no mask" result_detections.append(empl_detection) cur_list_b_boxes = [cur_index] cur_list_b_boxes.extend(b_box_max) result_b_boxes.append(cur_list_b_boxes) return result_detections, result_b_boxes

Все четыре сети были реализованы на фреймворке PyTorch. На выходе мы получаем только те изображения, где были детектированы лица сотрудников без масок. На каждом таком изображении лицо сотрудника выделяется красной рамкой с надписью «No_mask».

Весь комплекс работает на машине со следующими характеристиками:

1. Процессор: Intel Core i7-8700

2. Объем оперативной памяти: 32 ГБ

3. Видеокарта: Nvidia GeForce 1080Ti

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

1. Precision = 0,95

2. Recall = 0,43

3. F1 = 0,59

В итоге у нас получилась система, которая обрабатывает 15 скриншотов в секунду, помогая выявлять случаи нарушения масочного режима. Таким образом, не тратятся человеческие ресурсы на просмотр видео с камер наблюдения.

0
1 комментарий
Популярные
По порядку

Приделайте туда ещё пистолет. Для соблюдения законности на месте.

0
Читать все 1 комментарий
Модемы, роутеры и интернет-центры Yota можно приобрести на Avito, OZON и «СберМегамаркет»
Как шеврон стал хлястиком: бывший арт-директор «Яндекса» рассказал о создании брендинга «Яндекс.Станции Мини» Статьи редакции

Название компании на колонке «в лоб» смотрелось бы агрессивно, а сделать тканевый шильдик на практике оказалось сложно.

VELES BLOG Рассказываем как себя вести, чтобы заработать с Veles
Как я стал резидентом ОЭЗ «Технополис Москва» — опыт компании «ХайТэк»

Опытом работы на территории особой экономической зоны столицы делится генеральный директор НТЦ «ХайТэк» Алексей Алясев.

Пресс-служба ОЭЗ «Технополис Москва».
Использование YOLOv5 для задачи детекции

Ликбез по нейронным сетям

«Она похожа на соль — улучшит любое блюдо, если не переборщить»: как инженер-пианист создал гитарную педаль Big Muff Статьи редакции

Майк Мэтьюс бросил работу в IBM, чтобы дарить гитарам звучание, как у Хендрикса и The Rolling Stones, и придумал «золотой стандарт» педалей с искажением: её в своих записях использовали Pink Floyd, The White Stripes и Depeche Mode.

Майк Мэтьюс Vintage Guitar
Российско-швейцарская WayRay представила свой первый прототип электромобиля с AR-остеклением Статьи редакции

За четыре года стартап хочет подготовиться к серийному производству и получить разрешения на движение по дорогам общего пользования.

WayRay Holograktor WayRay
Аборты и эвтаназия — убийство, а геноцид с целью сделать всех счастливыми — правильно

Какие еще моральные суждения выносит искусственный интеллект?

Почему аренда самоката стоит как каршеринг и зачем отказываться от франшиз: интервью с главой Whoosh Дмитрием Чуйко Статьи редакции

До продажи бизнеса есть ещё «как минимум» два года, а пока Whoosh подумывает о запуске в Европе и учится сам собирать электросамокаты.

Сооснователь и гендиректор Whoosh Дмитрий Чуйко
null