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

Фотография

Программирование на квадрокоптере AR.Drone


  • Авторизуйтесь для ответа в теме
Сообщений в теме: 187

#141
erbol

erbol
  • Читатель
  • 361 сообщений

Видео полета команды Robodem

http://www.youtube.c...h?v=lZ1qMFPPiY4

и алгоритм полета


На самом деле, как таковой навигации, в классическом понимании, у нас практически не было. Мы проходим сей "лабиринт", подобно человеку, который идёт вперёд по коридору и ему неинтересно знать где север, где юг и в скольких метрах находится его цель. Он просто шагает прямо, стараясь не биться головой об стены и поворачивает когда видит поворот. Всё что мы позволили нашим алгоритмам знать о полигоне, это то что летя "вперёд", надо поворачивать налево, летя "назад", направо, а ширина коридора примерно 4-5 метров. И вот почему:

1) Сделать правильный алгоритм осмотра стен, а делаем мы это исключительно ко камере, к нашему сожалению, мы не успели. Правильно было бы смотреть по сторонам и выбирать проход, куда можно пролететь. Вместо этого, что-бы уложиться в сроки, мы сделали правило левой и правой руки, меняя его при каждой посадке. За что, собственно, и были наказаны дополнительными двумя посадками, пусть и, как я понял по реакции публики, довольно зрелищными. Увидев на обратном пути перегородку и придерживаясь правила правой руки, дрон решил что это поворот и повернул направо, увидев стенку снова, ещё раз, а дальше полетел прямо по коридору, где нас ожидал уже посещённый нами крест. Сев и взлетев, мы полетели по правилу левой руки, поворачивая налево, что было видно в самом конце прохождения поворота. Наконец то после третьей посадки опять включилось правило правой руки и преодолев препятствие мы полетели правильно.

2) У нас не было подходящего пространства похожего на полигон. Так же, левая стена полигона состояла из пено-блоков и давала помехи из линий между ними. Эти линии вполне походили на границу пола на некотором отдалении от нас. Тогда мы решили ограничить выбор расстояния между прямыми, формирующих коридор, расстояниями равными реальным размерам полигона, то есть, ~4 метра.

В остальном, наш дрон просто летел прямо и поворачивал когда перед ним была стена, а при виде креста, с удовольствием совершал на него посадку.

http://forum.rcdesig...d291488-51.html



#142
erbol

erbol
  • Читатель
  • 361 сообщений

Robodem , поздравляю !!!



#143
erbol

erbol
  • Читатель
  • 361 сообщений

Дисторсия

http://ru.wikipedia.org/wiki/Дисторсия

Калибровка камеры

http://ru.wikipedia....либровка_камеры

11.3 Удаление искажений

http://locv.ru/wiki/...ление_искажений



#144
erbol

erbol
  • Читатель
  • 361 сообщений
Для того чтобы выполнить калибровку камеры обычно используют рисунок шахматной доски. 
 
Функция поиска углов шахматной доски
 
