Андроид. Windows. Антивирусы. Гаджеты. Железо. Игры. Интернет. Операционные системы. Программы.

Детектирование объектов с помощью особенностей в OpenCV: FREAK. Детектирование множества объектов. Компьютерное зрение на openCV Распознавание объекта на изображении opencv

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

  • Matrox Imaging Library
  • Camellia Library
  • Open eVision
  • HALCON
  • libCVD
  • OpenCV
  • и т.д…
Данные SDK могут сильно различаться по функциональности, условиям лицензирования, используемым языкам программирования. Мы же подробнее остановимся на OpenCV . Она бесплатна как для учебных целей, так и для коммерческого использования. Написана на оптимизированном C/C++, поддерживает интерфейсы C, C++, Python, Java и включает в себя реализации свыше 2500 алгоритмов. Помимо стандартных функций обработки изображений (фильтрация, размытие, геометрические преобразования и т.д…) данный SDK позволяет решать более сложные задачи, к которым относятся обнаружение объекта на фотографии и его «узнавание». Следует понимать, что задачи обнаружения и распознавания могут быть совершенно различными:
  • поиск и распознавание конкретного объекта,
  • поиск объектов одной категории (без распознавания),
  • только распознавание объекта (уже готовое изображение с ним).
Для обнаружения признаков на изображении и проверки на совпадение в OpenCV имеются следующие методы:
  • Гистограмма направленных градиентов HOG(Histogram of Oriented Gradients) — может применяться для обнаружения пешеходов
  • Алгоритм Виолы-Джонса — применяется для поиска лиц
  • Алгоритм обнаружения признаков SIFT (Scale Invariant Feature Transform)
  • Алгоритм обнаружения признаков SURF (Speeded Up Robust Features)
Например, SIFT обнаруживает наборы точек, которые можно использовать для идентификации объекта. Помимо приведенных методик в OpenCV имеются и другие алгоритмы для детектирования и распознавания, а также набор алгоритмов, относящихся к машинному обучению, таких как метод k ближайших соседей, нейронные сети, метод опорных векторов и т.д… В целом OpenCV предоставляет инструментарий, достаточный для решения подавляющего большинства задач компьютерного зрения. Если алгоритм не имеется в составе SDK, то, как правило, он может быть без проблем запрограммирован. Кроме того, существует множество авторских версий алгоритмов, написанных пользователями на основе OpenCV. Также следует отметить, что за последние годы OpenCV сильно расширилась и стала в некоторой степени «тяжеловесной». В связи с этим, разными группами энтузиастов создаются «облегченные» библиотеки, основанные на OpenCV. Примеры: SimpleCV, liuliu ccv, tinycv… Полезные сайты
  1. http://opencv.org/ — Основной сайт проекта
  2. http://opencv.willowgarage.com/wiki/ — Старый сайт проекта с документацией по старым версиям

Ну, в основном вам нужно обнаружить круги . Вы видели cvHoughCircles() ? Разрешено ли вам это использовать?

На этой странице есть хорошая информация о том, как обнаружить вещи с помощью OpenCV . Вас может заинтересовать раздел 2.5 .

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

Вход :

Выходы :

// compiled with: g++ circles.cpp -o circles `pkg-config --cflags --libs opencv` #include #include #include #include int main(int argc, char** argv) { IplImage* img = NULL; if ((img = cvLoadImage(argv))== 0) { printf("cvLoadImage failed\n"); } IplImage* gray = cvCreateImage(cvGetSize(img), IPL_DEPTH_8U, 1); CvMemStorage* storage = cvCreateMemStorage(0); cvCvtColor(img, gray, CV_BGR2GRAY); // This is done so as to prevent a lot of false circles from being detected cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7); IplImage* canny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,1); IplImage* rgbcanny = cvCreateImage(cvGetSize(img),IPL_DEPTH_8U,3); cvCanny(gray, canny, 50, 100, 3); CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, gray->height/3, 250, 100); cvCvtColor(canny, rgbcanny, CV_GRAY2BGR); for (size_t i = 0; i < circles->total; i++) { // round the floats to an int float* p = (float*)cvGetSeqElem(circles, i); cv::Point center(cvRound(p), cvRound(p)); int radius = cvRound(p); // draw the circle center cvCircle(rgbcanny, center, 3, CV_RGB(0,255,0), -1, 8, 0); // draw the circle outline cvCircle(rgbcanny, center, radius+1, CV_RGB(0,0,255), 2, 8, 0); printf("x: %d y: %d r: %d\n",center.x,center.y, radius); } cvNamedWindow("circles", 1); cvShowImage("circles", rgbcanny); cvSaveImage("out.png", rgbcanny); cvWaitKey(0); return 0; }

