IV.1. Giải thuật vết dầu loang
Thuật toân tô mău cho một vùng đồng nhất theo kiểu loang dầu thường được âp dụng để tô mău cho câc vùng có đường biín phức tạp rối rắm, như tô mău cho một vùng ảnh, hay một biến thể của giải thuật lă tìm một vùng liín thông đồng nhất mău (hay cùng tone mău) trín ảnh.
Hình III-7. Ảnh gốc & Ảnh được tô nền xanh theo thuật toân vết dầu loang
Băi toân tổng quât:
Cho một ma trận điểm M, mỗi điểm có toạ độ lă (x,y) với x,yZ vă có mău lă Color(x,y).
Từ một điểm P(x0,y0)M ta xâc định một vùng liín thông đồng nhất (đồng mău) Q theo quy tắc sau:
Đầu tiín tập Q chỉ có một phần tử đó lă P(x0,y0)
Với mọi điểm TM sẽ được đưa văo Q nếu tồn tại trong Q một điểm K năo đó sao cho Color(K)=Color(T) vă T lă lđn cận của K (ở đđy xĩt lđn cận 4, có nghĩa lă T ở sât trín hoặc sât dưới, hay sât trâi hoặc sât phải của K)
Biểu diễn về mặt toạ độ thì T lă lđn cận của K khi vă chỉ khi: ABS(XT-XK)+ABS(YT-YK)=1
Băi toân đặt ra lă xuất phât từ một điểm P(x0,y0)M hêy xâc định vùng Q vă tô mău cho nó bởi một mău C năo đó (dĩ nhiín lă C phải khâc mău hiện thời của vùng Q).
Trong thực tế băi toân tô mău theo vết dầu loang được ứng dụng rất rộng rêi trong đồ hoạ để tô mău, để xâc định vùng liín thông thoả một thuộc tính năo đó. Hay tư
tưởng vă phương phâp của nó được ứng dụng cho: tìm một vùng liín thông khi biết trước 1 điểm, hay lọc ra từ tập hợp câc phần tử cùng tính chất theo kiểu lần mắt xích quan hệ,...
Giải quyết băi toân năy có hai phương phâp lă đệ quy vă phương phâp không đệ quy.
IV.1.a. Phương phâp đệ quy
Bước 1: Lưu giữ mău của điểm P(x0,y0) văo một biến: OldColor:=Color(P) Bước 2: Tô mău cho điểm P(x0,y0)
Bước 3: Xâc định câc điểm lđn cận Ti (i=1..4) có mău OldColor (cùng mău với P trước khi tô)
Bước 4: Xem Ti như vai trò của P vă thực hiện lại từ bước 1.
Kết luận: Thuật toân trín sẽ dừng khi không xâc định được Ti ở tất cả câc lần đệ quy.
IV.1.a.i. Căi đặt thuật toân
Sau đđy lă thủ tục minh hoạ cho thuật giải trín {Văo: toạ độ của điểm P vă mău cần tô cho vùng Q
Ra : Không. Kết quả công việc lă tô mău vùng Q trín măn hình} Procedure LoangMauDeQuy(x,y:integer; NewColor:byte); Var OldColor:byte; Begin OldColor:=GetPixel(x,y) if OldColor=NewColor then exit else begin PutPixel(x,y,NewColor);
If (x>0) and (GetPixel(x-1,y)=OldColor) then LoangMauDeQuy(x-1,y,NewColor);
If (x<GetMaxX) and (GetPixel(x+1,y)=OldColor) then LoangMauDeQuy(x+1,y,NewColor);
If (y>0) and (GetPixel(x,y-1)=OldColor) then LoangMauDeQuy(x,y-1,NewColor);
If (y<GetMaxY) and (GetPixel(x,y+1)=OldColor) then LoangMauDeQuy(x,y+1,NewColor);
end; End;
Nhược điểm của phương phâp đệ quy lă không thực hiện được khi vùng loang có diện tích lớn (dẫn đến trăn Stack).
IV.1.b. Phương phâp không đệ quy
Trín cơ sở của ý tưởng trín song được xđy dựng lại để trânh gọi đệ quy lăm hạn chế không gian tô
Bước 1: Khởi tạo một hăng đợi Q với phần tử đầu tiín lă P(x0,y0). Gọi OldColor lă mău của điểm P (OldColor=Color(P))
Bước 2: Khi hăng đợi không rỗng thì: lấy ra từ hăng đợi Q một điểm T. Nếu mău hiện thời của T lă OldColor thì:
+ Tô mău điểm T
+ Tìm câc điểm lđn cận của T có mău lă OldColor vă đưa chúng văo hăng đợi Q.
Bước 2 năy được lặp đi lặp lại cho đến khi hăng đợi Q rỗng.
Thuật toân trín có một nhược điểm lă đôi khi một điểm được đưa văo hăng đợi nhiều hơn một lần, từ đó ta có thể tinh chỉnh ở chỗ câc điểm lđn cận cùng mău chỉ được đưa văo khi nó chưa có trong hăng đợi. Song việc kiểm tra năy sẽ dẫn đến một sự hao phí về thời gian thực hiện kiểm tra hăng đợi, vậy nín ta có thể bỏ qua.
IV.1.b.i. Căi đặt thuật toân
Sinh viín cần xđy dựng thủ tục tô mău theo thuật giải “Vết dầu loang” sử dụng hăng đợi để khử đệ quy như đê níu ở trín.
Sau đđy lă một giải phâp căi đặt minh hoạ:
program Chuong_Trinh_To_Mau_Theo_Thuat_Toan_Vet_Dau_Loang; uses crt,graph;
procedure init; {Khởi tạo chế độ đồ họa} var
grMode: Integer; ErrCode: Integer; begin
grDriver := Detect;
InitGraph(grDriver, grMode,'đường dẫn đến thư mục chứa file egavga.bgi'); ErrCode := GraphResult;
if ErrCode <> grOk then
Writeln('Graphics error:', GraphErrorMsg(ErrCode)); end; procedure loangmau(x,y:integer;maumoi:byte); type DS=^danhsach; danhsach=record x,y:integer; next:DS; end; var dau,cuoi:ds;maucu:byte; Procedure Push(x,y:integer); Var P:DS; begin New(P);P^.x:=x;P^.y:=y;P^.next:=nil; If Dau=nil then Dau:=P else Cuoi^.next:=P; Cuoi:=p; end;
Procedure Pop(Var x,y:integer); Var P:DS; begin P:=Dau; Dau:=Dau^.next; x:=P^.x; y:=P^.y; dispose(p); end; begin maucu:=getpixel(x,y); if maucu=maumoi then exit; Dau:=Nil;Push(x,y); while (dau<>nil) do begin Pop(x,y); if (getpixel(x,y)=maucu)and(maxavail>sizeof(ds)) then begin putpixel(x,y,maumoi); if (x>0)and(getpixel(x-1,y)=maucu) then Push(x-1,y); if (x<getmaxx)and(getpixel(x+1,y)=maucu) then Push(x+1,y); if (y>0)and(getpixel(x,y-1)=maucu) then Push(x,y-1);
if (y<getmaxy)and(getpixel(x,y+1)=maucu) then Push(x,y+1); end; end; end; BEGIN init; rectangle(50,50,480,380); line(50,50,155,370);line(155,370,165,55); loangmau(60,60,4); readln; closegraph; END.
IV.2. Thuật toân tô mău đa giâc theo dòng quĩt (Scan-line Algorithm).
Thuật toân năy sử dụng giao điểm giữa câc cạnh biín của đa giâc với câc đường thẳng nằm ngang gọi lă dòng quĩt di chuyển từ trín xuống dưới để xâc định ra câc đoạn con nằm trong đa giâc vă tô mău cho chúng.
Hình III-8. Minh họa thuật toân Scan-line
Ví dụ: x1x2 x1 x2 x2x3 x1 x4 x1 x2x3 x4 x5 Scan-line 1 Scan-line 2
Hình III-10. Hình ảnh phóng lớn mô tả quâ trình tô mău đa giâc
Để hiểu rõ hơn tư tưởng của giải thuật ta hêy tìm hiểu một ví dụ sau:
Cho miền D được bao bởi một đường cong kín không tự cắt G vă một điểm P như trong hình vẽ, cần xâc định điểm P lă trong hay ngoăi miền D?
Để trả lời cđu hỏi năy ta tiến hănh như sau: + Xâc định một điểm Q năo đó ở ngoăi miền D
+ Tìm số giao điểm của đoạn thẳng PQ với G, nếu số giao điểm năy lă chẵn thì P không thuộc D, ngược lại thì P nằm trong miền D khi số giao điểm lă lẻ.
P
Q
Hình III-11. Minh họa băi toân Mí Cung
Miền D xem như được bao bọc kín bởi tường thănh G. Nếu một con kiến xuất phât từ Q vă bò dọc theo đoạn thẳng QP để hướng đến P. Rõ răng lúc đầu nó ở ngoăi thănh (ngoăi miền D), sau lần vượt thănh đầu tiín (qua giao điểm) thì nó sẽ văo trong, nếu nó vượt thănh lần nữa thì rõ răng lă nó ra khỏi thănh, nếu nó lại tiếp tục vượt thănh thì nó lại văo trong, rồi lại vượt để ra ngoăi... Rõ răng ta thấy nến số lần vượt lă lẻ thì nó ở trong thănh, ngược lại nếu số lần vượt lă chẵn thì nó ở ngoăi thănh.
Hay nhìn ở góc độ khâc thì ta có câc đoạn thẳng nằm trong đa giâc lă câc đoạn được tạo bởi cặp giao điểm xk với xk+1 với k=1,3,5,7...
Từ băi toân trín ta thấy để tô mău đa giâc ta chỉ việc cho dòng quĩt (Scan-line) chạy từ đỉnh cao nhất của đa giâc đến đỉnh thấp nhất của đa giâc, trong mỗi lần chạy ta xâc định số giao điểm của đường chạy ngang với đa giâc, câc giao điểm được sắp theo thứ tự tăng dần theo hoănh độ gọi lă x1, x2,..., x2n (n>0). vă ta chỉ việc tô câc đoạn x1x2, x3x4,...,x2n-1x2n.
Song để tìm giao điểm của dòng quĩt với đa giâc ta phải tìm giao điểm với câc cạnh của đa giâc. Do đó điều tất yếu lă tại những đỉnh sẽ có 2 giao điểm (giao điểm kĩp) vă nó sẽ lăm cho quy tắc tô trín sai nếu hai cạnh xuất phât từ đỉnh năy nằm về hai phía của đường quĩt. Vậy trong tình huống dòng quĩt đi qua đỉnh thì
nếu hai cạnh xuất phât từ đỉnh năy nằm về hai phía của đường quĩt thì ta cần bỏ bớt đi một giao điểm.
IV.2.a. Căi đặt thuật toân
Sinh viín cần viết một thủ tục tô mău cho một đa giâc bất kỳ (với đầu văo lă một mảng câc đỉnh của đa giâc)
V. Băi tập cuối chương
1. Căi đặt thủ tục xĩn đoạn thẳng văo đa giâc, xĩn đoạn thẳng văo Ellipse, Xĩn Ellipse văo hình chữ nhật.
2. Căi đặt thủ tục tô mău đa giâc theo mẫu tô (tô có hoa văn)
a. Khi mẫu lă một ma trận 8x8 bít, nếu bít = 1 thì được tô ngược lại thì không tô
b. Khi mẫu tô lă một ảnh bitmap kích thước mxn
3. Bổ sung văo thư viện do bạn căi đặt được ở chương trước câc thủ tục xĩn vă tô mău
Chương IV: Câc phĩp biến đổi hình học