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

Введение

Когда я проходил стажировку в Weeview, я впервые услышал OpenCV. С помощью OpenCV я написал код бочкообразной дисторсии, калибровки камеры и программу видеопипа. (вы можете увидеть здесь, здесь и здесь на моем GitHub) Хотя я потратил некоторое время на то, чтобы освоить это и даже быть заметным, что мой наставник совершенно не укладывался в график (такое смущение… ), в конце концов я научился использовать OpenCV и почувствовал, насколько он мощный. Вы можете интегрировать OpenCV в свой существующий проект C++ благодаря его заметной функции с высокой скоростью обработки. Более того, взглянув на его исходный код, вы можете понять как теорию каждого метода обработки изображений, так и его реализацию.

С течением времени OpenCV предоставляет множество функций, и глубокое обучение не является исключением. Начиная с версии 3.4, OpenCV постепенно добавляет функции глубокого обучения. Однако он по-прежнему не обеспечивает обучение модели глубокого обучения через свой API под названием DNN. Поэтому обычно при создании модели глубокого обучения с OpenCV существует следующий рабочий процесс:

обучить свою модель с помощью другой среды -›
загрузить обученную модель с помощью функции OpenCV, подобной readNet -›
сделать прогноз

YOLO — это хорошо известная архитектура нейронной сети для обнаружения объектов, и я очень впечатлен, что pjreddie может запрограммировать такую ​​сеть с помощью C и своей воли. Тем не менее, мы обычно конвертируем файл веса на практике, потому что наш босс говорит, что мы должны использовать определенный язык программирования. Кроме того, я слышал, что при выводе YOLO с использованием модуля OpenCV DNN намного быстрее, чем с использованием версий pjreddie или AlexeyAB (см. здесь), особенно на процессоре. Подводя итог, я пишу эту статью как запись вывода YOLO с использованием модели OpenCV DNN и провожу эксперимент по сравнению времени вывода между pjreddic, AlexeyAB и OpenCV.

Цель этой статьи

В этой статье я собираюсь:

  1. Сделайте пример обнаружения объекта fish YOLO на OpenCV (вы можете скопировать и вставить мой код по своему желанию в свою работу по обнаружению объектов).
  2. Проведите эксперимент по времени выполнения между выводами pjreddid, AlexeyAB и OpenCV YOLO.

Подготовить

  1. Клонируйте мой репозиторий отсюда.
  2. Загрузите предварительно обученные веса с мой Google Диск и поместите их в каталог yolo-fish.
  3. Создайте виртуальную среду conda и установите зависимости:
$ conda create -n fish-opencv-yolo-python python=3.6 pip 
$ conda activate fish-opencv-yolo-python
$ pip install -r requirements.txt

4. Активируйте виртуальную среду.

5. Запустите прогнозирование 七星斑.jpg с помощью этой команды: $ python yolo.py --image ./images/七星斑.jpg --yolo yolo-fish

Вы должны получить всплывающее окно, если нет никаких проблем:

Пояснения

Конечно, вы хотели бы знать, как использовать OpenCV для обнаружения объектов YOLO. В этом разделе я буду писать ключевые точки один за другим.

читать веса

OpenCV предоставляет множество функций, подобных readNet, для облегчения чтения весов, обученных другими фреймворками. В версии 4.1.1 OpenCV поддерживает формат следующих фреймворков:

  • Кафе
  • ТензорФлоу
  • Факел
  • даркнет
  • ДЛДТ (OpenVINO)
  • ОННКС

Я собираюсь использовать свою предварительно обученную модель Даркнета, поэтому выберите readNetFromDarknet(), чтобы прочитать веса Даркнета.

создать блоб (тензор)

В модуле DNN OpenCV требуется ваше входное преобразование в блоб или тензор в другой структуре нейронной сети. Чтобы создать большой двоичный объект, я использую функцию blobFromImage() для создания 4-мерного двоичного объекта, показанного ниже:

blob = cv.dnn.blobFromImage(image, 1 / 255.0, (416, 416), swapRB=True, crop=False)

В частности, некоторые параметры blobFromImage описаны ниже:

  • scalefactor: умножает каждый пиксель изображения на его значение. Я установил здесь 1 / 255.0, потому что хотел бы получить большой двоичный объект с типом CV_32F (или numpy.float32 в Python).
  • size: изменить размер изображения до определенного размера. Здесь я поставил (416, 416), потому что YOLO хочет получить этот размер.
  • Хотя моя сеть YOLO была обучена с размером (608, 608), я установил выше значение, потому что (608, 608) будет неправильно работать на OpenCV. См. раздел «Викторины» для более подробного описания.
  • swapRB=True: OpenCV сохраняет цветное изображение в формате BGR, а не в формате RGB, в то время как YOLO хочет получить изображение в формате RGB. Поэтому для этой цели я поставил True.
  • crop: обрезать изображение после изменения размера изображения. Я не хочу обрезать изображение, поэтому установил значение False.

После этой операции мы получаем 4D-блоб формата NCHW.

выполнить прямой проход через сеть YOLO

Прежде чем я сделаю прямой проход, я должен определить имена выходных слоев из моей модели YOLO следующими способами:

ln = net.getLayerNames()
ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]

После этого я могу сделать прямой проход:

net.setInput(blob)
start = time.time()
layerOutputs = net.forward(ln)
end = time.time()
# show execution time information of YOLO
print("[INFO] YOLO took {:.6f} seconds.".format(end - start)) 

немаксимальное подавление

Для обнаружения объекта мы обычно используем немаксимальное подавление, чтобы выбрать ограничивающую рамку, которая наиболее подходит для обозначения местоположения обнаруженного объекта. Хотя YOLO этого не делает, мы можем, в свою очередь, создать немаксимальное подавление:

idxs = cv.dnn.NMSBoxes(boxes, confidences, args["confidence"],
        args["threshold"])

Что вам нужно сделать, так это просто отправить ограничивающие рамки (box), достоверность (confidences), порог достоверности и порог NMS.

Сравнение времени логического вывода

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

Спецификация

Спецификация оборудования указана ниже:

  • Процессор: Core i5–3230M
  • Оперативная память: 16 ГБ

И я перечисляю спецификацию программного обеспечения здесь:

  • ОС: CentOS 7.6
  • OpenCV
  • даркнет pjreddie
  • Даркнет AlexeyAB

Вы можете найти работы pjreddie и AlexeyAB по следующей ссылке:

pjreddie: https://github.com/pjreddie/darknet

AlexeyAB: https://github.com/AlexeyAB/darknet

Здесь показаны некоторые контролируемые переменные:

  • Входное изображение: 七星斑.jpg
  • Входной размер YOLO: 608 x 608
  • достоверность: 0,25
  • порог: 0,4

Я делаю сравнительную временную таблицу в следующем:

Вы можете обнаружить, что Darknet, работающий на OpenCV, работает быстрее всего.

Вывод

В этой статье я покажу, как выполнять обнаружение объектов YOLO с пользовательскими данными с помощью OpenCV на примере изображения объекта рыбы. Я также показываю некоторые схемы при использовании обнаружения объектов YOLO с OpenCV. Наконец, я провел сравнение времени вывода и показал, что версия OpenCV работает быстрее всего.

Мелочи

Я обнаружил, что использование разрешения 416x416 в качестве входных данных даст более желаемый результат по сравнению с разрешением 608x608 в OpenCV.

Возьмем DSC_0061.JPG и 七星斑.jpg в качестве примера:

  1. Установите разрешение 608x608

2. Установите разрешение 416x416.

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

Специальная благодарность

Эта статья не появилась бы, если бы pyimagesearch не написал потрясающую статью о том, как научить вас использовать OpenCV для обнаружения объектов YOLO. С его работами вы можете ознакомиться в этой статье.