Обнаружение кругов сильно зависит от параметров cvHoughCircles() . Обратите внимание, что в этой демонстрации я также использовал Canny.

Я должен закодировать детектор объекта (в данном случае шарик) с помощью OpenCV. Проблема в том, что каждый поиск в google возвращает мне что-то с FACE DETECTION. Поэтому мне нужна помощь в том, с чего начать, что использовать и т. Д.

Некоторая информация:

  • Мяч не имеет фиксированного цвета, он, вероятно, будет белым, но он может измениться.
  • Я должен использовать машинное обучение, не обязательно быть сложным и надежным, предложение KNN (это проще и проще).
  • После всего моего поиска я обнаружил, что вычисление гистограммы образцов только для шаров и обучение его ML может быть полезным, но моя главная забота здесь в том, что размер шара может и изменится (ближе и дальше от камеры) и я понятия не имею, что передать ML, чтобы классифицировать для меня, я имею в виду.. я не могу (или я могу?) просто проверить каждый пиксель изображения для каждого возможного размера (от, скажем, от 5x5 до WxH) и надеемся найти положительный результат.
  • Там может быть неравномерный фон, например, люди, ткань за мячом и т. Д.
  • Как я уже сказал, мне нужно использовать алгоритм ML, что означает отсутствие алгоритмов Хаара или Виолы.
  • Кроме того, я думал об использовании контуров, чтобы найти круги на изображении Canny"ed, просто нужно найти способ преобразования контура в строку данных для обучения KNN.

    Итак... предложения?

    Заранее спасибо. ;)

Основная идея заключается в учете статистических связей между расположением антропометрических точек лица . На каждом изображении лица точки пронумерованы в одинаковом порядке. По их взаимному расположению осуществляется сравнение лиц.

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

Захват видеопотока с камеры и выделение лица

#include using namespace cv; int main() { // Load Face cascade (.xml file) CascadeClassifier face_cascade; face_cascade.load("haarcascade_frontalface_alt2.xml"); Mat img; VideoCapture cap(0); while (true) { cap >> img; //cvtColor(img, img, CV_BGR2GRAY); // Detect faces std::vector faces; face_cascade.detectMultiScale(img, faces, 1.1, 2, 0 | CV_HAAR_SCALE_IMAGE, Size(30, 30)); // Draw circles on the detected faces for (int i = 0; i < faces.size(); i++) { Point center(faces[i].x + faces[i].width*0.5, faces[i].y + faces[i].height*0.5); ellipse(img, center, Size(faces[i].width*0.5, faces[i].height*0.5), 0, 0, 360, Scalar(255, 0, 255), 4, 8, 0); } imshow("Detected Face", img); waitKey(1); } return 0; }

Файлы каскадов находятся в директории c:\opencv\build\etc\… Нужный каскад размещаете в директории проекта, там же, где и исходный файл main.cpp.

Выделение особых точек лица

Приложение создано на основе C++ code for OpenCV Facemark

#include #include #include #include #include #include #include "drawLandmarks.hpp" using namespace std; using namespace cv; using namespace cv::face; int main(int argc, char** argv) { // Load Face Detector CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark Ptr facemark = FacemarkLBF::create(); // Load landmark detector facemark->loadModel("lbfmodel.yaml"); // Set up webcam for video capture VideoCapture cam(0); // Variable to store a video frame and its grayscale Mat frame, gray; // Read a frame while (cam.read(frame)) { // Find face vector faces; // Convert frame to grayscale because // faceDetector requires grayscale image. cvtColor(frame, gray, COLOR_BGR2GRAY); // Detect faces faceDetector.detectMultiScale(gray, faces); // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Hence, we // use a vector of vector of points. vector< vector > landmarks; // Run landmark detector bool success = facemark-> < faces.size(); i++) { cv::rectangle(frame, faces[i], Scalar(0, 255, 0), 3); } for (int i = 0; i < landmarks.size(); i++) { drawLandmarks(frame, landmarks[i]); /*for (size_t j = 0; j < landmarks[i].size(); j++) circle(frame, Point(landmarks[i][j].x, landmarks[i][j].y), 1, Scalar(255, 0, 0), 2);*/ } } // Display results imshow("Facial Landmark Detection", frame); // Exit loop if ESC is pressed if (waitKey(1) == 27) break; } return 0; }

