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

Фотография

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


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

#161
erbol

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


Сообщение отредактировал erbol: 04.10.2013, 14:45:57


#162
erbol

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

Как прошел конкурс летающих роботов: полёты и ошибки

 

http://habrahabr.ru/...oc/blog/192704/



#163
erbol

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

Пусть надо найти контуры ящика на рисунке. Ясно что выбор инструмента будет зависеть от ситуации

То есть необходимо попробовать несколько способов и выбрать из них самый эффективный.

Для начала попробуем выполнить "бинаризацию" картинки

 

Алгоритм

 

1. Загружаем картинку

2. Разбиваем на каналы

3. Пороговое преобразование

4. Склеиваем полученные после фильтрации слои

5. Отображаем полученную картинку

 

 
 
#include <cv.h>
#include <highgui.h>
#include <stdlib.h>
#include <stdio.h>
 
int main(int argc, char* argv[])
{
        IplImage *image=0, *gray=0, *dst=0, *dst2=0;
        IplImage* r=0, *g=0, *b=0; // для хранения отдельных слоёв RGB-изображения
 
        // имя картинки задаётся первым параметром
        char* filename = argc >= 2 ? argv[1] : "1Xz1PR_adIw.jpg";
        // получаем картинку
        image = cvLoadImage(filename, 1);
 
        printf("[i] image: %s\n", filename);
        assert( image != 0 );
 
 
int minB = 0, maxB = 255;
int minG = 0, maxG = 255;
int minR = 0, maxR = 255;
        cvNamedWindow( "original", 1 );
cvCreateTrackbar("B max", "original", &maxB, 255);
cvCreateTrackbar("B min", "original", &minB, 255);
cvCreateTrackbar("G max", "original", &maxG, 255);
cvCreateTrackbar("G min", "original", &minG, 255);
cvCreateTrackbar("R max", "original", &maxR, 255);
cvCreateTrackbar("R min", "original", &minR, 255);
// покажем изображение
 
        cvShowImage( "original", image );
 
 
        r = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
        g = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
        b = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
 
        // разбиваем на отдельные слои
        cvSplit(image, b, g, r, 0);
 
 
 
        //
        // попробуем пороговое преобразование над отдельными слоями
        //
while (1) {
IplImage* t1, *t2, *t3; // для промежуточного хранения
t1 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
t2 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
t3 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
 
// выполняем пороговое преобразование
cvThreshold(r, t1, minR, maxR, CV_THRESH_BINARY);
cvThreshold(g, t2, minG, maxG, CV_THRESH_BINARY);
cvThreshold(b, t3, minB, maxB, CV_THRESH_BINARY);
 
// складываем результаты
cvMerge(t3, t2, t1, 0, image);
//cvMerge(b, g, r, 0, image);
 
cvNamedWindow( "RGB cvThreshold", 1 );
cvShowImage( "RGB cvThreshold", image);
 
cvReleaseImage(&t1); cvReleaseImage(&t2); cvReleaseImage(&t3);
 
 
       cvWaitKey(100);
}
        // освобождаем ресурсы
        cvReleaseImage(& image);
 
 
        cvReleaseImage(&r); cvReleaseImage(&g); cvReleaseImage(&b);
 
        // удаляем окна
        cvDestroyAllWindows();
        return 0;
}
 


#164
erbol

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

Некоторые замечания по поводу поиска контуров предметов на рисунке

 

1. Если использовать сглаживание, то обязательно cvSmooth(src, dst, CV_BILATERAL, kernel, kernel, smoothness, smoothnes)

 

2. Если использовать пороговую бинаризацию, то обязательно cvAdaptiveThreshold



#165
erbol

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

Неожиданно для меня в качестве источника и получателя функции cvSmooth могут быть цветные картинки

Вот исходная картинка

gallery_10467_19693_105622.png

а это картинка после сглаживания в режиме CV_BILATERAL, kernel = 15, smoothness_color = 50.0, smoothness_space = 300.0

