Podręcznik Grafika komputerowa i wizualizacja
Rozdział 2. PODSTAWOWE OPERACJE RASTROWE
2.2. Wypełnianie obszaru
Wypełnianie obszaru jest drugim po rysowaniu odcinka
lub łuku, najczęściej występującym problemem związanym z prymitywami. Zadanie
dla szczególnych przypadków (np. dla prostokąta) jest zadaniem trywialnym.
Natomiast w ogólnym przypadku algorytm powinien pracować poprawnie dla
dowolnego wielokąta (także wklęsłego), również dla wielokątów z „dziurami”.
Rys.2.7. Wypełnianie obszaru. Równoważność problemów a)
wypełniania i b) zmiany barwy obszaru.
Analogicznym zadaniem do wypełniania obszaru jest zmiana barwy w danym obszarze. Zadania są równoważne (rys.2.7). W wypełnianiu obszaru brzegiem są piksele o barwie linii ograniczającej obszar, w zmianie barwy brzegiem są piksele o barwie tła. Algorytm rozwiązujący jedno zadanie może posłużyć do rozwiązania drugiego.
Niech na mapie pikseli dana będzie krzywa zamknięta, zdefiniowana w postaci zbioru sąsiadujących ze sobą pikseli o danej barwie. Zadaniem jest wypełnienie tego obszaru, czyli zmiana barwy wewnętrznych pikseli na zadaną barwę wypełnienia. Znane są dwa klasyczne sposoby rozwiązania tego zadania.
- Wypełnianie przez spójność (nazywane czasem wypełnianiem przez sianie).
- Wypełnianie przez kontrolę parzystości.
Warto zwrócić tutaj uwagę na problem sąsiedztwa
i konieczność dostosowania do niego kształtu brzegu. Można wyróżnić dwa
przypadki. Gdy ruchy po mapie pikseli mogą odbywać się analogicznie do ruchów
wieży po szachownicy – wtedy piksel ma 4 sąsiadów – siatka jest czterospójna
(rys.2.8a). Gdy dodamy do tego jeszcze ruchy na ukos (odpowiada to kierunkom
ruchów hetmana w szachach), to piksel ma 8 sąsiadów – siatka jest ośmiospójna
(rys.2.8b). Czytelnik może przeanalizować jak powinien wyglądać rozkład pikseli
brzegu dla obu przypadków aby stanowił on figurę zamkniętą z punktu widzenia
możliwości ruchu.
Rys.2.8. Możliwości poruszania się po mapie pikseli. a) siatka czterospójna, b) siatka ośmiospójna.
Algorytm wypełniania przez spójność dla siatki czterospójnej (rys.2.9) wygląda następująco (przyjęto: c_b – barwa brzegu, c_f – barwa wypełnienia).:procedure wypełnij1(x,y)
begin
set_pixel(x,y,c_f);
if (barwa(x-1,y) inna niż c_b i inna niż c_f) wypełnij1(x-1,y);
if (barwa(x+1,y) inna niż c_b i inna niż c_f) wypełnij1(x+1,y);
if (barwa(x,y-1) inna niż c_b i inna niż c_f) wypełnij1(x,y-1);
if (barwa(x,y+1) inna niż c_b i inna niż c_f) wypełnij1(x,y+1);
end;
Czytelnik może zaproponować korektę algorytmu obejmującą siatkę ośmiospójną.
Rys.2.9. Punkt startowy („ziarno”) oraz kierunki wypełniania w pierwszym kroku wypełniania przez spójność.
Przedstawiona postać algorytmu wypełniania przez spójność jest algorytmem rekurencyjnym. Daje to łatwość opisu ale związane jest także problemami realizacyjnymi. Z tego powodu znane są wersje niniejszego algorytmu w postaci nierekurencyjnej.
Rys.2.10.
Wypełnianie przez kontrolę parzystości.
Odcinki pomiędzy nieparzystym a
parzystym punktem przecięcia z figurą są w jej wnętrzu.
Rys.2.11. Problemy brzegowe wypełniania przez kontrolę parzystości.
Na rysunku 2.11 prosta l2 przecina wielokąt w wierzchołku (punkt 2) ale jest to przecięcie zwykłe – pozostałe końce przecinanych boków są po przeciwległych stronach prostej l2. Prosta l3 również przecina wielokąt w wierzchołku (punkt 2) ale jest to ekstremum lokalne – pozostałe końce boków są po tej samej stronie prostej l3.
W szczególnych przypadkach mogą pojawić się obszary nie dające się wypełnić w sposób spójny – problem „drzazgi” (rys. 2.12). Jedynym sposobem rozwiązania tego problemu jest nadpróbkowanie. Należy spróbkować i wypełnić drzazgę z większą rozdzielczością, a następnie uśrednić barwę/luminancję wracając do rozdzielczości rastra.
Rys.2.12.
Problem drzazgi. Taki obszar jest trudny do wypełnienia zarówno algorytmem
wypełniania przez spójność jak i przez kontrolę parzystości.
W książkach [1, 2] można znaleźć szczegółowe opisy oraz pseudokody dla rozwiązania różnych problemów rysowania prymitywów w technice rastrowej.