Перейти к содержимому
Compvision.ru

Nuzhny

Пользователи
  • Количество публикаций

    1 427
  • Зарегистрирован

  • Посещение

  • Days Won

    176

Все публикации пользователя Nuzhny

  1. Проблема с cvCvtColor

    Ты лучше окно call stack в момент ошибки приведи - там и будет ответ.
  2. Трекинг объектов.

    С глюками согласен - исправил. Вот, добавил простенький алгоритм отсева отделившихся точек: 1. вычисляем центр масс распределения точек; 2. по нему корректируем размеры описывающего прямоугольника; 3. удаляем точки, не вошедшие в новый прямоугольник. У меня вроде как работает нормально. #include <algorithm> #include <limits> #include <highgui.h> #include <cv.h> #undef min #undef max //////////////////////////////////////////////////////////////////////////// //Поиск лица на кадре bool detect_face(IplImage *gray_img, CvHaarClassifierCascade *haar_cascade, CvMemStorage *mem_storage, CvRect &face_rect) { cvClearMemStorage(mem_storage); //Поиск лиц CvSeq *faces = cvHaarDetectObjects(gray_img, haar_cascade, mem_storage, 1.1, 2, 0, cvSize(20, 20)); if (!faces || !faces->total) return false; //Возвращаем первое найденное face_rect = *(CvRect *)cvGetSeqElem(faces, 0); return true; } //////////////////////////////////////////////////////////////////////////// class LKData { private: //Всякие данные IplImage *curr_img; IplImage *prev_img; IplImage *curr_pyramid_img; IplImage *prev_pyramid_img; int points_count; CvPoint2D32f *curr_points; CvPoint2D32f *prev_points; char *status; CvTermCriteria tc; int flags; public: LKData() : curr_img(NULL), prev_img(NULL), curr_pyramid_img(NULL), prev_pyramid_img(NULL), points_count(0), flags(0), curr_points(NULL), prev_points(NULL), status(NULL) { tc = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03); cvNamedWindow("points", 1); } //////////////////////////////////////////////////////////////////////////// ~LKData() { deinit(); cvDestroyWindow("points"); } //////////////////////////////////////////////////////////////////////////// //Инициализация данных для сопровождения void init(const IplImage *gray_img, const CvRect &face_rect) { deinit(); curr_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); prev_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); curr_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); prev_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); //Покроем прямоугольник лица равномерной сеткой из точек const int step_x = face_rect.width / 16; const int step_y = face_rect.height / 16; points_count = (face_rect.width / step_x + 1) * (face_rect.height / step_y + 1); curr_points = new CvPoint2D32f[points_count]; prev_points = new CvPoint2D32f[points_count]; status = new char[points_count]; size_t pc = 0; for (int i = face_rect.y, stop_i = face_rect.y + face_rect.height; i < stop_i; i += step_y) { for (int j = face_rect.x, stop_j = face_rect.x + face_rect.width; j < stop_j; j += step_x) { curr_points[pc] = cvPoint2D32f((float)j, (float)i); ++pc; } } points_count = (int)pc; cvCopyImage(gray_img, curr_img); cvFindCornerSubPix(curr_img, curr_points, points_count, cvSize(3, 3), cvSize(-1, -1), tc); //Смена указателей на параметры std::swap(prev_img, curr_img); std::swap(prev_pyramid_img, curr_pyramid_img); std::swap(prev_points, curr_points); } //////////////////////////////////////////////////////////////////////////// //Деинициализация данных для сопровождения void deinit() { if (curr_img) { cvReleaseImage(&curr_img); curr_img = NULL; } if (prev_img) { cvReleaseImage(&prev_img); prev_img = NULL; } if (curr_pyramid_img) { cvReleaseImage(&curr_pyramid_img); curr_pyramid_img = NULL; } if (prev_pyramid_img) { cvReleaseImage(&prev_pyramid_img); prev_pyramid_img = NULL; } points_count = 0; flags = 0; if (curr_points) { delete []curr_points; curr_points = NULL; } if (prev_points) { delete []prev_points; prev_points = NULL; } if (status) { delete []status; status = NULL; } } //////////////////////////////////////////////////////////////////////////// //Сопровождение лица bool tracking_face(IplImage *gray_img, CvRect &face_rect) { cvCopyImage(gray_img, curr_img); //Вычисление нового положения точек с помощью пирамидального алгоритма анализа оптического потока Лукаса-Канаде cvCalcOpticalFlowPyrLK(prev_img, curr_img, prev_pyramid_img, curr_pyramid_img, prev_points, curr_points, points_count, cvSize(20, 20), 3, status, 0, tc, flags); flags |= CV_LKFLOW_PYR_A_READY; if (!points_count) return false; //Удаление не найденных точек, а также вычисление координат описывающего прямоугольника float left = std::numeric_limits<float>::max(); float top = std::numeric_limits<float>::max(); float right = std::numeric_limits<float>::min(); float bottom = std::numeric_limits<float>::min(); //Центр масс CvPoint2D32f mc = cvPoint2D32f(0.f, 0.f); int k = 0; for (int i = 0; i < points_count; ++i) { if (status[i]) { curr_points[k] = curr_points[i]; if (curr_points[k].x < left) left = curr_points[k].x; if (curr_points[k].x > right) right = curr_points[k].x; if (curr_points[k].y < top) top = curr_points[k].y; if (curr_points[k].y > bottom) bottom = curr_points[k].y; mc.x += curr_points[k].x; mc.y += curr_points[k].y; ++k; } } points_count = k; mc.x /= (float)points_count; mc.y /= (float)points_count; //Вычисление расстояния от центра масс, до ближайших сторон описывающего прямоугольника float min_x = std::min(mc.x - left, right - mc.x); float min_y = std::min(mc.y - top, bottom - mc.y); //Границы описывающего прямоугольника пересчитываются с учётом полученных минимальных значений + небольшой отступ на всякий случай left = mc.x - min_x - min_x / 4.f; right = mc.x + min_x + min_x / 4.f; top = mc.y - min_y - min_y / 4.f; bottom = mc.y + min_y + min_y / 4.f; //Удаление точек, которые не попали в новый прямоугольник k = 0; for (int i = 0; i < points_count; ++i) { if (curr_points[i].x > left && curr_points[i].x < right && curr_points[i].y > top && curr_points[i].y < bottom) { curr_points[k] = curr_points[i]; //Вывод точек cvDrawCircle(gray_img, cvPoint((int)curr_points[k].x, (int)curr_points[k].y), 1, cvScalar(255, 0, 255)); ++k; } } points_count = k; printf("points_count = %i\n", points_count); face_rect.x = (int)left; face_rect.y = (int)top; face_rect.width = (int)(right - left); face_rect.height = (int)(bottom - top); //Смена указателей на параметры std::swap(prev_img, curr_img); std::swap(prev_pyramid_img, curr_pyramid_img); std::swap(prev_points, curr_points); cvShowImage("points", gray_img); return true; } }; //////////////////////////////////////////////////////////////////////////// int main() { //Загружаем обученные данные для классификатора CvHaarClassifierCascade *haar_cascade = (CvHaarClassifierCascade *)cvLoad("c:\\Program Files\\OpenCV_1_1\\data\\haarcascades\\haarcascade_frontalface_alt2.xml", 0, 0, 0); if (!haar_cascade) return 1; CvMemStorage *mem_storage = cvCreateMemStorage(0); //Захватываем видео (можно и с камеры) с лицами #if 0 CvCapture *video = cvCaptureFromFile("e:\\video_bmp\\cam_face.avi"); #else CvCapture *video = cvCaptureFromCAM(0); #endif if (!video) { cvClearMemStorage(mem_storage); cvRelease((void **)&haar_cascade); return 2; } cvNamedWindow("frame", 1); IplImage *gray_img = NULL; //Прямоугольник найденного лица CvRect face_rect = cvRect(0, 0, 0, 0); LKData lk_data; enum detector_states //Состояния нашего детектора { find_face, track_face }; detector_states state = find_face; for (IplImage *frame = cvQueryFrame(video); frame; frame = cvQueryFrame(video)) { //Вся работа ведётся на изображении в градациях серого if (!gray_img) gray_img = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1); cvCvtColor(frame, gray_img, CV_RGB2GRAY); //Наш примитивный автомат switch (state) { case find_face: //Поиск лица if (detect_face(gray_img, haar_cascade, mem_storage, face_rect)) { //Лицо найдено, инициализируем данные для сопровождения и меняем состояние lk_data.init(gray_img, face_rect); state = track_face; } break; case track_face: //Сопровождение лица if (!lk_data.tracking_face(gray_img, face_rect)) { //Лицо потеряно, деинициализируем данные сопровождения и меняем состояние lk_data.deinit(); state = find_face; } break; } cvDrawRect(frame, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0)); cvShowImage("frame", frame); if (cvWaitKey(10) > 0) break; } cvReleaseCapture(&video); cvDestroyWindow("frame"); cvClearMemStorage(mem_storage); cvRelease((void **)&haar_cascade); return 0; } ////////////////////////////////////////////////////////////////////////////[/codebox]
  3. Трекинг объектов.

    Если честно, меня очень удивляют твои затруднения. Элементарные знания языка и среды разработки должны быть - как же ты собираешься разбираться в гораздо более сложных алгоритмах? Visual Studio надо открывать hgfhgfhgf.sln. В Solution Explorer будет отображаться дерево проекта с исходниками. Ммм, ты знаешь что такое bat файлы, "командная строка", параметры функции main? Надо тебе разобраться с этими понятиями.
  4. Трекинг объектов.

    Что означает "после преобразования С++" я даже предположить не могу. "hgfhgfhgf" - это я по привычке дал имя случайным образом. В папке release есть bat файл. Его можно редактировать в блокноте. Открой его, посмотри какие параметры там указаны. Их и меняй. Если запустить сам exe без bat файла из командной строки, то он выведет доступные опции и параметры. Как оно работает: 1. Неподвижная камера смотрит куда-нибудь, сцена без движения. 2. Начинается движение, небольшое, объект меньше четверти размера кадра. 3. Он должен выделиться кружком.
  5. Трекинг объектов.

    Это совсем другая задача. Я ей никогда не занимался (хотя хочется - нет времени).
  6. Трекинг объектов.

    Вот здесь. Там есть папка release, запускай через bat-файл, в котором прописаны параметры используемых алгоритмов. Их можно (и нужно!) менять, при разных комбинациях параметров будет разное качество и скорость работы програмы. Видео берёт с первой камеры в системе.
  7. Трекинг объектов.

    Проблема в другом: найти на стационарном изображении движущийся объект - нетрудно. Трудности начнутся, когда ты будешь крутить камерой: смазывание изображения, интерлейсинг, артефакты сжатия... Это для начала. Потом: раз камера движется, то и задний план будет меняться, сразу отметаются самые популярные алгоритмы вычитания фона. Если ты всё таки захочешь их оставить, то надо будет использовать весьма точное сопоставление и наложение кадров (фактически это задача панорамирования). Если вычитание фона не использовать, то надо будет придумать хороший алгоритма поиска объекта. Если объект - человек, то отмашка рук, изменяющаяся геометрия ног и другие факторы начнут очень сильно портить картину. Короче говоря, это весьма непросто. P.S. Если хочешь, могу скомпилировать пример blobtrack.exe, чтобы он ничего лишнего не требовал (странно, что у тебя это не получается). Видео брать с камеры или из файла?
  8. Трекинг объектов.

    Программирование контроллера по сравнению с задачей отслеживания объекта поворотной камерой - это ерунда. Даже на стационарной камере точное и быстрое сопровождение сделать непросто. Готовые решения ты вряд ли найдёшь. Посмотри здесь четвёртый ролик - это фича очень немногих систем видеонаблюдения. Так что тебе придётся хорошенько над этим подумать.
  9. Можно. Можно. Это же обычная структура. Посмотри на её поля их значения - сразу всё станет ясно.
  10. Я думаю, что можно попробовать натренировать классификатор на номер - должно получиться очень неплохо.
  11. Трекинг объектов.

    Что такое CRT я думаю ты знаешь. Существует 2 способа собрать .exe: 1. прилинковать к нему CRT в виде статических lib; 2. ничего не прилинковывать, CRT используется из dll (например для 2008-й студии это msvcp80.dll, msvcr80.dll,...). В первом случае тебе ничего тащить с программой не надо, а во втором эти самые dll. Преимущества и недостатки есть у каждого подхода. Соответственно многие инсталляторы тащат с собой vcredist - майкрософтовский инсталлятор CRT. Или кидают эти dll в папку с программой. В OpenCV 1.1 эти dll лежат в папке bin.
  12. Трекинг объектов.

    Гм, с какой камеры? blobtrack.exe на входе из командной строки получает имя avi-файла с видео (а также параметры алгоритмов). С камерой он не работает. Ты можешь его скомпилировать? Почему стандартный не запускается? Может быть ему просто надо подсунуть майкрософтовскую CRT в ддлках? Или поставить vcredist?
  13. Странно, у меня 2005-я студия поддерживает OpenMP из коробки.
  14. Ну исходники же открыты - можно исправить. P.S. Я пока с версии 1.1 не ухожу, неохота.
  15. Трекинг объектов.

    Какие ошибки? Может, просто соответствующие *.lib не подключил? P.S. Русскоязычная студия - это ужас!
  16. Трекинг объектов.

    Советую посмотреть на реализацию стандартных примеров из OpenCV: blobtrack.exe и bgfg_codebook.exe. В основном тебе будет интересен первый пример.
  17. GStrimer в OpenCV

    Документации я тоже не видел, но в исходниках OpneCV 1.1 есть функция cvCreateCapture_GStreamer, которая включается при определённом макросе HAVE_GSTREAMER. Определить его, конечно, можно, после перекомпилировать highgui. Может и поможет, надо пробовать.
  18. Трекинг объектов.

    2gonzik: Ну в примерах же всё есть! Надо же просто скомпоновать. Нерадивый студент? Вот, набросал на скорую руку, но сразу скажу, что не реализовал пункт 5: Если какая-то точка слишком далеко "оторвалась" от объекта (например, на расстояние, превышающее размер лица), то её тоже удаляем. Сам попробуй, а то уже футбол начался, "Рубин" играет. #include <algorithm> #include <limits> #include <highgui.h> #include <cv.h> #undef min #undef max #pragma comment(lib, "cv.lib") #pragma comment(lib, "cxcore.lib") #pragma comment(lib, "highgui.lib") //////////////////////////////////////////////////////////////////////////// //Поиск лица на кадре bool detect_face(IplImage *gray_img, CvHaarClassifierCascade *haar_cascade, CvMemStorage *mem_storage, CvRect &face_rect) { cvClearMemStorage(mem_storage); //Поиск лиц CvSeq *faces = cvHaarDetectObjects(gray_img, haar_cascade, mem_storage, 1.1, 2, 0, cvSize(20, 20)); if (!faces || !faces->total) return false; //Возвращаем первое найденное face_rect = *(CvRect *)cvGetSeqElem(faces, 0); return true; } //////////////////////////////////////////////////////////////////////////// class LKData { private: //Всякие данные IplImage *curr_img; IplImage *prev_img; IplImage *curr_pyramid_img; IplImage *prev_pyramid_img; int points_count; CvPoint2D32f *curr_points; CvPoint2D32f *prev_points; char *status; CvTermCriteria tc; int flags; public: LKData() : curr_img(NULL), prev_img(NULL), curr_pyramid_img(NULL), prev_pyramid_img(NULL), points_count(0), flags(0), curr_points(NULL), prev_points(NULL), status(NULL) { tc = cvTermCriteria(CV_TERMCRIT_ITER | CV_TERMCRIT_EPS, 20, 0.03); cvNamedWindow("points", 1); } //////////////////////////////////////////////////////////////////////////// ~LKData() { deinit(); cvDestroyWindow("points"); } //////////////////////////////////////////////////////////////////////////// //Инициализация данных для сопровождения void init(const IplImage *gray_img, const CvRect &face_rect) { deinit(); curr_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); prev_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); curr_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); prev_pyramid_img = cvCreateImage(cvSize(gray_img->width, gray_img->height), IPL_DEPTH_8U, 1); //Покроем прямоугольник лица равномерной сеткой из точек const int step_x = face_rect.width / 16; const int step_y = face_rect.height / 16; points_count = (face_rect.width / step_x + 1) * (face_rect.height / step_y + 1); curr_points = new CvPoint2D32f[points_count]; prev_points = new CvPoint2D32f[points_count]; status = new char[points_count]; size_t pc = 0; for (int i = face_rect.y, stop_i = face_rect.y + face_rect.height; i < stop_i; i += step_y) { for (int j = face_rect.x, stop_j = face_rect.x + face_rect.width; j < stop_j; j += step_x) { curr_points[pc] = cvPoint2D32f((double)j, (double)i); ++pc; } } points_count = (int)pc; cvCopyImage(gray_img, curr_img); cvFindCornerSubPix(curr_img, curr_points, points_count, cvSize(3, 3), cvSize(-1, -1), tc); //Смена указателей на параметры std::swap(prev_img, curr_img); std::swap(prev_pyramid_img, curr_pyramid_img); std::swap(prev_points, curr_points); } //////////////////////////////////////////////////////////////////////////// //Деинициализация данных для сопровождения void deinit() { if (curr_img) { cvReleaseImage(&curr_img); curr_img = NULL; } if (prev_img) { cvReleaseImage(&prev_img); prev_img = NULL; } if (curr_pyramid_img) { cvReleaseImage(&curr_pyramid_img); curr_pyramid_img = NULL; } if (prev_pyramid_img) { cvReleaseImage(&prev_pyramid_img); prev_pyramid_img = NULL; } points_count = 0; flags = 0; if (curr_points) { delete []curr_points; curr_points = NULL; } if (prev_points) { delete []prev_points; prev_points = NULL; } if (status) { delete []status; status = NULL; } } //////////////////////////////////////////////////////////////////////////// //Сопровождение лица bool tracking_face(IplImage *gray_img, CvRect &face_rect) { cvCopyImage(gray_img, curr_img); //Вычисление нового положения точек с помощью пирамидального алгоритма анализа оптического потока Лукаса-Канаде cvCalcOpticalFlowPyrLK(prev_img, curr_img, prev_pyramid_img, curr_pyramid_img, prev_points, curr_points, points_count, cvSize(20, 20), 3, status, 0, tc, flags); flags |= CV_LKFLOW_PYR_A_READY; if (!points_count) return false; //Удаление не найденных точек, а также вычисление координат описывающего прямоугольника double left = std::numeric_limits<double>::max(); double top = std::numeric_limits<double>::max(); double right = std::numeric_limits<double>::min(); double bottom = std::numeric_limits<double>::min(); int k = 0; for (int i = 0; i < points_count; ++i) { if (status[i]) { curr_points[k] = curr_points[i]; //Вывод точек cvDrawCircle(gray_img, cvPoint((int)curr_points[k].x, (int)curr_points[k].y), 1, cvScalar(255, 255, 255)); if (curr_points[k].x < left) left = curr_points[k].x; if (curr_points[k].x > right) right = curr_points[k].x; if (curr_points[k].y < top) top = curr_points[k].y; if (curr_points[k].y > bottom) bottom = curr_points[k].y; ++k; } } points_count = k; printf("points_count = %i\n", points_count); face_rect.x = (int)left; face_rect.y = (int)top; face_rect.width = (int)(right - left); face_rect.height = (int)(bottom - top); //Смена указателей на параметры std::swap(prev_img, curr_img); std::swap(prev_pyramid_img, curr_pyramid_img); std::swap(prev_points, curr_points); cvShowImage("points", gray_img); return true; } }; //////////////////////////////////////////////////////////////////////////// int main() { //Загружаем обученные данные для классификатора CvHaarClassifierCascade *haar_cascade = (CvHaarClassifierCascade *)cvLoad("c:\\Program Files\\OpenCV_1_1\\data\\haarcascades\\haarcascade_frontalface_alt2.xml", 0, 0, 0); if (!haar_cascade) return 1; CvMemStorage *mem_storage = cvCreateMemStorage(0); //Захватываем видео (можно и с камеры) с лицами #if 0 CvCapture *video = cvCaptureFromFile("e:\\video_bmp\\cam_face.avi"); #else CvCapture *video = cvCaptureFromCAM(0); #endif if (!video) { cvClearMemStorage(mem_storage); return 2; } cvNamedWindow("frame", 1); IplImage *gray_img = NULL; //Прямоугольник найденного лица CvRect face_rect = cvRect(0, 0, 0, 0); LKData lk_data; enum detector_states //Состояния нашего детектора { find_face, track_face }; detector_states state = find_face; for (IplImage *frame = cvQueryFrame(video); frame; frame = cvQueryFrame(video)) { //Вся работа ведётся на изображении в градациях серого if (!gray_img) gray_img = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1); cvCvtColor(frame, gray_img, CV_RGB2GRAY); //Наш примитивный автомат switch (state) { case find_face: //Поиск лица if (detect_face(gray_img, haar_cascade, mem_storage, face_rect)) { //Лицо найдено, инициализируем данные для сопровождения и меняем состояние lk_data.init(gray_img, face_rect); state = track_face; } break; case track_face: //Сопровождение лица if (!lk_data.tracking_face(gray_img, face_rect)) { //Лицо потеряно, деинициализируем данные сопровождения и меняем состояние lk_data.deinit(); state = find_face; } break; } cvDrawRect(frame, cvPoint(face_rect.x, face_rect.y), cvPoint(face_rect.x + face_rect.width, face_rect.y + face_rect.height), cvScalar(255, 0, 0)); cvShowImage("frame", frame); cvWaitKey(10); } cvClearMemStorage(mem_storage); cvReleaseCapture(&video); cvDestroyWindow("frame"); return 0; } ////////////////////////////////////////////////////////////////////////////[/codebox] P.S. Принимаются от всех заинтересованных лиц идеи по улучшению алгоритма. Идеи (а не реализация по примерам) действительно интересны.
  19. Трекинг объектов.

    Как в примере lkdemo.exe: 1. На кадре найдено лицо: а) заполняем массив точек лица каким-либо способом: равномерно по площади лица, случайным образом, cvGoodFeaturesToTrack; б) если использовались первые 2 способа, то для массива точек вызываем cvFindCornerSubPix. 2. Для следующего кадра: вызываем cvCalcOpticalFlowPyrLK, добавляем к флагам CV_LKFLOW_PYR_A_READY. 3. Если полученное число точек равно нулю - цель потеряна, выход, переходим к пункту 1. 4. Удаляем из массива не найденные на очередном кадре точки на основании массива status из cvCalcOpticalFlowPyrLK. 5. Если какая-то точка слишком далеко "оторвалась" от объекта (например, на расстояние, превышающее размер лица), то её тоже удаляем. 6. Если точек не осталось или осталось слишком мало (например 1-2 точки на лицо), то считаем цель потерянной, выход, переходим к пункту 1. 7. Вычисляем прямоугольник, описывающий оставшиеся точки, выводим его. 8. Можно вывести на кадре траекторию движения лица: центры прямоугольников на каждом кадре; при желании траекторию можно обрабатывать фильтром Кальмана. 9. Переход к пункту 2. Реализация практически всех пунктов есть в примере lkdemo.exe Если качество видео достаточно высокое, то сопровождение должно работать корректно.
  20. Трекинг объектов.

    Давай попробуем разобраться что есть что. 1. Нам подаётся видеопоток, в котором содержатся или не содержатся интересующие нас объекты - лица. 2. Лица надо как-то обнаружить: каскады Хаара, поиск регионов с текстурой, похожей на кожу и т.п. Поиск надо производить на каждом кадре? 3. Если поиск производится на каждом кадре, то надо определить какое лицо на кадре t соответствует лицу на кадре t+1. Есть варианты: по координатам, по размеру, найти точки с особенностями и сравнивать их и т.д. Соответствие между лицами на соседних кадрах найдено? Это и есть сопровождение. 4. Допустим, нам надо найти первое попавшееся лицо и сопровождать только его в видеопотоке. Тут можно воспользоваться алгоритмом Лукаса-Канаде. Находим алгоритмом из пункта 2 лицо, находим на нём характерные точки (например, как в примере lkdemo.exe). Сопровождаем точки с помощью Лукаса-Канаде; после их пропадания считаем, что лицо исчезло из поля зрения. Снова переходим к пункту 2. 5. Фильтр Кальмана в компьютерном зрении применяется для сглаживания траектории движения объекта (лица), а также для предсказания его положения на следующем кадре. Тут необходимо отметить, что фильтр Кальмана предназначен для линейных моделей движения. Для нелинейного же применяется particle filter (как вариант particle filter + mean shift).
  21. А что же там сложного для переделки? Убирай всё, что касается Билдера (это будет интерфейс) и заменяй на стандартный OpenCV вывод. Вообще, в примерах OpenCV есть отличный пример Лукаса-Канаде.
  22. Фильтр Калмана

    Если автор не против, то выложу переделку - делал как-то для себя, поиграть. Немного перегруппировал код, отформатировал по своему вкусу, но всё работает также как и в оригинале:#include "stdafx.h" #include <highgui.h> #include <cv.h> #pragma comment(lib, "cv.lib") #pragma comment(lib, "cxcore.lib") #pragma comment(lib, "highgui.lib") //////////////////////////////////////////////////////////////////////////// //function to find the biggest blob and to get the top left position CvPoint2D32f findBigBlob(IplImage *mask) { int maxval = 0; int minval = 100; //начинаем поиск контуров CvMemStorage *storage = cvCreateMemStorage(0); CvContourScanner traverse = cvStartFindContours(mask, storage, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_NONE); //находим контуры с длиной периметра между minval и maxval CvSeq *mContour = 0; for (CvSeq *contour = cvFindNextContour(traverse); contour; contour = cvFindNextContour(traverse)) { int contourarea = (int)abs(cvContourArea(contour, CV_WHOLE_SEQ)); if (contourarea > maxval) { mContour = contour; maxval = contourarea; } } CvPoint2D32f ret_val = cvPoint2D32f(-1.0, -1.0); if (maxval > minval) { //находим центр масс CvMoments moments; cvMoments(mContour, &moments, 0); ret_val.x = (float)(moments.m10 / moments.m00); ret_val.y = (float)(moments.m01 / moments.m00); } //освобождаем память cvEndFindContours(&traverse); cvReleaseMemStorage(&storage); return ret_val; } //////////////////////////////////////////////////////////////////////////// //находим участки, подходящие нам по цвету (шайба) void region_color_range(const IplImage *color, IplImage *mask, uchar bmin, uchar bmax, uchar gmin, uchar gmax, uchar rmin, uchar rmax) { uchar *dst_ptr = (uchar *)mask->imageData; for (const uchar *src_ptr = (uchar *)color->imageData, *stop = src_ptr + color->imageSize; src_ptr != stop; src_ptr += color->nChannels) { uchar b = src_ptr[0]; uchar g = src_ptr[1]; uchar r = src_ptr[2]; //проверяем диапазон составляющих цвета if (b <= bmax && b >= bmin && g <= gmax && g >= gmin && r <= rmax && r >= rmin) *dst_ptr = 255; else *dst_ptr = 0; ++dst_ptr; } } //////////////////////////////////////////////////////////////////////////// int main() { //параметры, для идентификации шайбы по цвету uchar bmin = 0; uchar bmax = 51; uchar gmin = 120; uchar gmax = 225; uchar rmin = 102; uchar rmax = 235; CvMat *measurement = cvCreateMat(2, 1, CV_32FC1); cvZero(measurement); CvRNG rng = cvRNG(-1); CvMat *state = cvCreateMat(4, 1, CV_32FC1); // (x, y, deltax, deltay) cvRandArr(&rng, state, CV_RAND_NORMAL, cvRealScalar(0), cvRealScalar(0.1)); //стандартный набор функций для фильтра кальмана CvKalman *kalman = cvCreateKalman(4, 2, 0); //4 переменных состояния, 2 переменных измерения float deltatime = 50.f; //приращение времени float transition_matrix[] = { 1, 0, deltatime, 0, 0, 1, 0, deltatime, 0, 0, 1, 0, 0, 0, 0, 1}; //transition matrix memcpy(kalman->transition_matrix->data.fl, transition_matrix, sizeof(transition_matrix)); cvSetIdentity(kalman->measurement_matrix, cvRealScalar(1)); cvSetIdentity(kalman->process_noise_cov, cvRealScalar(1e-5)); cvSetIdentity(kalman->measurement_noise_cov, cvRealScalar(1e-1)); cvSetIdentity(kalman->error_cov_post, cvRealScalar(1)); //выбираем случайное начальное состояние cvRandArr(&rng, kalman->state_post, CV_RAND_NORMAL, cvRealScalar(0), cvRealScalar(0.1)); cvNamedWindow("frame", 1); cvNamedWindow("color_segm", 1); cvNamedWindow("contours", 1); CvCapture *video = cvCaptureFromAVI("vid1.avi"); IplImage *mask = NULL; for (IplImage *frame = cvQueryFrame(video); frame; frame = cvQueryFrame(video)) { if (!mask) mask = cvCreateImage(cvSize(frame->width, frame->height), IPL_DEPTH_8U, 1); //находим положение шайбы, используя поиск по цвету region_color_range(frame, mask, bmin, bmax, gmin, gmax, rmin, rmax); cvShowImage("color_segm", mask); CvPoint2D32f position = findBigBlob(mask); cvShowImage("contours", mask); const CvMat *kalman_predict = cvKalmanPredict(kalman, 0); float predict_x = kalman_predict->data.fl[0]; float predict_y = kalman_predict->data.fl[1]; if (position.x < 0.0) { //уточняем используя предсказание measurement->data.fl[0] = predict_x; measurement->data.fl[1] = predict_y; } else { //уточняем, используя данные измерений measurement->data.fl[0] = position.x; measurement->data.fl[1] = position.y; } //Предсказанное и измеренное положение центра объекта cvDrawCircle(frame, cvPoint((int)position.x, (int)position.y), 3, cvScalar(255, 255, 255), -1, 8, 0); cvDrawCircle(frame, cvPoint((int)predict_x, (int)predict_y), 3, cvScalar(0, 0, 0), -1, 8, 0); //обновляем состояние фильтра cvKalmanCorrect(kalman, measurement); cvWaitKey(100); cvShowImage("frame", frame); } cvReleaseCapture(&video); if (mask) cvReleaseImage(&mask); cvDestroyWindow("frame"); cvDestroyWindow("color_segm"); cvDestroyWindow("contours"); return 0; } ////////////////////////////////////////////////////////////////////////////[/codebox]
  23. cvCreateImage пошаливает!

    У меня нормально проходит. Что именно говорит текст ошибки? Какая версия OpenCV?
  24. Отключить вывод ошибок

    Тут я ошибся, разумеется, надо менять на: #define CV_ERROR( Code, Msg ) {} По поводу cvd.lib, cxcored.lib - компилируй в Release.
×