cvSmooth(src, dst, CV_BILATERAL, kernel , kernel , smoothness_color, smoothness_space);

gallery_10467_19693_112063.png

Видно что края объектов на рисунке не размыты, хотя удалось избавиться от ненужных подробностей  на полу и на стенке полигона



#166
erbol

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

Условия нового конкурса КРОК

 

http://www.robots.cr...ns/etap2014.pdf



#167
erbol

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

Пример использования функции cvMorphologyEx (морфологические преобразования). с типом преобразования  CV_MOP_CLOSE. Это преобразование позволяет избавиться от узких участков разъединяющих широкие сравнительо однородные по цвету области

gallery_10467_19693_325247.png

Видно, что линии на стене стали менее заметными



#168
erbol

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

В статье описан хороший фильтр яркости

http://habrahabr.ru/post/172651/
http://www.ipol.im/p.../2011/lmps_rpe/
http://demo.ipol.im/...E320C2C0D7B7642

Исходная картинка

gallery_10467_19693_105622.png

После обработки фильтром яркости Retinex Poisson Equation с параметром t=10.0

gallery_10467_19693_5329.png


Сообщение отредактировал erbol: 29.10.2013, 15:52:44


#169
erbol

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

Для коррекции баланса белого применяется алгоритм нормализации гистограммы (равномерное растяжение гистограммы от минимальных до максимальных значений яркости, с «обрезанием» неинформативных краев). Для обработки яркости изображения его гистограмма сдвигается в центр. 



#170
erbol

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

Третий аргумент функции cvHoughLines2 целое число которое определяет метод трансформации Хафа. Их три.

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

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

 

Вот пример работы функции для такой картинки

 

gallery_10467_19693_1026.png

 

Для таких параметров функции

 

        lines = cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 1, 1, 1 );

 

gallery_10467_19693_484.png



#171
erbol

erbol
  • Читатель
  • 361 сообщений
Четвертый и пятый аргумент функции cvHoughLines2 задают параметры отбора в ячейки аккумуляторной матрицы. Четвертый аргумент задает разрешение метода по дистанции, пятый по углу
 
Шестой - пороговый параметр. Линия возвращается, если аккумулирующий параметр больше порогового значения.
 
Седьмой аргумент - минимальная длина линии. 
 
Шестой аргумент задает минимальное число пикселей для линии, чтобы эта линия попала в результат, причем эти точки не обязательно должны идти подряд, то есть между ними может быть промежуток.
 
Седьмой аргумент - задает минимальную длину линии в пикселах. Под длиной линии понимается сумма длин отрезков плюс промежутки между ними
 
Для того чтобы функция cvHoughLines2 в режиме CV_HOUGH_PROBABILISTIC надежно работала нужно дать по возможности большие значения для шестого и седьмого аргументов
 
Пусть задано два отрезка лежащих на одной прямой линии. Длина первого отрезка - 9 пикселов, второго - 15 пикселов. Пусть между концом первого отрезка и началом второго промежуток равен 15 пикселам
 
Для того чтобы функция вернула в результате отрезок состоящий из двух надо задать следующие параметры
 
cvHoughLines2( dst, storage, CV_HOUGH_PROBABILISTIC, 1, CV_PI/180, 23, 37, 15 )
 
Общая длина отрезков лежащих на одной прямой равна 9 + 15 = 24. Значит значение шестого параметра не должно превышать 23, если мы хотим чтобы функция обнаружила эти два отрезка и приняла за части одного отрезка.
 
Промежуток между отрезками равен 15 пикселам. Если мы хотим чтобы функция воспринимала два коллинеарных отрезка как части одного большого отрезка надо дать восьмому параметру значение не меньше 15. Этот параметр задает максимальный промежуток между частями одной линии
 
Значение седьмого параметра который задает минимальную длину в пикселах не должно превышать 37 пикселов 


#172
erbol

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

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

 