В проекте приложения, там же где и файл main.cpp, разместил файлы haarcascade_frontalface_alt2.xml , drawLandmarks.hpp и lbfmodel.yaml , на которые есть ссылки в коде. Файлы каскадов находятся в директории c:\opencv\build\etc\… Файлы drawLandmarks.hpp и lbfmodel.yaml есть в архиве Facemark_LBF.rar .

После вставки кода появились ошибки из-за того, что в OpenCV 3.4.3-vc14-vc15 отсутствуют ряд библиотек, необходимых для запуска приложения. Скомпоновал свою библиотеку (скачать opencv_new.zip) и установил ее в корень диска C (C:\opencv-new).

Теперь, все настройки, которые выполнялись , необходимо выполнить и для opencv-new:

Выполняю настройки в Windows . Выхожу на окно «Изменить переменную среды» (кнопки Windows->Служебные->Панель управления -> Система и безопасность -> Система -> Дополнительные параметры системы -> Переменные среды -> Path ->Изменить). В этом окне создаю переменную C:\opencv-new \x64\vc14\bin. Перезагружаю Windows .

В свойствах проекта также ссылаюсь на библиотеку opencv_new (вместо opencv). В окне «Property Pages» выполняю действия:

  • C/C++ -> General -> Additional Include Directories -> C:\opencv-new \include
  • Linker -> General -> Additional Library Directories -> C:\opencv-new \x64\vc14\lib
  • Linker -> Input -> Additional Dependencies -> opencv_core400.lib; opencv_face400.lib; opencv_videoio400.lib; opencv_objdetect400.lib; opencv_imgproc400.lib; opencv_highgui400.lib

При запуске программа выдает ошибку, если в установках проекта Debug. Для Release, запуск успешный.


Выбор признаков для фильтрации изображений и распознавания лиц

Точечный каркас лица отображается по разному в зависимости от объективных и субъективных факторов.

Объективные факторы — положение лица относительно камеры.

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

При видеозахвате иногда проскакивают и такие изображения. Их нужно отфильтровывать — как при обучении так и распознавании.

Некоторые из точек есть наиболее стабильными и информативными. Они жестко привязаны к лицу, независимо от его положения относительно камеры. Кроме того, они хорошо характеризуют специфику лица. Эти точки могут быть использованы как основа для моделирования системы признаков.

Для сравнения лиц можно использовать точечный 2D каркас одного и того же положения лица. Какое положение лица относительно камеры есть наиболее информативным? Очевидно, что фронтальное. Не зря в криминалистике делают фото в анфас и профиль. Пока ограничимся анфасом.

Все признаки (расстояния) должны быть безразмерные (нормализованые), т.е., соотнесены к какому-то размеру(расстоянию). Предполагаю, что наиболее подходящий для этого размер — расстояние между серединами угловых точек глаз. А почему, например, не внешними угловыми точками глаз, которые реально определены в массиве landmarks? Дело в том, что угловые точки глаз раздвигаются (сближаются) при реагировании на изменение цвета, выражении удивления, моргании и т.п. Расстояние между серединами глаз нивелирует эти колебания и поэтому более предпочтительно.

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

Итак, прежде чем формировать признаки для обучения и сравнения, необходимо отфильтровать полученные видеозахватом точечные каркасы лиц, которые по субъективным или объективным причинам не есть правильное фронтальное изображение лица (анфас).

Оставляем только те точечные каркасы, которые проходят по следующим признакам:

  • Прямая, которая проходит через крайние точки глаз (линия глаз), перпендикулярна прямой, которая проходит через крайние точки носа (линия носа).
  • Линия глаз параллельна прямой, которая проходит через точки уголков рта (линия рта).
  • Соблюдается симметрия указанных выше точек относительно линии носа.
  • Угловые точки глаз (внешние и внутренние) находятся на одной прямой.