int cvFindChessboardCorners( 
const void* image, 
CvSize pattern_size, 
CvPoint2D32f* corners, 
int* corner_count = NULL, 
nt flags = CV_CALIB_CB_ADAPTIVE_THRESH
);
Эта функция принимает в качестве аргумента одно изображение, содержащее шахматную доску. Это изображение должно быть 8-битным в оттенках серого (один канал) изображением. Второй аргумент, pattern_size, показывает, сколько углов в каждой строке и столбце доски. Это счетчик числа внутренних углов; таким образом, для стандартной настольной игры шахматы правильное значение будет cvSize(7,7).* Следующий аргумент, углы, является указателем на массив, в котором могут быть записаны расположения углов. Этот массив должен быть предопределенным и, конечно же, должен быть достаточно большим для всех углов на доске (49 на стандартных шахматах). Отдельные значения - это расположения углов в пиксельных координатах. Corner_count аргумент не является обязательным; если не-нулевой, это указатель на целое число, где число найденных углов может быть записано. Если функция успешно нашла все углы,† то возвращаемым значением будет ненулевым числом. Если функция завершается ошибкой, то будет возвращен 0. Последний аргумент flags могут быть использованы для реализации одного или нескольких дополнительных шагов фильтрации, чтобы помочь найти углы на шахматной доске. Любые или все аргументы могут быть объединены с помощью логического OR.
 
 
Параметры
CV_CALIB_CB_ADAPTIVE_THRESH
Поведение по умолчанию cvFindChessboardCorners () является первым порогом изображения на основе средней яркости, но если этот флаг установлен, то будет использоваться адаптивный порог.
CV_CALIB_CB_NORMALIZE_IMAGE
Если установлен этот флаг вызывается изображение, которое будет нормировано через cvEqualizeHist() до порога применяемости.
CV_CALIB_CB_FILTER_QUADS
Как только на рисунке установлены пороги, алгоритм пытается найти четырехугольники в результате перспективного вида черных квадратов на шахматной доске. Это приближение, согласно которому линии каждого ребра четырехугольника считаются прямыми, не совсем верно, когда есть радиальные искажения в изображение. Если этот флаг установлен, то различные дополнительные ограничения применяются к тем, четырехугольникам для того, чтобы отклонить ложные четырехугольники.
 
 
При отладке, часто желательно нарисовать найденные шахматной доски углы на изображении (обычно изображение, которое мы использовали для вычисления углы в первую очередь); таким образом, мы можем видеть прогнозируемые углы совпадают ли с наблюдаемыми углами. С этой целью OpenCV предоставляет удобную процедуру для решения этой общей задачи. Функция cvDrawChessboardCorners() рисует углы, найденные cvFindChessboardCorners() на изображениях, которые вы предоставляете. Если не все углы были найдены, имеющиеся углы будут представлены как маленькие красные круги. Если вся картина была найдена, то углы будут окрашены в разные цвета (каждая строка будет иметь свой собственный цвет) и связанны линиями, представляющими в порядке выявленных углов.
 
void cvDrawChessboardCorners(
CvArr* image,
CvSize pattern_size,
CvPoint2D32f* corners,
int count,
int pattern_was_found 
);
Первый аргумент cvDrawChessboardCorners() это изображение, на котором будет сделан рисунок. Потому что углы будут представлены как цветные круги, это должно быть 8-битное цветное изображение, в большинстве случаев, это будет копия изображения, которое вы дали cvFindChessboardCorners() (но вы должны преобразовать его в трех канальное изображение собственно). Следующие два аргумента, pattern_size и cornersv, такие же, как соответствующие аргументы для cvFindChessboardCorners(). Количество аргументов целое число, равное количеству углов. Наконец, аргумент pattern_was_found указывает, что во входной шахматной доске была успешно найдена структура, это может быть установлено на значение, возвращаемое cvFindChessboardCorners().
 


#145
erbol

erbol
  • Читатель
  • 361 сообщений

В качестве шаблона для калибровки видеокамеры используем рисунок типа "шахматная доска"

Для распечатки используем прикрепленный файл. Распечатываем рисунок на лист A4

Прикрепленные файлы

  • Прикрепленный файл  pattern_7x10.pdf   447,36К   Количество загрузок: 173


#146
erbol

erbol
  • Читатель
  • 361 сообщений

Результат выполнения калибровки видеокамеры помещаем в файл с расширением xml

Он содержит данные о двух матрицах

Матрице intrinsic (размерность 3*3) и матрице distortion (размерность 1*4)

Вот содержимое этого файла

<?xml version="1.0"?>
<opencv_storage>
<intrinsic type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>f</dt>
  <data>
    5.63349854e+002 0. 3.24438904e+002 0. 5.65041321e+002
    1.64898773e+002 0. 0. 1.</data></intrinsic>
<distortion type_id="opencv-matrix">
  <rows>1</rows>
  <cols>4</cols>
  <dt>f</dt>
  <data>
    -5.51602602e-001 3.91032815e-001 -1.13318418e-003 2.73855217e-003</data></distortion>