Краевые точки (пикселы) это геометрические абстракции нижнего уровня. Из них можно получить абстракции более высокого уровня - отрезки прямых и далее анализируя отрезки можно получить абстракции высшего уровня - "стенки коридора лабиринта" и "препятствия"

 

Желательно чтобы методы используемые для получения отрезков прямых и далее информации о перегородках и стенках лабиринта имели высокую "устойчивость и качество"



#173
erbol

erbol
  • Читатель
  • 361 сообщений
Учим робота понимать геометрию мира с помощью алгоритма "точка схода".
 
Кратко суть алгоритма сводится к тому, что на картинке ищем отрезки прямых линий и пытаемся найти общую точку пересечения прямых линий, фрагментами которых являются найденные нами отрезки. Эта точка называется "точкой схода" и лежит на особой линии которая называется "линией горизонта".
 
Алгоритм "точки схода"
 
1. Загружаем картинку и фильтруем шумы с помощью cvSmooth
        image=cvLoadImage("vanish.png");
 
        IplImage *gray_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
        IplImage *canny_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
 
        // Convert the image to grayscale
        cvCvtColor(image , gray_out, CV_RGB2GRAY);
 
        // Denoising
        cvSmooth(gray_out, gray_out, CV_GAUSSIAN, 3, 3);
 
2. Ищем "краевые пикселы" ("углы") с помощью cvCanny
 
        // Detect edges
        cvCanny(gray_out, canny_out, th1, th2, 3);
 
3. Ищем отрезки прямых линий с помощью cvHoughLines2
 
        // Detect lines
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq *lines = cvHoughLines2(canny_out, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 50);  
 
 
4. Просматриваем параметры отрезков. Если угол наклона прямой к вертикали меньше 28 градусов или угол наклона к горизонтали меньше 12 градусов, то такая прямая отбрасывается
 
Формально для отбора используется следующее условие
 
0.5 < fabs(m) && fabs(m) < 5.0
 
где m это
 
m = -cos(theta) / sin(theta)
 
Параметры линий прошедших отбор записываем и эти линии рисуем на картинке. Параметры линий будут использованы для отбора прямых имеющих точки пересечения.
 
 
        // Hough standard transform
        std::vector<float> m1, c1, xvc, yvc;
        for (int i = 0; i < MIN(lines->total,100); i++ ) {
            float *line = (float*)cvGetSeqElem(lines, i);
            float rho = line[0];
            float theta = line[1];
            // Находим координаты точки пересечения перпендикуляра
            // из центра координат и отрезка
            double a = cos(theta), b = sin(theta);
            // х0 , у0 - координаты точки пересечения перпендикуляра и отрезка
            double x0 = a * rho, y0 = b * rho;
 
            // Line points
            CvPoint pt1, pt2;
            // Находим координаты точек лежащих на
            //растоянии 1000 пикселов от точки х0 и у0 в
            //обе стороны
            pt1.x = cvRound(x0 + 1000 * (-B));
            pt1.y = cvRound(y0 + 1000 * ( a));
            pt2.x = cvRound(x0 - 1000 * (-B));
            pt2.y = cvRound(y0 - 1000 * ( a));
 
            // Save angled line
            // Сохраняем нужные значения в вектора
            // Для каждой линии определяем две величины            
            if (fabs(theta) > 0.0) {
                float m = -cos(theta) / sin(theta);
                float c = rho * (1.0 / sin(theta));
                if (0.5 < fabs(m) && fabs(m) < 5.0) {
                    m1.push_back(m);
                    c1.push_back(c);
                    cvLine(image, pt1, pt2, CV_RGB(255,0,0));
                }
            }
        }
 
5. Находим координаты точек пересечения прямых. Если эти координаты не выходят за границы картинки, то сохраняем их в вектора xvc. yvc
 
 
        // Detect vanishing points
