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

executor

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

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

  • Посещение

  • Days Won

    2

executor last won the day on March 9 2011

executor had the most liked content!

Репутация

5 Новичек

О executor

  • Звание
    Новичок

Contact Methods

  • Website URL
    http://fluxrobotics.blogspot.com
  • ICQ
    0

Profile Information

  • Пол
    Не скажу
  • Расположение
    Kyiv
  • Интересы
    Programming, Space, Astronomy.
    Computer Graphics, Comp Vision, GPU computing, Robotics, Game development
  1. Попробуйте переустанавливать размер кадра после снятия первого кадра: CvCapture *cam = cvCreateCameraCapture(0); if (!cam) return 0; if (!cvQueryFrame(cam)) return 0; // снимаем первый кадр // lifecap studio = 1080p = 1920 x 1080 int desiredW = 1920; int desiredH = 1080; cvSetCaptureProperty(cam,CV_CAP_PROP_FRAME_WIDTH,desiredW); cvSetCaptureProperty(cam,CV_CAP_PROP_FRAME_HEIGHT,desiredH); if (!cvQueryFrame(cam)) return 0; // кадр после переустановки int retw = (int)cvGetCaptureProperty(cam,CV_CAP_PROP_FRAME_WIDTH); int reth = (int)cvGetCaptureProperty(cam,CV_CAP_PROP_FRAME_HEIGHT); if (!cvQueryFrame(cam)) return 0; // проверяем снова if (retw != desiredW || reth != desiredH) return 0;
  2. Здравствуйте, Virt. Не могу сказать, что я спец в отладке, но полезными мне кажутся такие инструменты: conditional breakpoint (вы задаете условие в брейкпоинте, и когда, например переменная достигает некоторой величины, - программа останавливается на этом брейкпоинте), variable watch (не всегда оно, правда, хорошо работает, особенно, когда переменная локальная и выполнение выходит за пределы функции). Часто использую вывод отладочной информации в заголовок окна или вывод текста в консоль на каждом шаге. Вы можете попытаться логить каждую секунду (или меньший интервал) в файлик, и на каждом этапе просматривать значения, при этом постоянно искать максимальные и минимальные значения за какой-то определенный период времени. Мне кажется интерактивные приложения, особенно, когда данные постоянно изменяются, очень сложно отлаживать. Возможно неплохо записать, например десяток "хороших" взмахов руки вверх и вниз, и несколько плохих взмахов (или неправильных перемещений, например, горизонтальных) в avi файл (или несколько avi на каждое движение), а затем провести, "унифицированный тест", и проследить за тем, чтобы реакция на этот тест вас устраивала (функция определяла движения, как движения, а на "шумы" не реагировала). min_trigging_amount я просто подбирал, когда взмахивал рукой, и искал значения (оно выводилось в консоль). Я заметил что реакция на взмах вниз на моей камере хуже идет чем взмах вверх. Поэтому, может быть, целесообразно разделить min_trigging_amount_down и min_trigging_amount_up. min_trigging_amount_down я бы поставил равным полтора min_trigging_amount_up. Тут может быть несколько вариантов. Например, что-то на подобии цифрового фильтра, при котором происходит сложная зависимость изменения переменных во времени, а также слежение, например за скоростью изменения величин и продолжительностью их изменения. Вы можете накапливать несколько параметров, например: количество движений общих движений и распознаных перемещений вверх и вниз, а также их "результирующее перемещение" за последние 0.5 (меньше минимальной длительности жеста), 1 (среднее время жеста) и 4 (больше среднего) секунд. После этого можно сказать следующее: если малый участок проверки "заполнен" а средний не заполнен - тогда это шум если малый заполнен, и средний заполнен, а больший не заполнен - тогда это (возможно) правильное перемещение (можно еще проверить, соблюдалась ли однонаправленность все три интервала времени) "заполнен" - это значит, что за все время сканирования перемещения система приняла решение что sum > trigging_value. также вы можете определять скорость перемещения характерных точек за некоторое время (в процентах видимого пространства, то есть например если точка уехала на 30%, - это хороший показатель для определения жеста, а 70% - это человек просто поднялся и ушел (например) ) если вы, например, сможете записывать траекторию перемещения признаков по трем точкам (или больше), и отслеживать, чтобы эта ломаная (состоящая из трех точек) имела угол раскрытия (например) < 140-150 градусов - значит движение было "относительно" однонаправленно. Скорее всего, придется подбирать несколько ключевых коэффициентов вручную. Если вы хотите, например, автоматизировать процесс, т.е. обучить систему на взмахи каждого человека индивидуально, то можно было-бы обучить нейронную сеть (даже один слой, нелин. активационная функция). На её входы подавать: <sum, total, up, down, sum1, total1, up1, down1, чувствиельность>, (sum - сумма за последние 0.5 секунд, sum1 - за всю последнюю 1.0 секунду, например), а на выходе единственное значение (float) - коэффициент соответстивя и его знак, например (у нейросети обычно выходы от 0 до 1 (однополярный) или -0.5 ..0.5 (биполярный сигмоид): 0..0.3 - нет движения + шумы, 0.4-0.99 - пользователь оценил движение как "хоршее" и насколько "хорошее". Нейронная сеть, в данном случае лишь метод автоматического подбора коэффициентов. Писать код нейронной сети (и её обучения) часто не приходится, есть библиотеки FANN, Flood (http://www.cimne.com/flood/). Если вас интересует, я бы мог расписать более подробно, как я вижу эту задачу с подхода нейросетей.
  3. Стерео зрение

    При подаче в функцию cvInitUndistortRectifyMap (вы же ректифицируете изображение?), четвертый параметр - матрица NewCameraMatrix для правой камеры, т.е. "M2". Она содержит все недостающие величины. Я так понимаю, в вашем примере, эта матрица тоже рассчитывается подобно тому как в книге (в коде на примере) стр 450 внизу (после "OR ELSE HARTLEY'S METHOD, ... , compute the rectification transformation directly ... "). Вот как выглядит матрица Q у меня. (моя предыдущая теоретическая имела C1 и C2 равные 0). У меня f = 5.84*10^2, C1 = 3.11*10^2, C2 = 2.41*10^2, Tx = 0.118 Вот написал функцию, которая принимает матрицу 4 параметра cvInitUndistortRectifyMap и расстояние между камерами в метрах, и возвращает double_1channel матрицу Q (возвращаемая ею матрица у меня полностью совпала с откалиброванной Q из StereoCalibrate() по выводу в xml). // vM2_right - та же что и 4 параметр cvInitUndistortRectifyMap для правой камеры // т.е. new_camera_matrix правой камеры CvMat * CreateArtificialMatQ(CvMat *vM2_right, double Tx) { // находим нужные величины из матрицы правой камеры vM2 double f = CV_MAT_ELEM(*vM2_right,double,0,0); double C1 = CV_MAT_ELEM(*vM2_right,double,0,2); double C2 = CV_MAT_ELEM(*vM2_right,double,1,2); // заполняем правильно элементы матрицы CvMat *MatQ_artificial = cvCreateMat(4,4,CV_64FC1); cvZero(MatQ_artificial); CV_MAT_ELEM(*MatQ_artificial,double,0,0) = 1; CV_MAT_ELEM(*MatQ_artificial,double,1,1) = 1; CV_MAT_ELEM(*MatQ_artificial,double,0,3) = -C1; CV_MAT_ELEM(*MatQ_artificial,double,1,3) = -C2; CV_MAT_ELEM(*MatQ_artificial,double,2,3) = f; CV_MAT_ELEM(*MatQ_artificial,double,3,2) = -1.0/Tx; return MatQ_artificial; } Но я не могу пока-что проверить будет ли она правильно работать на cvStereoRectifyUncalibrated.
  4. Сделал распознавание по своему более простому чем у вас алгоритму. По-моему у вас переставлен up++ и down++. По упрощенному алгоритму будет хуже результат (там общее направление движения (sum) / суммарное кол-во движений (total) > некоторого порога (min_trigging_amount) ) - тогда есть движение. Взмах руки детектируется у меня уже, пишет вверх или вниз, но я закомментил много вашего кода. См. вложение. P.S.: мне кажется, ваш алгоритм рассчитан на большее кол-во Features в движении (ваш all), чем удается извлечь из кадра... P.P.S.: почитал внимательно ваш алгоритм, у вас похоже просто слишком высокое требование к (double)up / total > 0.4. У меня из 45 признаков до 10 на одно движение (up или down) получается (а часто и вовсе до 6). Думаю к total (или all, по-вашему) стоит добавлять только линии длинны больше некоторой минимально определенной, а у вас эта переменная равна, по сути, corner_count. Main_v2.zip
  5. В прикрепленном файле, в целом скорость чуть поднял (в 2-4 раза), изменял размеры блоков, кол-во Features. В функции FindMotion вы каждый раз выделяете память под множество изображений динамически, а затем её удаляете, хотя это и не сильно ухудьшает её скорость. Лучше сделать "ленивое" выделение памяти (использовать статик, использовать все изображения в классе с деструктором, или другой, более щадящий менеджер памяти ОС подход) или InitFound, ReleaseFound функции, либо лучше обернуть функцию в класс, тогда она будет потокобезопасной. Ну и третье что менял, - это кол-во итераций и эпсилон. Еще у вас c = cvWaitKey(1); ждет аж 33 мсек, хотя каждый кадр у вас и так прилично обрабатывается по времени. Может кто еще что-то подскажет. Main.zip
  6. Стерео зрение

    Здравствуйте, RinOS. Рекомендую все-таки использовать cvStereoRectify() т.к. результат его работы более точен, а cvStereoRectifyUncalibrated() лучше использовать когда существуют значительные непараллельности в оптических осях камер, насколько я понимаю. Критерием правильности калибровки стерео может служить правильное число в векторе T (который означает расстояние между оптическими осями по оси x, y и z) камер. У меня, при расстоянии между камерами 12 см, и 29 калибровочных пар изображений 640х480 в оттенках серого (изображения я сохраняю предварительно в bmp, чтобы каждый раз не мучаться с их показом камерам) величина составляет: цитирую xml содержимое <data>-1.1886876922892217e-001 -7.8263643755714435e-004 -4.6620003758508491e-003</data>, (все величины в метрах - первая величина - это сдвиг по оси X, то есть расстояние между камерами). То есть 1.6 %, что может быть точнее измерянного мною расстояния. Чем шире расстояние между камерами, тем лучше будет восприятие на более дальних расстояниях, и тем хуже будет поле зрения камеры, при обзоре близких предметов. Для того чтобы величина вектора T содержала метрические величины, необходимо, чтобы вы правильно (в метрических единицах) указали размер клеточки при калибровке. В книге learning OpenCV, в примере стерео (стр 445), есть константа squareSize, у меня в коде примерно так (размер клетки 3 см): float chesbSquareSize = 0.030f; // 30 mm is a Square size for (size_t pair_idx = 0; pair_idx < boards_count; pair_idx++) { for (size_t i=pair_idx*board_n,j = 0;j < board_n; ++i,++j) { // Chessboard points CV_MAT_ELEM(*image_pointsL,float,i,0) = vCalibData[IMG_LEFT][pair_idx].vPoints[j].x; CV_MAT_ELEM(*image_pointsL,float,i,1) = vCalibData[IMG_LEFT][pair_idx].vPoints[j].y; CV_MAT_ELEM(*image_pointsR,float,i,0) = vCalibData[IMG_RIGHT][pair_idx].vPoints[j].x; CV_MAT_ELEM(*image_pointsR,float,i,1) = vCalibData[IMG_RIGHT][pair_idx].vPoints[j].y; // Linear space remapping points CV_MAT_ELEM(*object_points,float,i,0) = (float)(j/w) * chesbSquareSize; CV_MAT_ELEM(*object_points,float,i,1) = (float)(j%w) * chesbSquareSize; CV_MAT_ELEM(*object_points,float,i,2) = 0; }; CV_MAT_ELEM(*point_counts,UINT,pair_idx,0) = (UINT)board_n; }; Откалиброванные матрицы удобно сохранять в xml. Для того, чтобы калибровка была корректной, рекомендуют использовать "шахматную доску" с не одинаковым кол-вом клеток по ширине и высоте (я заметил вы такую и использовали). Для улучшения качества BlockMatcher'а, попробуйте BMState->uniquenessRatio = 0; Привожу мои рабочие параметры: BMState->preFilterSize = 17; BMState->preFilterCap = 31; BMState->SADWindowSize = 11; BMState->minDisparity = 13; BMState->numberOfDisparities = 256; BMState->textureThreshold = 35; BMState->uniquenessRatio = 0; Искомую матрицу репроекции Q вы можете заполнить вручную по формуле Q= стр 435 Learn OpenCV, используя ранее вычисленные матрицы: CameraMatrix и T, например.. но мне кажется это сложный путь, и ... некоторые величины (f, n) придется выдумывать. Вот набросал матрицу, которую вы можете использовать, подставив лишь расстояние между объективами камер: Но я не уверен, что она даст для вас точный и качественный результат. f можно уменьшить вовсе до 5 метров. Если вы вызовете cvStereoRectify() то наверняка ничего не потеряете, по книге инных вариантов не приводится. Матрицу Q нельзя извлечь из cvStereoRectifyUncalibrated() поскольку (стр 431): То есть, теоретически, если вы при калибровке, задавали реальные метрические координаты (с помощью размера) ваших клеточек, то на выходе ReprojectTo3D проекции получите реальные размеры и расстояния до объекта в метрах. Насколько я понимаю, disparityImage должен быть Float(существует быстрый вариант с Int). Подавать нужно disparityImage не нормализованный. Репроекцией еще сам не занимался, поэтому грабли раскрыть в этой теме пока не могу (может на этих выходных, тогда я бы отписался здесь). Прикрепляю свою шахматную доску (visio), может пригодится.
  7. Попробуйте принудительно ставить индексы камерам: CvCapture *CaptureLeft = cvCaptureFromCAM(0); Sleep(1000); // cvWaitKey(1000); CvCapture *CaptureRight = cvCaptureFromCAM(1); // и так далее Зеленого экрана быть не должно. Поищите, может какой-то баг в программе другой? У меня Philips spc2050nc две камеры. Они иногда не хотят вместе работать, приходится компьютер перезагружать, и камеры в нужном порядке вставлять в USB с задержкой в пару секунд. Попробуйте проверить не нулевость CvCapture* для второй камеры, получить размер изображения второй камеры: int width2 = (int)cvGetCaptureProperty(CaptureRight,CV_CAP_PROP_FRAME_WIDTH); int height2 = (int)cvGetCaptureProperty(CaptureRight,CV_CAP_PROP_FRAME_HEIGHT); или растолкать камеру (считать размер кадра, получить пару кадров, задержка, записать новый размер кадра, задержка, получить пару кадров).
×