</opencv_storage>


#147
erbol

erbol
  • Читатель
  • 361 сообщений
Процедура калибровки следующая
 
1. Включаем drone
2. Подключаем компьютер к сети drone
3. Запускаем программу на С++
4. На экране получаем сообщение - Press space key to take a sample picture !
5. Направляем горизонтальную камеру drone на картинку с шахматной доской, так чтобы она вся помещалась в ней. Жмем клавишу пробел для получения снимка с параметрами
6. Меняем расположение drone относительно картинки и снова делаем снимок. Делаем около двадцати снимков
7. Жмем клавишу escape. Программа сохраняет вычисленные параметры калибровки в файл camera.xml
 
Вот код программы из проекта Puku cvdrone
 
#include 
 
 
 
// Parameter for calibration pattern
// Параметы для калибровочного шаблона
#define PAT_ROW    (7)                  // Rows of pattern
#define PAT_COL    (10)                 // Columns of pattern
#define PAT_SIZE   (PAT_ROW*PAT_COL)
#define CHESS_SIZE (24.0)               // Size of a pattern [mm]
 
// --------------------------------------------------------------------------
// cvDrawText(Image, Drowing point, Messages)
// Description  : Draw the specified text.
// Return value : NONE
// --------------------------------------------------------------------------
inline void cvDrawText(IplImage *image, CvPoint point, const char *fmt, ...)
{
    // Font
    static CvFont font = cvFont(1.0);
 
    // Apply format
    char text[256];
    va_list ap;
    va_start(ap, fmt);
    vsprintf(text, fmt, ap);
    va_end(ap);
 
    // Draw the text
    cvPutText(image, text, point, &font, cvScalarAll(255));
}
 