//Если точка пересечения двух произвольных линий из
//набора находится в окне, то сохраняем координаты
//этой точки
        for (int k = 0; k < (int)m1.size(); k++) {
            for(int k1 = k+1; k1 < (int)m1.size(); k1++) {
                if (fabs(m1[k] - m1[k1]) > 1.0) {
                    int xv = fabs((c1[k1] - c1[k]) / (m1[k] - m1[k1]));
                    int yv = fabs((m1[k1] * xv) + c1[k1]);
                    if(yv > 0 && yv < image->height && xv > 0 && xv < image->width) {
                        xvc.push_back(xv);
                        yvc.push_back(yv);
                    }
                }
            }
        }
6. Находим координаты "точки схода". Каждая точка пересечения имеет свой вес, который определяет ее вклад в координаты "точки схода". Чем дальше точка от центра картинки тем меньше ее вклад.Вклад обратно пропорционален экспоненте, аргументом которой является расстояние от центра картинки
 
 
        // Detected
// Находим взвешенное значение всех точек пересеченя -
//это точка лежит на линии горизонта
        if (!xvc.empty()) {
            double sum_x = 0, sum_y = 0, sum_w = 0;
            for (int i = 0; i < (int)xvc.size(); i++) {
//http://www.realcoding.net/articles/opisanie-funktsii-c-si-c-hypot.html
// sqrt(x*x + y*y);
                double w = exp(-hypot(xvc[i] - canny_out->width/2, yvc[i] - canny_out->height/2));
                sum_x += w * xvc[i];
                sum_y += w * yvc[i];
                sum_w += w;
            }
 
            // Vanishing point
            CvPoint vanishing_point = cvPoint(sum_x/sum_w, sum_y/sum_w);
 
            // Show result
            cvCircle(image, vanishing_point, 5, cvScalar(255,0,0), 2);
        }


#174
erbol

erbol
  • Читатель
  • 361 сообщений
Код программы "точка схода" на С++
 
 
#include <cv.h>
#include <highgui.h>
#include <math.h>
 
// Vanishing point detection sample based on
// http://dasl.mem.drexel.edu/wiki/index.php/Vanishing_point_detection_for_corridors_and_hallways
 
