OpenCV 2.4.10 Обнаружение лиц работает с видео, но не может обнаруживаться на статическом изображении

Я использую каскадный классификатор OpenCV для обнаружения лиц. Я последовал инструкциям по веб-камере и смог использовать detectMultiScale, чтобы найти и отследить свое лицо, пока он транслировал видео с веб-камеры моего ноутбука.

Но когда я фотографирую себя с веб-камеры своего ноутбука, я загружаю это изображение в OpenCV и применяю detectMultiScale к этому изображению, и по какой-то причине Cascade Classifier не может обнаружить лица на этом статическом изображении!

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

Вот код, который я использую (только что выделил соответствующие строки):

Общий код:

String face_cascade_name = "/path/to/data/haarcascades/haarcascade_frontalface_alt.xml";
CascadeClassifier face_cascade;

Mat imagePreprocessing(Mat frame) {
    Mat processed_frame;
    cvtColor( frame, processed_frame, COLOR_BGR2GRAY );
    equalizeHist( processed_frame, processed_frame );
    return processed_frame;
}

Для потокового обнаружения лиц с веб-камеры:

int detectThroughWebCam() {
    VideoCapture capture;
    Mat frame;
    if( !face_cascade.load( face_cascade_name ) ){ printf("--(!)Error loading face cascade\n"); return -1; };


    //-- 2. Read the video stream
    capture.open( -1 );
    if ( ! capture.isOpened() ) { printf("--(!)Error opening video capture\n"); return -1; }

    while ( capture.read(frame) )
    {
         if(frame.empty()) {
             printf(" --(!) No captured frame -- Break!");
             break;
         }
         //-- 3. Apply the classifier to the frame
         Mat processed_image = imagePreprocessing( frame);
         vector<Rect> faces;
         face_cascade.detectMultiScale( processed_frame, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE|CV_HAAR_FIND_BIGGEST_OBJECT, Size(30, 30) );
         if (faces.size() > 0) cout << "SUCCESS" << endl;
         int c = waitKey(10);
         if( (char)c == 27 ) { break; } // escape
    }
    return 0;
}

Для моего обнаружения лица на статическом изображении:

void staticFaceDetection() {
    Mat image = imread("path/to/jpg/image");
    Mat processed_frame = imagePreprocessing(image);
    std::vector<Rect> faces;
    //-- Detect faces
    face_cascade.detectMultiScale( processed_frame, faces, 1.1, 2, 0|CV_HAAR_SCALE_IMAGE|CV_HAAR_FIND_BIGGEST_OBJECT, Size(30, 30) );
    if (faces.size() > 0) cout << "SUCCESS" << endl;
}

На мой взгляд, оба эти процесса идентичны (единственная разница в том, где я получаю исходное изображение), но версия видеопотока регулярно обнаруживает лица, в то время как статический метод, кажется, никогда не может найти лицо.

Я что-то упустил?


person user2555636    schedule 31.05.2015    source источник
comment
Не могли бы вы поделиться полным кодом?   -  person hola    schedule 04.04.2016


Ответы (2)


Для этого есть несколько возможных причин.

  1. Вы сохраняете изображение в низком разрешении. Попробуйте сохранить его в исходном разрешении

  2. Сжатие без потерь. Вы сохраняете изображения в формате .jpg? возможно, у вас слишком сильное сжатие. Попробуйте сохранить как файл BMP (сохраняет исходное качество).

  3. Формат изображения. Я не знаю, что делает ваш imagePreprocessing() метод, но вы можете столкнуться со следующими проблемами. Камера записывает видео в определенном формате (большинство камер используют YUV). Обычно обнаружение лиц выполняется на первой плоскости Y. Когда вы сохраняете изображение и считываете его с диска как RGB, вы не должны запускать обнаружение лиц на первой плоскости. Это будет плоскость «B», и синий цвет хранит очень мало информации о лице. убедитесь, что вы правильно преобразовали изображение в оттенки серого, прежде чем запускать обнаружение лица.

  4. Диапазон изображения. Это частая ошибка. Убедитесь, что динамический диапазон изображения правильный. Иногда по ошибке вы можете умножить все значения на 255, что приведет к превращению всего изображения в белый цвет.

  5. Возможно, обнаружение лиц на изображениях работает нормально, но вы каким-то образом очищаете вектор faces после обнаружения лиц. Другая ошибка может заключаться в том, что вы читаете другой файл изображения. Например, вы сохраняете изображения в каталог «A», но случайно читаете их из каталога «B».

Если ничего из вышеперечисленного не помогает. Выполните следующую отладку. Для i-го кадра видео - сохранить в памяти. Затем сохраните его на диск и прочтите обратно из файла в память. Теперь самое важное: сравните изображения. Если они разные - это причина разных результатов распознавания лиц. Если нет, то необходимо дальнейшее расследование. Я почти уверен, что изображения не будут идентичными, и в этом проблема. Вы можете увидеть, где изображения не идентичны, взяв разницу между значениями пикселей и отобразив различное изображение. Вы можете сравнивать изображения, используя функцию memcmp(), которая сравнивает 2 блока памяти. Удачи

person DanielHsH    schedule 31.05.2015
comment
Я сделал, как вы предложили: взял свой видеокадр, сохранил его в формате JPG и затем перезагрузил. К моему удивлению, когда я снял разницу в изображениях, не было никакой разницы между изображениями (изображение разницы было полностью черным), и, более того, обнаружение лиц в видеопотоке все еще работало, даже если я изо всех сил старался сохранить захваченный кадр в файл jpg, а затем перезагрузите его из этого файла для передачи алгоритму faceDetection. Кроме того, я проверил, что и кадры из захвата видео, и загруженные мной изображения jpg были CV_8U3C с тем же динамическим диапазоном и сохранены как BGR. - person user2555636; 01.06.2015
comment
Я правильно конвертирую изображения в оттенки серого (см. Мою функцию imagePreProcessing выше), поэтому я серьезно не могу найти источник этой путаницы. - person user2555636; 01.06.2015
comment
Вы сравнивали изображения с помощью memcmp () или просто глазами (видя разностное изображение черного). Возможно, есть небольшие различия в значениях пикселей (+ -1), и вы просто не можете видеть это своими глазами, поэтому изображение diff выглядит полностью черным. В качестве альтернативы вы можете просуммировать ABS разностного изображения и посмотреть, равно ли оно нулю. Крайне маловероятно, что изображение останется точно таким же после записи и чтения с диска в формате JPG. - person DanielHsH; 01.06.2015

Решил!

Действительно глупая ошибка. Я не вызывал facecascades.load для загрузки haarcascades для версии со статическим изображением, но я сделал это для версии с видеокамерой.

Теперь все работает.

person user2555636    schedule 02.06.2015