// --------------------------------------------------------------------------
// cvAsk(Message)
// Description  : Show a question.
// Return value : NO:0 YES:1
// --------------------------------------------------------------------------
inline int cvAsk(const char *message, ...)
{
    char *arg;
    char str[256];
 
    // Apply format
    va_start(arg, message);
    vsprintf(str, message, arg);
    va_end(arg);
 
    // Show message box
    return (MessageBox(NULL, str, "QUESTION", MB_YESNO|MB_ICONQUESTION|MB_TOPMOST|MB_SETFOREGROUND) == IDYES);
}
 
 
// --------------------------------------------------------------------------
// main(Number of arguments, Argument values)
// Description  : This is the entry point of the program.
// Return value : SUCCESS:0  ERROR:-1
// --------------------------------------------------------------------------
int main(int argc, char **argv)
{
    // AR.Drone class
    ARDrone ardrone;
 
    // Initialize
    if (!ardrone.open()) {
        printf("Failed to initialize.\n");
        return -1;
    }
 
    // Images
    std::vector<IplImage*> images;
    printf("Press space key to take a sample picture !\n");
 
    // Main loop
    while (1) {
        // Key input
        int key = cvWaitKey(1);
        if (key == 0x1b) break;
 
        // Update
        if (!ardrone.update()) break;
 
        // Get an image
        IplImage *image = ardrone.getImage();
 
        // If you push Space key
        if (key == ' ') {
            // Convert the camera image to grayscale
            IplImage *gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
            cvCvtColor(image, gray, CV_BGR2GRAY);
 
            // Detect the chessboard
            int corner_count = 0;
            CvSize size = cvSize(PAT_COL, PAT_ROW);
            CvPoint2D32f corners[PAT_SIZE];
            int found = cvFindChessboardCorners(gray, size, corners, &corner_count);
 
            // Detected
            if (found) {
                // Draw corners.
                cvDrawChessboardCorners(image, size, corners, corner_count, found);
 
                // Add to buffer
                images.push_back(gray);
                Beep(3000, 100);
printf("Good\n");
/*
BOOL Beep
(
DWORD dwFreq, // звуковая частота
DWORD dwDuration // длительность звучания
);
 
Beep(440, 100);
440 -- частота
100 -- длительность (миллисекунды)
 
У ноты "Ля", например, частота 440 Гц.
 
*/
 
            }
            // Failed to detect
            else {
                // Release the image
// освобождаем ресурсы
                cvReleaseImage(&gray);
                Beep(100, 100);
printf("Bad\n");
            }
        }
 
        // Display the image
        cvDrawText(image, cvPoint(15, 20), "NUM = %d", (int)images.size());
        cvShowImage("camera", image);
    }
 
    // Destroy the window
    cvDestroyWindow("camera");
 
    // At least one image was taken
    if (!images.empty()) {
        // Total number of images
        const int num = (int)images.size();
 
        //// For debug
        //for (int i = 0; i < num; i++) {
        //    char name[256];
        //    sprintf(name, "images[%d/%d]", i+1, num);
        //    cvShowImage(name, images[i]);
        //    cvWaitKey(0);
        //    cvDestroyWindow(name);
        //}
 
        // Ask save parameters or not
        if (cvAsk("Do you save the camera parameters ?\n")) {
            // Detect coners
            int *p_count = (int*)malloc(sizeof(int) * num);
            CvPoint2D32f *corners = (CvPoint2D32f*)cvAlloc(sizeof(CvPoint2D32f) * num * PAT_SIZE);
            for (int i = 0; i < num; i++) {
                // Detect chessboard
                int corner_count = 0;
                CvSize size = cvSize(PAT_COL, PAT_ROW);
                int found = cvFindChessboardCorners(images[i], size, &corners[i * PAT_SIZE], &corner_count);
 
                // Convert the corners to sub-pixel
                cvFindCornerSubPix(images[i], &corners[i * PAT_SIZE], corner_count, cvSize(3, 3), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_ITER|CV_TERMCRIT_EPS, 20, 0.03));
                p_count[i] = corner_count;
            }
 
            // Set the 3D position of patterns
            CvPoint3D32f *objects = (CvPoint3D32f*)cvAlloc(sizeof(CvPoint3D32f) * num * PAT_SIZE);
            for (int i = 0; i < num; i++) {
                for (int j = 0; j < PAT_ROW; j++) {
                    for (int k = 0; k < PAT_COL; k++) {
                        objects[i * PAT_SIZE + j * PAT_COL + k].x = j * CHESS_SIZE;
                        objects[i * PAT_SIZE + j * PAT_COL + k].y = k * CHESS_SIZE;
                        objects[i * PAT_SIZE + j * PAT_COL + k].z = 0.0;
                    }
                }
            }
 
            // Create matrices
            CvMat object_points, image_points, point_counts;
            cvInitMatHeader(&object_points, num * PAT_SIZE, 3, CV_32FC1, objects);
            cvInitMatHeader(&image_points,  num * PAT_SIZE, 1, CV_32FC2, corners);
            cvInitMatHeader(&point_counts,  num,            1, CV_32SC1, p_count);
 
            // Estimate intrinsic parameters and distortion coefficients
            printf("Calicurating parameters...");
            CvMat *intrinsic   = cvCreateMat(3, 3, CV_32FC1);
            CvMat *distortion  = cvCreateMat(1, 4, CV_32FC1);
            cvCalibrateCamera2(&object_points, &image_points, &point_counts, cvGetSize(images[0]), intrinsic, distortion);
            printf("Finished !\n");
 
            // Output a file
            printf("Generating a XML file...");
            CvFileStorage *fs = cvOpenFileStorage("camera.xml", 0, CV_STORAGE_WRITE);
            cvWrite(fs, "intrinsic", intrinsic);
            cvWrite(fs, "distortion", distortion);
            cvReleaseFileStorage(&fs);    
            printf("Finished !\n");
 
            // Release the matrices
            free(p_count);
            cvFree(&corners);
            cvFree(&objects);
            cvReleaseMat(&intrinsic);
            cvReleaseMat(&distortion);
        }
 
        // Release the images
        for (int i = 0; i < num; i++) cvReleaseImage(&images[i]);
    }
 
    // See you
    ardrone.close();
 
    return 0;
}
 