Пример фронтальных изображений, которые проходят по всем признакам:

Пример изображений, которые отфильтровываются:

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

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

Алгоритм распознавания лиц по 2D-каркасу точек

Координаты точек каркаса лица изначально задаются в системе координат, которая привязана к верхней левой точке окна. При этом ось Y направлена вниз.

Для удобства определения признаков используем пользовательскую систему координат (ПСК), ось X которой проходит через отрезок между серединами глаз, а ось Y — перпендикулярно этому отрезку через его середину в направлении вверх. Координаты ПСК (от -1 до +1) нормализованы — соотнесены с расстоянием между средними точками глаз.

ПСК обеспечивает удобство и простоту определения признаков. Например, положение лица в анфас определяется признаком симметрии соответствующих точек глаз относительно линии носа. Этот признак формализуется совпадением линии носа с осью Y, т.е X1=X2=0, где X1 и X2 — координаты крайних точек носа (27 и 30) в ПСК.

Определяем относительно оконной СК

Координаты средних точек левого и правого глаз (Left и Right):

XL = (X45 + X42) /2 ; YL = (Y45 + Y42) /2 ; XR = (X39 + X 36) /2; YR = (Y39 + Y 36) /2;

Начало ПСК:

X0 =(XL + XR)/2; Y0 =(YL + YR)/2;

Расстояния между средними точками глаз вдоль осей Х и Y:

DX = XR — XL; DY = YR — YL;

Действительное расстояние L между средними точками глаз (по теореме Пифагора):

L = sqrt (DX** 2 + DY**2)

Тригонометрические функции угла поворота ПСК:

Переходим от координат в оконной СК к координатам в ПСК , используя параметры X0,Y0, L, sin AL, cos AL:

X_User_0 = 2 (X_Window — X0) / L;

Y_User_0 = — 2 (Y_Window — Y0) / L ;

X_User = X_User_0 * cos_AL — Y_User_0 * sin_AL;

Y_User = X_User_0 * sin_AL + Y_User_0 * cos_AL;

Реализуем фильтрацию изображений последовательно проверяя признаки:

1.Признак перпендикулярности линий носа и глаз, а также симметрии угловых точек глаз . Линия носа определяется точками 27 и 30 (см. рисунок во ). Оба признака выполняются, если в ПСК координаты этих точек X1 = X2= 0 (т.е., линия носа совпадает с осью Y).

2.Признак параллельности линии глаз и линии рта . Линия рта определяется точками 48 и 54 (см. рисунок во ). Признак выполняется, если в ПСК Y1-Y2=0.

3. Признак симметрии угловых точек рта . Линия рта определяется точками 48 и 54 (см. рисунок во ). Признак выполняется, если в ПСК X1+X2 =0

4. Признак «Угловые точки глаз находятся на одной прямой» . Прямые определяются парами точек: (36 и 45), а также (39 и 42). Поскольку тест по признаку 1 уже пройден, достаточно лишь определить в ПСК признак Y2-Y1 =0 лишь для точек 36 и 39.

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

Программа сравнения лиц по одному признаку

В качестве признака берется расстояние между точками переносицы и подбородка (Landmarks точками 27 и 8, см. рисунок во ). Признак, нормализован, определяется в ПСК отношением: (Y1 — Y2)/L , где L — расстояние между центрами глаз. При обучении программы признак для конкретного лица определяется числом, которое высвечивается рядом с отслеживаемым лицом (эта часть кода в программе закомментирована). При распознавании значение признака сравнивается с введенным в программу конкретным признаком для каждого лица. При положительном результате сравнения рядом с лицом появляется его идентификатор.

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

Контрольные задания:

  1. Ознакомиться с программой.
  2. Определить значение признака для своего лица и нескольких своих коллег.
  3. Протестировать программу на предмет идентификации лиц (своего и коллег).

