Как работает операция заливки в приложениях paint?

все программы рисования, независимо от того, насколько они просты или сложны, поставляются с инструментом заливки. Это в основном заменяет цвет закрытой области другим цветом. Я знаю, что для этого существуют разные API, но меня интересует алгоритм. Каков был бы эффективный алгоритм для реализации этого инструмента?

пара вещей, которые я могу думать быстро:

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

Пример Изображения

6 ответов


многие реализации выполняются как рекурсивный алгоритм conquer и divide. Если вы сделаете быстрый google для "Flood fill algorithm", вы найдете множество ресурсов, включая отличную страницу Википедии на теме.


наиболее часто используется алгоритм заливки потока. Ниже приводится наивная версия этого прямо из моего старого университетского учебника "компьютерная графика с OpenGL" Хирна Бейкера, 3rd ed:

void floodFill4 (int x, int y, int fillColor, int interiorColor)
{
  int color;

  /* Set current color to fillColor, then perform the following operations */
  getPixel(x, y, color);
  if (color == interiorColor) 
  {
    setPixel(x,y);  // Set color of pixel to fillColor.
    floodFill4(x + 1, y, fillColor, interiorColor);
    floodFill4(x - 1, y, fillColor, interiorColor);
    floodFill4(x, y + 1, fillColor, interiorColor);
    floodFill4(x, y - 1, fillColor, interiorColor);
  }
}

для больших изображений, однако, выше, вероятно, даст вам ошибку переполнения стека из-за рекурсии для каждого пикселя. Часто этот алгоритм модифицируется так, что использует итерацию при заполнении строки пикселей, затем рекурсивно заполняет строки выше и ниже. Как @kasperjj заявил, что в Википедии есть хорошая статья об этом.


эти виды алгоритмов подробно обсуждаются в компьютерная графика: принципы и практика. Я настоятельно рекомендую эту книгу, если вы заинтересованы в понимании того, как растеризировать линии, заполнять полигоны, писать 3d-код без использования DirectX или OpenGL API. Конечно, для реальных приложений вы, вероятно, захотите использовать существующие библиотеки, но если вам интересно, как эти библиотеки работают, это потрясающее чтение.


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

1) сохранение логической памяти, ячейки которой вы уже посетили:Vis[]

2) ведение списка точек, которые вы уже посетили, но еще не отметили соседей для:Busy[]

3) Начните оба из них как пустые

4) Добавьте начальную точку в Busy

5)

while you have a point P in Busy:
{
    for each neighbour N of the point P for which Vis[N] is still false
    {
       if appropriate (not crossing the boundary of the fill region)
       {
           set Vis[N] to true
           update the colour of N in the bitmap
           add N to the end of Busy[]
       }
       remove P from Busy[]
    }
}

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

статья в Википедии.

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


общая идея описывается как Алгоритм Заливки и есть различные модификации к нему. Общим является заполнение scanline. См. связанный вопрос как работают движки 2D-рендеринга на основе Scanline?