#148
erbol

erbol
  • Читатель
  • 361 сообщений
А вот каким образом используется информация в файле для коррекции картинки получаемой с drone
 
 
#include "ardrone/ardrone.h"
 
int main(int argc, char **argv)
{
    // AR.Drone class
    ARDrone ardrone;
 
    // Initialize
    if (!ardrone.open()) {
        printf("Failed to initialize.\n");
        return -1;
    }
 
    // Image of AR.Drone's camera
    IplImage *image = ardrone.getImage();
 
    // Read intrincis camera parameters
    CvFileStorage *fs = cvOpenFileStorage("camera.xml", 0, CV_STORAGE_READ);
    CvMat *intrinsic = (CvMat*)cvRead(fs, cvGetFileNodeByName(fs, NULL, "intrinsic"));
    CvMat *distortion = (CvMat*)cvRead(fs, cvGetFileNodeByName(fs, NULL, "distortion"));
 
    // Initialize undistortion maps
    CvMat *mapx = cvCreateMat(image->height, image->width, CV_32FC1);
    CvMat *mapy = cvCreateMat(image->height, image->width, CV_32FC1);
    cvInitUndistortMap(intrinsic, distortion, mapx, mapy);
 
    // Main loop
    while (1) {
        // Key input
        int key = cvWaitKey(1);
        if (key == 0x1b) break;
 
        // Update
        if (!ardrone.update()) break;
 
        // Get an image
        image = ardrone.getImage();
 
        // Remap the image
        cvRemap(image, image, mapx, mapy);
 
        // Display the image
        cvShowImage("camera", image);
    }
 
    // Release the matrices
    cvReleaseMat(&mapx);
    cvReleaseMat(&mapy);
    cvReleaseFileStorage(&fs);
 
    // See you
    ardrone.close();
 
    return 0;
}
 


#149
erbol

erbol
  • Читатель
  • 361 сообщений
Вот еще одна интересная задача. Допустим на картинке видим фигуру. Надо найти ее центр (например центр посадочной площадки в виде креста)
 
 
Задача (наипростейшая).
Дано: лист бумаги, на котором нарисованы черные (может быть и серые) круги.
Найти: Найти эти круги.
 
1. Представьте что мы случайно тыкаем в лист бумаги датчиком, который дает нам значение яркости (вероятности на самом деле) в точке, куда мы ткнули.
2. Вначале мы тыкаем по всему листу равномерно. Иногда натыкаемся на темные точки.
3. Эти темные точки ставим более жирными. Тыкаем так в лист 1000 раз (1000 частиц).
 
4. Находим взвешенную плотность точек. То есть суммируем точки (допустим обычные белые точки имеют вес 0.1 , а точки попавшие на черное 1, серые дают промежуточный вес). В результате получим уплотнение там, где расположены темные области, но мы должны их найти более точно. Нормируем, получаем распределение вероятности для следующих тыканий.
 
5. Дальше тыкаем датчиком не равномерно, а в соответствии с полученным ранее распределением. Тыкаем еще 1000 раз. И т.д.
 
У Puku в проекте cvdrone этот алгоритм тоже реализован в файле sample_condens_tracking
 
Функции CvConDensation и cvCreateConDensation описаны здесь


#150
erbol

erbol
  • Читатель
  • 361 сообщений

Картинка с горизонтальной камеры drone до калибровки. Видно что изображение бочкообразное

 

gallery_10467_19593_196711.png

 

Картинка после калибровки камеры

 

gallery_10467_19593_182656.png



#151
erbol

erbol
  • Читатель
  • 361 сообщений

Из работающих алгоритмов видеораспознавания меток и выработки реакции на них пока только две штуки

 

1. Первый алгоритм. Метка - белая полоса на черной. Drone увидев полосу через вертикальную камеру тормозит и останавливается

 

2. Второй алгоритм. Та же метка. Drone пролетая через нее обнуляет координату х вектора перемещения. Вектор перемещения рассчитывается как произведение интервала времени на текущую скорость. Текущую скорость берем через навигационные данные получаемые с drone. Временной интервал рассчитываем



