OpenCV реализует обнаружение лиц на основе остаточной сети

машинное обучение алгоритм

OpenCV реализует обнаружение лиц на основе остаточной сети
Версия OpenCV3.3 впервые представила модуль Deep Neural Network (DNN) в официальной версии выпуска.Модуль DNN в последней версии OpenCV3.4 выпустил две нирваны, одна из которых поддерживает более быстрое обнаружение объектов R-CNN, что быстрее, чем SSD.По сравнению с YOLO, эти модели имеют более высокую точность обнаружения и возможности обнаружения мелких объектов.Другой является поддержка обнаружения лиц на основе модели SSD + Resnet.Хотя скорость не может достичь производительности каскадного детектора HAAR в реальном времени, точность и модель Способность к обобщению можно назвать алгоритмом обнаружения лиц метода каскадного детектора HAAR. Как разработчик OpenCV, которому нужна функция обнаружения лиц, есть более надежный выбор.Здесь мы сначала кратко представим, что такое остаточная сеть, а затем продемонстрируем ее модель обнаружения лиц, основанную на обнаружении лиц камерой в реальном времени в OpenCV.
Один: Остаточная сеть (Resnet)
Исходная сеть CNN LeNet и AlexNet имеет относительно мало сверточных слоев.VGG достигает значительного увеличения глубины сети за счет небольшого ядра свертки, но когда количество слоев чрезмерно увеличивается, обнаруживается, что как ошибки обучения, так и ошибки тестирования увеличиваются. , как показано ниже:
OpenCV基于残差网络实现人脸检测

Сначала люди думали, что это вызвано исчезновением градиента или взрывом градиента, но благодаря всем усилиям это не проблема переобучения, а явление затухания сети, поэтому в ответ на эту ситуацию команда MSRA He Kaiming предложила метод. Идея новой сетевой модели - Остаточные сети заключается в использовании остаточной структуры для обучения сети Остаточная структура выглядит следующим образом:
OpenCV基于残差网络实现人脸检测

Автор считает, что F(x) = H(x)-x, поэтому получается тождественное отображение, такое как H(x) = F(x) + x, а затем автор устанавливает 34-слойную простую сеть и 34-слойную сеть. -слойная остаточная сеть в качестве сравнения. Крайняя левая сеть VGG-19 используется в качестве эталона, и вся структура сети показана следующим образом:
--- Картинка слишком большая! ! !
После того, как модель была создана, автор провел обучение и тестирование на различных наборах данных и заметил, что эффект остаточной сети был значительно лучше, чем у простой 34-слойной сети, и обнаружил, что чем глубже слой сети, основанный на остаточная структура, тем лучше эффект Ну, 34-слойная обычная сеть имеет очевидное явление затухания по сравнению с 18-слойной простой сетью. Результаты сравнительного обучения следующие:
OpenCV基于残差网络实现人脸检测

До появления остаточной сети немногие сети имели более 100 слоев, но остаточная сеть могла достигать тысяч слоев.Нет никаких сомнений в том, что команда Хэ Кайминга также использовала модель остаточной сети в конкурсе классификации изображений ImageNet в 2015 году. чемпионат с использованием 152-слойной остаточной сети. Остаточная сетевая модель распознавания лиц в OpenCV основана на SSD, поэтому скорость по-прежнему довольно высока, а эффект особенно хорош. Не так много глупостей, позвольте мне посмотреть, как использовать его для обнаружения лиц в OpenCV.
Второе: реализация кода распознавания лиц
Модель генерируется на основе обучения сети Caffe, поэтому первое, что нужно сделать перед тем, как приступить к написанию программы, это скачать файл модели и файл описания, я уже скачал это, так что вам не нужно переходить на мой адрес github. файл модели
GitHub.com/gloomyfish1…
Скачав модель, поместите ее в локальную папку, после чего можно приступать к программированию.
Сначала нужно загрузить модель в сеть:

    String modelDesc = "D:/vcprojects/images/dnn/face/deploy.prototxt";
    String modelBinary = "D:/vcprojects/images/dnn/face/res10_300x300_ssd_iter_140000.caffemodel";
    // 初始化网络
    dnn::Net net = readNetFromCaffe(modelDesc, modelBinary);
    if (net.empty())
    {
        printf("could not load net...\n");
        return -1;
    }

