Заполнение многоугольников и областей
6.3. Заполнение с затравкой
Область, подлежащая заполнению, не всегда задается в виде многоугольника. В этом разделе мы рассмотрим случай, когда заполняемая область задается цветом своей границы. Множество пикселей на растре не задает область однозначно, поэтому требуется задать координаты "затравочного" пикселя, принадлежащего области.
Алгоритмы, рассматриваемые в этом разделе, используют структуру данных под названием стек. Стек содержит упорядоченный набор элементов и поддерживает две основные операции: добавить элемент и извлечь элемент. Вторая операция возвращает элемент, добавленный последним, и удаляет его из набора элементов. Программно стек может быть реализован на основе одномерного массива.
Простейший алгоритм заполнения с затравкой - это так называемый алгоритм короеда, получивший подобное название, поскольку заполняемая область последовательно "выедается" по одному пикселю. Он устроен следующим образом:
//Заполняет цветом A область, ограниченную цветом B
Добавить затравочный пиксель в стек;
while(стек не пуст)
{
P = стек.Извлечь(); //извлечение пикселя из стека
Закрасить пиксель P;
foreach(Q in соседние с P пиксели)
if(цвет Q != B и Q еще не закрашен)
стек.Добавить(Q)
}
Листинг
6.5.
Алгоритм короеда
При обходе соседних пикселей может рассматриваться и 4-связность ( Q принимает 4 значения), и 8-связность ( Q принимает 8 значений). В зависимости от этого результат будет различным.
Внутри приведенного алгоритма производится проверка "Q еще не закрашен". Если известно, что пикселей цвета А внутри нашей области изначально не было, то это условие эквивалентно условию "цвет Q != A". В противном случае для проверки этого условия требуется введение специального буфера, где каждому пикселю соответствует флаг закраски, инициализируемый нулем и становящийся единицей при закраске пикселя.
Пример работы алгоритма показан на рис. 6.7. 4-связная область закрашивается в серый цвет и ограничена темными пикселями. Пиксель P извлечен из стека. Он закрашивается серым. Соседние незакрашенные пиксели Q, R и S добавляются в стек.
Используя пространственную когерентность, можно построить более эффективный алгоритм, использующий стек меньшей глубины и закрашивающий за одну итерацию целый горизонтальный отрезок пикселей:
//Заполняет цветом A область, ограниченную цветом B
Добавить затравочный пиксель в стек;
while(стек не пуст)
{
(X,Y) = стек.Извлечь(); //извлечение пикселя из стека
X_min = X;
while(цвет(X_min-1,Y) != B)
X_min--;
X_max = X;
while(цвет(X_max+1,Y) != B)
X_max++;
Закрасить отрезок (X_min,Y)--(X_max,Y) цветом A;
//обработка строки сверху
флаг = 1;
for(X = X_min; X <= X_max; X++)
{
if( цвет(X,Y-1) != B и (X,Y-1) еще не закрашен)
{
if( флаг == 1 )
{
стек.Добавить(X,Y-1);
флаг = 0;
}
}
else
флаг = 1;
}
//обработка строки снизу
флаг = 1;
for(X = X_min; X <= X_max; X++)
{
if( цвет(X,Y+1) != B и (X,Y+1) еще не закрашен)
{
if( флаг == 1 )
{
стек.Добавить(X,Y+1);
флаг = 0;
}
}
else
флаг = 1;
}
}
Листинг
6.6.
Заполнение с затравкой по отрезкам
Пример работы алгоритма показан на рис. 6.8. Пиксель P - затравочный; 4-связная область закрашивается в серый цвет и ограничена темными пикселями. При первой итерации производится заполнение целого отрезка. Пиксели Q и R на строке сверху и S на строке снизу добавляются в стек.
Заметим, что приведенные в данном разделе алгоритмы несложно переделать для перекрашивания с затравкой области постоянного цвета A в другой цвет B. Иными словами, для случая, когда область задается не цветом границы, а собственным цветом. В этом случае алгоритмы даже упрощаются: соседний пиксель добавляется в стек, только если он имеет цвет A (иначе он или не принадлежит перекрашиваемой области, или уже закрашен).