#152
erbol

erbol
  • Читатель
  • 361 сообщений

Внимание, набираю команду для участия в соревнованиях типа "Летающие роботы"

 

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

 

Используемое устройство - AR.Drone 2.0

ПО - Visual C++ и и проект Puku

 

Условия конкурса http://www.robots.croc.ru/about/

 

Обсуждение различных проблем связанных с проведением конкурса

 

http://forum.rcdesig...read291488.html

 

Мои темы связанные с программированием летающих роботов

 

http://forum.fpv.kz/topic/27/



#153
erbol

erbol
  • Читатель
  • 361 сообщений

Трекинг объектов

http://robocraft.ru/...c.php?f=7&t=425






#154
erbol

erbol
  • Читатель
  • 361 сообщений

Фильтр_Калмана
Фильтр Кальмана. Постановка задачи

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

Данные о текущей скорости поступают с датчика дискретно, через одинаковый интервал времени. Измерения скорости тела неточные. Закон распределения вероятностей значений измеренной скорости тела относительно истинной скорости тела пусть соответствует стандартному нормальному Гауссову распределению  с математическим ожиданием 0 и стандартным отклонением 1.

http://ru.wikipedia....е_распределение
http://ru.wikipedia....множение_матриц

Тогда состояние тела в любой момент дискретный времени (через 0,1, 2,... сек после старта) определятся с помощью двух чисел - координаты тела на прямой и скоростью. Зная изменение скорости за интервал времени можно найти ускорение.  

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

Формула для расчета координаты

dx = v*dt + a*dt^2/2
x = x0 + dx

--------------------------

Вот просто отличная статья Малинникова про фильтр Кальмана

http://malinnikov.ru...a/#comment-2012

--------------------------

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

1. Если точность линеек одинаковая тогда результат измерений будет равен среднему арифметическому двух измерений. Пусть например при измерении отрезка первой линейкой результат равен 5,5 см , а при измерении второй линейкой результат равен 5,7 см. Тогда среднее значение результата равно 5,6 см.

2. Если точность измерений разная тогда меняется значение среднеквадратичного отклонения. Пусть одна линейка дает точный результат, а вторая врет. Тогда результат измерений будет равен измерению точной линейки и не будет зависеть от результата измерений неточной линейки.

Я хотел логический вывод придумать для общего случая разных сигм (среднеквадратичных отклонений) , но не получилось. Так что просто буду пользоваться формулой которая использована в публикации Малинникова

Для дисперсии результата по двум измерениям с помощью разных инструментов имеем

new_var = 1 / (1 / var1 + 1 / var2)


Для среднего значения

new_mean = (var2 * mean1 + var1 * mean2) / (var1 + var2)

gallery_10467_19593_43103.png

Первому инструменту и результату измерения соответствует синее распределение. Второму - красное. Результат - график с зеленой линией .



#155
erbol

erbol
  • Читатель
  • 361 сообщений

Робот строит карту лабиринта

 


Сообщение отредактировал erbol: 16.09.2013, 12:50:58


#156
erbol

erbol
  • Читатель
  • 361 сообщений

Отчет об участии команды Robodem в соревнованиях летающих роботов компании КРОК. 

 

http://habrahabr.ru/post/193304/



#157
erbol

erbol
  • Читатель
  • 361 сообщений
Вот пример реализации фильтра Кальмана из видеокурса на C++
 
 
#include <stdio.h>
 
 
void update(double& mean1, double& var1, double& mean2, double& var2)
{
mean1 = (var2 * mean1 + var1 * mean2) / (var1 + var2);
var1 = 1/(1/var1 + 1/var2);
}
 