// --------------------------------------------------------------------------
// 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)
{
 
 
 
        //IplImage* dst = cvCreateImage( cvGetSize(src), 8, 1 );
        //IplImage* color_dst = cvCreateImage( cvGetSize(src), 8, 3 );
 
 
    // Thresholds. Создаем переменные для бегунков
    int th1 = 0, th2 = 255;
 
    // Create a window
    cvNamedWindow("canny");
    cvCreateTrackbar("th1", "canny", &th1, 255);
    cvCreateTrackbar("th2", "canny", &th2, 255);
IplImage *image = 0;
 
    // Main loop
    while (1) {
        // Key input
        int key = cvWaitKey(1);
        if (key == 0x1b) break;
 
 
 
image = cvLoadImage("vanish.png");;
 
// Фильтруем шумы
        IplImage *gray_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); 
        IplImage *canny_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
 
        // Convert the image to grayscale
        cvCvtColor(image , gray_out, CV_RGB2GRAY);
 
        // Denoising
        cvSmooth(gray_out, gray_out, CV_GAUSSIAN, 3, 3);
// Ищем границы 
        // Detect edges
        cvCanny(gray_out, canny_out, th1, th2, 3);
 
        // Detect lines Ищем отрезки прямых линий
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq *lines = cvHoughLines2(canny_out, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, 50);  
 
        // Hough standard transform
        std::vector<float> m1, c1, xvc, yvc;
        for (int i = 0; i < MIN(lines->total,100); i++ ) {
            float *line = (float*)cvGetSeqElem(lines, i);
            float rho = line[0];
            float theta = line[1];
// Находим координаты точки пересечения перпендикуляра 
// из центра координат и отрезка
            double a = cos(theta), b = sin(theta);
// х0 , у0 - координаты точки пересечения перпендикуляра и отрезка
            double x0 = a * rho, y0 = b * rho;
 
            // Line points 
            CvPoint pt1, pt2;
// Находим координаты точек лежащих на 
//растоянии 1000 пикселов от точки х0 и у0 в 
//обе стороны
pt1.x = cvRound(x0 + 1000 * (-b));
            pt1.y = cvRound(y0 + 1000 * ( a));
            pt2.x = cvRound(x0 - 1000 * (-b));
            pt2.y = cvRound(y0 - 1000 * ( a));
 
            // Save angled line 
// Сохраняем нужные значения в вектора
// Для каждой линии определяем две величины            
if (fabs(theta) > 0.0) {
                float m = -cos(theta) / sin(theta);
                float c = rho * (1.0 / sin(theta));
                if (0.5 < fabs(m) && fabs(m) < 5.0) {
                    m1.push_back(m);
                    c1.push_back(c);
                    cvLine(image, pt1, pt2, CV_RGB(255,0,0));
                }
            } 
        }
 
        // Detect vanishing points
//Если точка пересечения двух произвольных линий из 
//набора находится в окне, то сохраняем координаты 
//этой точки 
        for (int k = 0; k < (int)m1.size(); k++) {
            for(int k1 = k+1; k1 < (int)m1.size(); k1++) {
                if (fabs(m1[k] - m1[k1]) > 1.0) {
                    int xv = fabs((c1[k1] - c1[k]) / (m1[k] - m1[k1]));
                    int yv = fabs((m1[k1] * xv) + c1[k1]);
                    if(yv > 0 && yv < image->height && xv > 0 && xv < image->width) {
                        xvc.push_back(xv);
                        yvc.push_back(yv);
                    }
                }
            }
        }
 
        // Detected
// Находим взвешенное значение всех точек пересеченя - 
//это точка лежит на линии горизонта
        if (!xvc.empty()) {
            double sum_x = 0, sum_y = 0, sum_w = 0;
            for (int i = 0; i < (int)xvc.size(); i++) {
//http://www.realcoding.net/articles/opisanie-funktsii-c-si-c-hypot.html
// sqrt(x*x + y*y);
                double w = exp(-hypot(xvc[i] - canny_out->width/2, yvc[i] - canny_out->height/2));
                sum_x += w * xvc[i];
                sum_y += w * yvc[i];
                sum_w += w;
            }
 
            // Vanishing point
            CvPoint vanishing_point = cvPoint(sum_x/sum_w, sum_y/sum_w);
 
            // Show result
            cvCircle(image, vanishing_point, 5, cvScalar(255,0,0), 2);
        }
 
        // Display the image
        cvShowImage("canny", canny_out);
        cvShowImage("camera", image);
 
        // Release memories
        cvReleaseImage(&gray_out);
cvReleaseImage(&image);
        cvReleaseImage(&canny_out);
        cvReleaseMemStorage(&storage);
    }
 
 
 
    return 0;
}
 


#175
erbol

erbol
  • Читатель
  • 361 сообщений
Алгоритм подбора значения порогового параметра threshold функции cvHoughLines2
 
В алгоритме "точка схода" вычисляются координаты точек пересечения линий которые лежат в области картинки. Эти координаты помещаются в вектора xvc и yvc. Измерив длину вектора определяем количество точек пересечения
 
1. Если xvc.size > 4, то увеличиваем значение для threshold на единицу
2. Если xvc.size <= 4, то ничего не делаем

 

3 Если xvc.size == 4, то уменьшаем значение для threshold на единицу 

 

Информативная часть картинки в алгоритме "точка схода" это контур основания лабиринта по которому движется робот. Для поиска "точки схода" используются две линии контура "параллельные" оси камеры по обе стороны от нее. Заметим, что чем больше значение порогового параметра в функции cvHoughLines2 тем точнее вычисляется положение "точки схода". Поэтому значение параметра лучше динамически подстраивать под конкретную картинку полученную от робота. Выбирая его таким образом, чтобы отрезки из которых строятся прямые имели длину не менее 20 пикселов. Если это условие выполняется увеличиваем значение параметра, до тех пор пока число "точек схода" прямых полученных от функции cvHoughLines2 не станет минимальным, например меньше четырех