Затем, чтобы открыть локальную камеру или видеофайл, используйте объект VideoCapture, код выглядит следующим образом:

// 打开摄像头
    VideoCapture capture(0);
    if (!capture.isOpened()) {
        printf("could not load camera...\n");
        return -1;
    }

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

        // 输入数据调整
        Mat inputBlob = blobFromImage(frame, inScaleFactor,
            Size(inWidth, inHeight), meanVal, false, false); 
        net.setInput(inputBlob, "data");

Затем в OpenCV, вызвав net.forward для обнаружения, извлеките показатель достоверности (0 ~ 1) для результата и извлеките позицию BOX выше порогового значения (при условии, что 0,5), вы можете нарисовать прямоугольную рамку для отображения, код этой части выглядит следующим образом:

// 人脸检测
        Mat detection = net.forward("detection_out"); 
        vector<double> layersTimings;
        double freq = getTickFrequency() / 1000;
        double time = net.getPerfProfile(layersTimings) / freq;
        Mat detectionMat(detection.size[2], detection.size[3], CV_32F, detection.ptr<float>());

        ostringstream ss;
        ss << "FPS: " << 1000 / time << " ; time: " << time << " ms";
        putText(frame, ss.str(), Point(20, 20), 0, 0.5, Scalar(0, 0, 255));
        for (int i = 0; i < detectionMat.rows; i++)
        {
            float confidence = detectionMat.at<float>(i, 2);
            if (confidence > confidenceThreshold)
            {
                int xLeftBottom = static_cast<int>(detectionMat.at<float>(i, 3) * frame.cols);
                int yLeftBottom = static_cast<int>(detectionMat.at<float>(i, 4) * frame.rows);
                int xRightTop = static_cast<int>(detectionMat.at<float>(i, 5) * frame.cols);
                int yRightTop = static_cast<int>(detectionMat.at<float>(i, 6) * frame.rows);

                Rect object((int)xLeftBottom, (int)yLeftBottom,
                    (int)(xRightTop - xLeftBottom),
                    (int)(yRightTop - yLeftBottom));

                rectangle(frame, object, Scalar(0, 255, 0));

                ss.str("");
                ss << confidence;
                String conf(ss.str());
                String label = "Face: " + conf;
                int baseLine = 0;
                Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);
                rectangle(frame, Rect(Point(xLeftBottom, yLeftBottom - labelSize.height),
                    Size(labelSize.width, labelSize.height + baseLine)),
                    Scalar(255, 255, 255), CV_FILLED);
                putText(frame, label, Point(xLeftBottom, yLeftBottom),
                    FONT_HERSHEY_SIMPLEX, 0.5, Scalar(0, 0, 0));
            }
        }

Окончательные результаты бегущего дисплея следующие, при нормальных обстоятельствах лицо не заблокировано:
OpenCV基于残差网络实现人脸检测
С открытым лицом и наклоненной головой:
OpenCV基于残差网络实现人脸检测
Когда лицо закрыто:
OpenCV基于残差网络实现人脸检测
Больше в различных ситуациях, таких как наклон, боковая грань, размытие и т. д.:
OpenCV基于残差网络实现人脸检测
Видно, насколько мощна модель остаточной сети.Не пора ли заказать песню «Лян Лян» и отправить ее на каскадный детектор HAAR. Полный исходный код приведенной выше демонстрации можно загрузить на GITHUB.
GitHub.com/gloomyfish1…

Учебное пособие по OpenCV DNN