void predict(double& mean1, double& var1, double& mean2, double& var2)
{
mean1 = mean1 + mean2;
var1 = var1 + var2;
}
 
 
int main(int argc, char **argv)
{
double mean1[5] = {5, 6, 7, 9, 10};
double mean2[5] = {1, 1, 2, 1, 1};
double measurement_sig = 4;
double motion_sig = 2;
double mean = 0;
double m_sig = 10000;
 
for (int i = 0; i < 5; i ++ ){
update(mean, m_sig, mean1[i], measurement_sig);
printf("update: mean = %3.18f, m_sig = %3.18f\n", mean, m_sig);
predict(mean, m_sig, mean2[i], motion_sig);
printf("predict: mean = %3.18f, m_sig = %3.18f\n", mean, m_sig);
 
}
 
 
}
 
 


#158
erbol

erbol
  • Читатель
  • 361 сообщений

Вот алгоритм нахождения "точки схода" из статьи 

 

http://dasl.mem.drex...rs_and_hallways

 

Шаг 1: Обнаружение линий в кадре
Шаг 2: Находим наклон линии
Шаг 3: Используя фильтр наклона линий избавляемся от горизонтальных и вертикальных линий.
Шаг 4: Оставляем только диагональные линии
Шаг 5: Расчет пересечения диагональных линий.
Шаг 6: Выбираем точку с наибольшим количеством пересечений - "точку схода"



#159
erbol

erbol
  • Читатель
  • 361 сообщений
Относительно параметров функции cvGoodFeaturesToTrack
 
Первые три параметра - картинки одноканальные. Первый параметр - исходная картинка на которой находится анализируемое изображение
 
corners это массив 32-битных точек (CvPoint2D32f), который содержит выбранные точки после того как функция закончит свою работу. Нужно выделить память под этот массив перед запуском cvGoodFeaturesToTrack().
 
corner_count указывает макс. количество точек которые будут возвращены. После выхода из функции corner_count перезаписывается числом найденных углов (точек).
 
qualityLevel - параметр, характеризующий качество отобранных из картинки точек.Например если лучшая точка имеет качество измерения = 1500, а qualityLevel = 0,01 , то все точки с показателем качества менее 15 отклоняются.
 
minDistance - Минимально возможное евклидово расстояние между возвращенными точками.
 
block_size - размер среднего блока для вычисления производной матрицы ковариации над каждым пикселем


#160
erbol

erbol
  • Читатель
  • 361 сообщений

Постановка.

Пусть имеется многоугольник.

gallery_10467_19172_2021.png
Рис. 1

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

Функция ищет на рисунке точки которые лежат в вершине углов. Линии соединяющие вершины если они не строго вертикальны или горизонтальны тоже состоят из углов


gallery_10467_19172_334.png
Рис. 2

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

1. Качественные точки получаются при условии что лучи угла являются вертикальными или горизонтальными линиями

gallery_10467_19172_218.png
Рис. 3

Это результат поиска точек функцией при следующих значениях параметров

cvGoodFeaturesToTrack(prev, eig_img, tmp_img, corners1, &corner_count, 0.99, 4.0, NULL, 3, 0, 0.4);

то есть параметр quality_level равен 0.99

С картинкой изображенной на рис. 3 проблем при поиске "особых точек" не возникает. На всем интервале значений параметра quality_level от 0.99 до 0.01 отбираются только точки лежащие в вершинах прямоугольников. 

Для многоугольника у которого вертикальные стороны имеют наклон 10 градусов имеем

gallery_10467_19172_5173.png
Рис. 4

cvGoodFeaturesToTrack(prev, eig_img, tmp_img, corners1, &corner_count, 0.81, 4.0, NULL, 3, 0, 0.4);

quality_level равен 0.81

gallery_10467_19172_3232.png

Рис. 5

quality_level равен 0.99


gallery_10467_19172_8160.png

Рис. 6

quality_level равен 0.5


gallery_10467_19172_1385.png

Рис. 7

quality_level равен 0.1




Количество пользователей, читающих эту тему: 4

пользователей: 0, неизвестных прохожих: 4, скрытых пользователей: 0

Размещение рекламы на сайте     Предложения о сотрудничестве     Служба поддержки пользователей

© 2011-2022 vse.kz. При любом использовании материалов Форума ссылка на vse.kz обязательна.