#176
erbol

erbol
  • Читатель
  • 361 сообщений
В алгоритме точка схода циклически вычисляется координаты точек пересечения прямых линий получаемых от функции cvHoughLines2. Эти данные помещаются в два вектора xvc и yvc. Измеряя размер вектора можно определить количество точек пересечения и реализовать следующую схему подбора оптимального значения для величины порогового параметра
 
 
if ((int)xvc.size() > limit) {
 
printf("threshold(+) %d\n", th3);
printf("xvc %d\n", (int)xvc.size());
if ((int)xvc.size() > 10) {
th3 = th3 + 4;
}
else
{
th3++;
}
 
}
else
{
// (int)xvc.size() <= limit && (int)xvc.size() > 0
if ((int)xvc.size() > 0) {
 
if (!xvc.empty()) {
for (int j = 0; j < (int)xvc.size(); j++) {
xvc1.push_back(xvc[j]);
yvc1.push_back(yvc[j]);
}
}
flag = false;
}
else
{
// (int)xvc.size() == 0
printf("threshold(-) %d\n", th3);
printf("xvc %d\n", (int)xvc.size());
th3--;
// Выходим из цикла, так как не обнаруженно прямых линий на картинке
if (th3 < low_th3) flag = false;
}
}
 
 
где используются следующие величины, определенные перед входом в главный цикл программы
 
int limit = 3, low_th3 = 20;
 
и логическая переменная 
 
bool flag = true; 
 
использованная в качестве условия выхода из вложенного цикла, используемого для оптимизации значения порогового параметра


#177
russo_turisto

russo_turisto
  • Постоялец
  • 359 сообщений

erbol где можно купить не за дорого этот квадрокопер?


  • 0

#178
erbol

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

Я покупал на ebay. Доставка где то 50 долларов

 

Вот , например

 

http://www.ebay.com/...=item51b582d6c1


Сообщение отредактировал erbol: 18.12.2013, 10:05:42


#179
erbol

erbol
  • Читатель
  • 361 сообщений
Для нахождения контуров предметов используем алгоритм Кенни, который реализован в функции cvCanny библиотеки openCV. Функция имеет пять аргументов. Параметр threshold1 - задает минимальное значение градиента пиксела попадающего  в обработанное  функцией изображение.
 
Кроме функции cvCanny за качество работы алгоритма "точка схода" отвечает пороговый параметр функции cvHoughLines2.
 
Правильный подбор этих двух параметров позволяет получить приближенные к реальности координаты точки схода
 
Код программы
 
 
#include <cv.h>
#include <highgui.h>
#include <math.h>
 
// Vanishing point detection sample based on
// http://dasl.mem.drexel.edu/wiki/index.php/Vanishing_point_detection_for_corridors_and_hallways
 
// --------------------------------------------------------------------------
// main(Number of arguments, Argument values)
// Description  : This is the entry point of the program.
// Return value : SUCCESS:0  ERROR:-1
// --------------------------------------------------------------------------
// Thresholds. Создаем переменные для бегунков
//IplImage *canny_out=0;
int th1 = 255, th2 = 255, th3 = 20;
 
