Заливка замкнутой области
Пример показывает один из самых простых и эффективных способов заливки. Использовать его в таком варианте не рекомендую, рисовать на TImage->Canvas довольно медленно, но в качестве примера очень удобно.
Процедура последовательно просматривает соседние точки, и если они не залиты, то заливает и добавляет 4 соседние точки в очередь, на рассмотрение. И так пока очередь не кончится.
На рисунке черными стрелками показаны точки, которые будут добавлены в очередь для просмотра, а красными, которые не будут добавлены, так как уже залиты.



Теперь собственно - исходник. (Borland C++ Builder). На форме достаточно иметь TImage - Image1.
void ImageFill(short x, short y, TColor color) {
// Получим размеры изображения
int imw=Form1->Image1->Width;
int imh=Form1->Image1->Height;
// Выделим памяти для складирования координат, которые еще предстоит залить
int STACK_SIZE=(imw+2)*(imh+2);
short *floodfill_stackx=(short*)malloc(STACK_SIZE*sizeof(short));
short *floodfill_stacky=(short*)malloc(STACK_SIZE*sizeof(short));
if (floodfill_stacky==NULL || floodfill_stackx==NULL) return;
int stack_head=0;
int stack_tail=0;
TColor clr=Form1->Image1->Canvas->Pixels[x][y];
floodfill_stackx[stack_head]=x;
floodfill_stacky[stack_head]=y;
Form1->Image1->Canvas->Pixels[x][y]=color;
stack_head++;
// Пока не кончится память или точки на изображении
while (stack_head<STACK_SIZE && stack_head>stack_tail) {
x=floodfill_stackx[stack_tail];
y=floodfill_stacky[stack_tail];
stack_tail++;
if (x>=0 && y>=0 && x<imw && y<imh) {
// Проверим точку справа, если она не залита, то зальем
if (Form1->Image1->Canvas->Pixels[x+1][y]==clr) {
floodfill_stackx[stack_head]=x+1;
floodfill_stacky[stack_head]=y;
Form1->Image1->Canvas->Pixels[x+1][y]=color;
stack_head++;
}
// Проверим точку слева, если она не залита, то зальем
if (Form1->Image1->Canvas->Pixels[x-1][y]==clr) {
floodfill_stackx[stack_head]=x-1;
floodfill_stacky[stack_head]=y;
Form1->Image1->Canvas->Pixels[x-1][y]=color;
stack_head++;
}
// Проверим точку снизу, если она не залита, то зальем
if (Form1->Image1->Canvas->Pixels[x][y+1]==clr) {
floodfill_stackx[stack_head]=x;
floodfill_stacky[stack_head]=y+1;
Form1->Image1->Canvas->Pixels[x][y+1]=color;
stack_head++;
}
// Проверим точку сверху, если она не залита, то зальем
if (Form1->Image1->Canvas->Pixels[x][y-1]==clr) {
floodfill_stackx[stack_head]=x;
floodfill_stacky[stack_head]=y-1;
Form1->Image1->Canvas->Pixels[x][y-1]=color;
stack_head++;
}
}
}
Form1->Image1->Canvas->TextOutA(1,1,IntToStr(stack_head));
// Освободим память
free(floodfill_stacky);
free(floodfill_stackx);
}
void __fastcall TForm1::Button1Click(TObject *Sender) {
Image1->Canvas->Ellipse(20,20,300,200);
ImageFill(1,1,0xFF0000);
}
Оставить комментарий
Комментарии
1.


17 марта 2006, 22:46:05
Ах да, скажу - неизбежно будет переполнение стека (который таки переполнится несмотря на проверку stack_head<STACK_SIZE, поглядите внимательно). Почему? А потому, что признаком конца псевдоитерации служит считанный цвет и при равных цветах распространение всегда будет во все четыре стороны и алгоритм вообще никогда не остановится.
з.ы. if(clr==color)return; надо поставить первой строкой, чтобы зря не выделять и не удалять память.
з.ы. if(clr==color)return; надо поставить первой строкой, чтобы зря не выделять и не удалять память.
2.


17 марта 2006, 22:10:49
Мало того, что алгоритм ужасен в неэффективности, так ещё и... вот подумайте, что будет, если заливать область тем же цветом, что и сама область! Подумали?
А теперь ОБЯЗАТЕЛЬНО вставьте проверку if(clr==color)return;
А теперь ОБЯЗАТЕЛЬНО вставьте проверку if(clr==color)return;