#include #include #include #include #include #include #include "drawLandmarks.hpp" using namespace std; using namespace cv; using namespace cv::face; int main(int argc, char** argv) { // Load Face Detector CascadeClassifier faceDetector("haarcascade_frontalface_alt2.xml"); // Create an instance of Facemark Ptr facemark = FacemarkLBF::create(); // Load landmark detector facemark->loadModel("lbfmodel.yaml"); // Set up webcam for video capture VideoCapture cam(0); // Variable to store a video frame and its grayscale Mat frame, gray; // Read a frame while (cam.read(frame)) { // Find face vector faces; // Convert frame to grayscale because // faceDetector requires grayscale image. cvtColor(frame, gray, COLOR_BGR2GRAY); // Detect faces faceDetector.detectMultiScale(gray, faces); // Variable for landmarks. // Landmarks for one face is a vector of points // There can be more than one face in the image. Hence, we // use a vector of vector of points. vector< vector > landmarks; // Run landmark detector bool success = facemark->fit(frame, faces, landmarks); if (success) { // If successful, render the landmarks on the face for (size_t i = 0; i < faces.size(); i++) { cv::rectangle(frame, faces[i], Scalar(0, 255, 0), 3); } for (int i = 0; i < landmarks.size(); i++) { //if((i >=30)&&(i <= 35)) drawLandmarks(frame, landmarks[i]); for (size_t j = 0; j < landmarks[i].size(); j++) { circle(frame, Point(landmarks[i][j].x, landmarks[i][j].y), 1, Scalar(255, 0, 0), 2); } line(frame, Point(landmarks[i].x, landmarks[i].y), Point(landmarks[i].x, landmarks[i].y), Scalar(0, 0, 255), 2); float XL = (landmarks[i].x + landmarks[i].x) / 2; float YL = (landmarks[i].y + landmarks[i].y) / 2; float XR = (landmarks[i].x + landmarks[i].x) / 2; float YR = (landmarks[i].y + landmarks[i].y) / 2; line(frame, Point(XL, YL), Point(XR, YR), Scalar(0, 0, 255), 2); float DX = XR - XL; float DY = YR - YL; float L = sqrt(DX * DX + DY * DY); float X1 = (landmarks[i].x); float Y1 = (landmarks[i].y); float X2 = (landmarks[i].x); float Y2 = (landmarks[i].y); float DX1 = abs(X1 - X2); float DY1 = abs(Y1 - Y2); float L1 = sqrt(DX1 * DX1 + DY1 * DY1); float X0 = (XL + XR) / 2; float Y0 = (YL + YR) / 2; float sin_AL = DY / L; float cos_AL = DX / L; float X_User_0 = (landmarks[i].x - X0) / L; float Y_User_0 = -(landmarks[i].y - Y0) / L; float X_User27 = X_User_0 * cos_AL - Y_User_0 * sin_AL; float Y_User27 = X_User_0 * sin_AL + Y_User_0 * cos_AL; X_User_0 = (landmarks[i].x - X0) / L; Y_User_0 = -(landmarks[i].y - Y0) / L; float X_User30 = X_User_0 * cos_AL - Y_User_0 * sin_AL; float Y_User30 = X_User_0 * sin_AL + Y_User_0 * cos_AL; if (abs(X_User27 - X_User30) <= 0.1) { //putText(frame, std::to_string(abs(L1 / L)), Point(landmarks[i].x, landmarks[i].y), 1, 2, Scalar(0, 0, 255), 2); if (abs((L1 / L) - 1.6) < 0.1) { putText(frame, "Roman", Point(landmarks[i].x, landmarks[i].y), 1, 2, Scalar(0, 0, 255), 2); } if (abs((L1 / L) - 1.9) < 0.1) { putText(frame, "Pasha", Point(landmarks[i].x, landmarks[i].y), 1, 2, Scalar(0, 0, 255), 2); } if (abs((L1 / L) - 2.1) < 0.1) { putText(frame, "Svirnesvkiy", Point(landmarks[i].x, landmarks[i].y), 1, 2, Scalar(0, 0, 255), 2); } } putText(frame, "Incorrect", Point(landmarks[i].x, landmarks[i].y), 1, 2, Scalar(0, 0, 255), 2); } } // Display results imshow("Facial Landmark Detection", frame); // Exit loop if ESC is pressed if (waitKey(1) == 27) break; } return 0; }

Похожие публикации