void findTh1(IplImage* src)
{
bool flag = true, flag1 = true;
while (flag) {
 
        IplImage *canny_out = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
 
 
        // Detect edges
        cvCanny(src, canny_out, th1, th2, 3);
 
 
        // Detect lines Ищем отрезки прямых линий
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq *lines = cvHoughLines2(canny_out, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, th3);  
 
        // Hough standard transform
        std::vector<float> m1, c1, xvc, yvc;
        for (int i = 0; i < MIN(lines->total,100); i++ ) {
            float *line = (float*)cvGetSeqElem(lines, i);
            float rho = line[0];
            float theta = line[1];
// Находим координаты точки пересечения перпендикуляра
// из центра координат и отрезка
            double a = cos(theta), b = sin(theta);
// х0 , у0 - координаты точки пересечения перпендикуляра и отрезка
            double x0 = a * rho, y0 = b * rho;
 
            // Line points
            CvPoint pt1, pt2;
// Находим координаты точек лежащих на
//растоянии 1000 пикселов от точки х0 и у0 в
//обе стороны
pt1.x = cvRound(x0 + 1000 * (-B));
            pt1.y = cvRound(y0 + 1000 * ( a));
            pt2.x = cvRound(x0 - 1000 * (-B));
            pt2.y = cvRound(y0 - 1000 * ( a));
 
            // Save angled line
// Сохраняем нужные значения в вектора
// Для каждой линии определяем две величины            
if (fabs(theta) > 0.0) {
                float m = -cos(theta) / sin(theta);
                float c = rho * (1.0 / sin(theta));
                if (0.4 < fabs(m) && fabs(m) < 5.0) {
                    m1.push_back(m);
                    c1.push_back(c);
                    //cvLine(image, pt1, pt2, CV_RGB(255,0,0));
                }
            }
        }
 
        // Detect vanishing points
//Если точка пересечения двух произвольных линий из
//набора находится в окне, то сохраняем координаты
//этой точки
        for (int k = 0; k < (int)m1.size(); k++) {
            for(int k1 = k+1; k1 < (int)m1.size(); k1++) {
                if (fabs(m1[k] - m1[k1]) > 1.0) {
                    int xv = fabs((c1[k1] - c1[k]) / (m1[k] - m1[k1]));
                    int yv = fabs((m1[k1] * xv) + c1[k1]);
                    if(yv > 0 && yv < src->height && xv > 0 && xv < src->width) {
                        xvc.push_back(xv);
                        yvc.push_back(yv);
                    }
                }
            }
        }
 
 
if ((int)xvc.size() == 0) {
if (th1 > 5) {
th1 = th1 - 5;
}
else
{
flag = false;
}
}
else
{
if (th3 < 100 && (int)xvc.size() > 2) th3 = th3 + 2;
else
{
flag = false;
 
}
 
}
 
cvReleaseMemStorage(&storage);
}
 
 
}
 
 
int main(int argc, char** argv)
{
 
    // Create a window
    cvNamedWindow("canny");
    cvCreateTrackbar("th1", "canny", &th1, 255);
    cvCreateTrackbar("th2", "canny", &th2, 255);
IplImage *image = 0;
 
    // Main loop
    while (1) {
        // Key input
        int key = cvWaitKey(1);
        if (key == 0x1b) break;
 
 
 
image = cvLoadImage("srcgray.png");
 
int width = (int) image->width;
int height = (int) image->height;
 
// Очищаем верхнюю половину рисунка, заливаем ее белым цветом
        // устанавливаем ROI
        cvSetImageROI(image, cvRect(0,0,image->width,image->height/2));
        // обнулим изображение
        cvZero(image);
// Инвертируем
cvAddS(image, cvScalar(255,255,255), image);
        // сбрасываем ROI
        cvResetImageROI(image);
 
// Фильтруем шумы
        IplImage *gray_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
        IplImage *canny_out = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1);
 
        // Convert the image to grayscale
        cvCvtColor(image , gray_out, CV_RGB2GRAY);
 
        // Denoising
        cvSmooth(gray_out, gray_out, CV_GAUSSIAN, 3, 3);
 
findTh1(gray_out);
 
// Ищем границы
        // Detect edges
        cvCanny(gray_out, canny_out, th1, th2, 3);
 
 
 
        // Detect lines Ищем отрезки прямых линий
        CvMemStorage* storage = cvCreateMemStorage(0);
        CvSeq *lines = cvHoughLines2(canny_out, storage, CV_HOUGH_STANDARD, 1, CV_PI/180, th3);  
 
        // Hough standard transform
        std::vector<float> m1, c1, xvc, yvc;
        for (int i = 0; i < MIN(lines->total,100); i++ ) {
            float *line = (float*)cvGetSeqElem(lines, i);
            float rho = line[0];
            float theta = line[1];
// Находим координаты точки пересечения перпендикуляра
// из центра координат и отрезка
            double a = cos(theta), b = sin(theta);
// х0 , у0 - координаты точки пересечения перпендикуляра и отрезка
            double x0 = a * rho, y0 = b * rho;
 
            // Line points
            CvPoint pt1, pt2;
// Находим координаты точек лежащих на
//растоянии 1000 пикселов от точки х0 и у0 в
//обе стороны
pt1.x = cvRound(x0 + 1000 * (-B));
            pt1.y = cvRound(y0 + 1000 * ( a));
            pt2.x = cvRound(x0 - 1000 * (-B));
            pt2.y = cvRound(y0 - 1000 * ( a));
 
            // Save angled line
// Сохраняем нужные значения в вектора
// Для каждой линии определяем две величины            
if (fabs(theta) > 0.0) {
                float m = -cos(theta) / sin(theta);
                float c = rho * (1.0 / sin(theta));
                if (0.4 < fabs(m) && fabs(m) < 5.0) {
                    m1.push_back(m);
                    c1.push_back(c);
                    cvLine(image, pt1, pt2, CV_RGB(255,0,0));
                }
            }
        }
 
        // Detect vanishing points
//Если точка пересечения двух произвольных линий из
//набора находится в окне, то сохраняем координаты
//этой точки
        for (int k = 0; k < (int)m1.size(); k++) {
            for(int k1 = k+1; k1 < (int)m1.size(); k1++) {
                if (fabs(m1[k] - m1[k1]) > 1.0) {
                    int xv = fabs((c1[k1] - c1[k]) / (m1[k] - m1[k1]));
                    int yv = fabs((m1[k1] * xv) + c1[k1]);
                    if(yv > 0 && yv < image->height && xv > 0 && xv < image->width) {
                        xvc.push_back(xv);
                        yvc.push_back(yv);
                    }
                }
            }
        }
 
        // Detected
// Находим взвешенное значение всех точек пересеченя -
//это точка лежит на линии горизонта
        if (!xvc.empty()) {
            double sum_x = 0, sum_y = 0, sum_w = 0;
            for (int i = 0; i < (int)xvc.size(); i++) {
//http://www.realcoding.net/articles/opisanie-funktsii-c-si-c-hypot.html
// sqrt(x*x + y*y);
                double w = exp(-hypot(xvc[i] - canny_out->width/2, yvc[i] - canny_out->height/2));
                sum_x += w * xvc[i];
                sum_y += w * yvc[i];
                sum_w += w;
            }
 
            // Vanishing point
            CvPoint vanishing_point = cvPoint(sum_x/sum_w, sum_y/sum_w);
 
            // Show result
            cvCircle(image, vanishing_point, 5, cvScalar(255,0,0), 2);
        }
 
        // Display the image
        cvShowImage("canny", canny_out);
        cvShowImage("camera", image);
 
        // Release memories
        cvReleaseImage(&gray_out);
cvReleaseImage(&image);
        cvReleaseImage(&canny_out);
        cvReleaseMemStorage(&storage);
    }
printf("th1 %d\n", th1);
printf("th3 %d\n", th3);
 
 
 
    return 0;
}
 


#180
erbol

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

Вот результаты работы обработки программой картинок

gallery_10467_19804_9683.png

Для этой картинки программа выдала следующие оптимальные значения

для параметра th1 - 255, для th3 - 86

gallery_10467_19804_205084.png

для параметра th1 - 255, для th3 - 100

gallery_10467_19804_10977.png

для параметра th1 - 210, для th3 - 48

gallery_10467_19804_99504.png

для параметра th1 - 255, для th3 - 48




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

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

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

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