2013-10-14 4 views
0

У меня есть код для алгоритма flood fill.Алгоритм заполнения наводнений работает медленно

void floodFill() { 
    float target[3] = { 1.0, 1.0, 0.0 }; 
    float border[3] = { 1.0, 1.0, 1.0 }; 
    float clearp[3] = { 0.0, 0.0, 0.0 }; 
    std::stack<pixel*> colored; 
    if (!stack.empty()) // stack contains first pixel 
     colored.push(stack.top()); 

    while(!colored.empty()) { 

     pixel *p = colored.top(); 
     drawPixel(p->x, p->y, target); 
     colored.pop(); 

     //up 
     float pix[3]; 
     glReadPixels(p->x, p->y + KOEF, 1, 1, GL_RGB, GL_FLOAT, pix); 
     if (!compare(pix,border) && compare(pix,clearp)) { 
      pixel *pn = new pixel(); 
      pn->x = p->x; 
      pn->y = p->y + KOEF; 
      colored.push(pn); 
     } 
     //down 
     glReadPixels(p->x, p->y - KOEF, 1, 1, GL_RGB, GL_FLOAT, pix); 
     if (!compare(pix,border) && compare(pix,clearp)) { 
      pixel *pn = new pixel(); 
      pn->x = p->x; 
      pn->y = p->y - KOEF; 
      colored.push(pn); 
     } 

     //left 
     glReadPixels(p->x - KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix); 
     if (!compare(pix,border) && compare(pix,clearp)) { 
      pixel *pn = new pixel(); 
      pn->x = p->x - KOEF; 
      pn->y = p->y; 
      colored.push(pn); 
     } 

     //right 
     glReadPixels(p->x + KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix); 
     if (!compare(pix,border) && compare(pix,clearp)) { 
      pixel *pn = new pixel(); 
      pn->x = p->x + KOEF; 
      pn->y = p->y; 
      colored.push(pn); 
     } 

    } 
} 

Обращаю пиксель, используя этот метод

void drawPixel(float x, float y, float *t) { 
glRasterPos2i(x, y); 
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t); 
for(int i = 0; i < KOEF; i++) { 

    glRasterPos2i(x, y + i); 
    glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t); 

    glRasterPos2i(x + i, y); 
    glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t); 

    glRasterPos2i(x + i, y + i); 
    glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t); 
} 
}; 

Чтобы заполнить некоторую область Я выбираю первый пиксель мыши, а затем вызвать метод floodFill.

void mouse(int button, int state, int x, int y) { 

if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) { 
    pixel *p = new pixel(); 
    p->x = x; 
    p->y = HEIGHT - y; 
    if (!stack.empty()) 
     stack.pop(); 
    stack.push(p); // first pixel 

    floodFill(); 
} 
}; 

В результате (к примеру)

enter image description here

Но он работает очень медленно (несколько секунд область на картинке -.. Он рисовал его в течение 11 секунд область вокруг буквы - 43 секунд). И я думал, что он медленно рисует пиксель после пикселя, но он ждет несколько секунд, а затем я вижу результат.

мой компьютер

intel core 2 duo p8600 2.4 GHz 
nvidia 9600m gt 512 mb 
windows x86 
ram 4 GB(3)` 

Если это работает так медленно или есть проблемы?

+0

Вы пытались запустить свою программу под профилировщиком, например [Very Sleepy] (http://www.codersnotes.com/sleepy)? –

+5

Не удивительно, что 'glReadPixels (...)' - это операция с обратным проходом, и вы буквально заливаете OpenGL однопиксельными чтениями. OpenGL основан на архитектуре клиент/сервер, вам нужно минимизировать количество обратных ссылок, если вы хотите достойную производительность. Вам лучше было бы сделать это полностью на процессоре, а затем перенести свое изображение на OpenGL в самом конце или, по крайней мере, на чтение более одного пикселя за раз. –

+1

Если вы хотите, чтобы пиксели рисовались один за другим, вы должны поменять буферы внутри вашего 'while' –

ответ

4

Должно ли оно работать так медленно или возникает проблема?

Нет, не следует. Поскольку Photoshop может сделать это быстрее :-)

Похоже, что есть некоторые проблемы, связанные с эффективностью.

  1. Вы не должны использовать вызовы OpenGL для операций с одним пикселем. Вам лучше сделать буферную копию изображения, обработать (налить), а затем скопировать обратно.

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

  3. Ваша программа кажется слишком ООП-иш для своей цели. Не рекомендуется использовать new и stack в самой внутренней петле процедуры обработки изображений.

6

Это ужасно способ использования OpenGL.

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

+1

Слишком сложно. Это моя первая задача, использующая OpenGL. – lapots

+1

@ user1432980 Если это сложно, я бы предположил, что вы не используете OpenGL. Так как это предлагает архитектура OpenGL. Если вы используете (или, скорее, неправильно используете) OpenGL таким образом, вы просто замедляете работу. Если вы не хотите менять свой подход, измените библиотеку, используя SDL или что-то сравнимое (но это просто делегирует загрузку на GPU в ОС) – PeterT

+0

Вопрос не в том, хочу я этого или нет. И это задача, а не какое-то серьезное приложение. «Если он работает - он работает». – lapots

Смежные вопросы