1. 程式人生 > >種子填充演算法(簡單和掃描線)

種子填充演算法(簡單和掃描線)

簡單的種子填充演算法

掃描線種子填充演算法

種子填充演算法的思路就是通過區域的一點賦予指定的顏色,然後通過填充其周圍的畫素點,從而將填充顏色擴充套件到整個顏色區域的過程。

如何畫圖

我們已經知道有很多工具可以拿來畫圖,比如MFC或者是OpenGL都是畫圖很好的手段。這兩個都是擁有很多適應方法的軟體介面。但是我使用的是Easyx這個更加方便便捷的工具。

該工具可以在如下頁面下載,安裝至相應的編譯器即可。

下載完成之後記得安裝Easyx裡面的Easyx_Help.chm,這裡面有許多我們開發會運用到的方法。

我們也知道種子填充演算法需要獲取點的顏色和在某個點再畫上你需要的顏色,所以需要用到如下方法

//這個是為了獲取某座標點的顏色
COLORREF getpixel(int x, int y);
//這個是為了在某個點畫上你想要的顏色
void putpixel(int x, int y, COLORREF color);

簡單的種子填充演算法

我們需要的是通過getpixel方法來獲取點的顏色,判斷其是否與原顏色相同,如果不相同,則變化其顏色為新的 顏色,通過遞迴其4連通區域來達到有序在不越出區域的情況下,到達區域內的任意元素。

 void FloodFill4_1(int x, int y, COLORREF oldcolor, COLORREF newcolor) {
     try
{ if (x > 100 && x < 300 && y > 100 && y < 300) { if (getpixel(x, y) == oldcolor) { Sleep(1); putpixel(x, y, newcolor); FloodFill4_1(x, y + 1, oldcolor, newcolor); FloodFill4_1(x, y - 1
, oldcolor, newcolor); FloodFill4_1(x - 1, y, oldcolor, newcolor); FloodFill4_1(x + 1, y, oldcolor, newcolor); } } } catch (stack) { } }

掃描線種子填充演算法

掃描線填充可由以下4個步驟實現

  1. 初始化:堆疊置空。講種子點(x,y)入棧
  2. 出棧:若棧空則結束。否則取棧頂元素(x,y),以y作為當前掃描線。
  3. 填充並確定種子點所在區段:從種子點(x,y)出發,沿當前掃描線向左、右兩個方向填充,直到邊界。分別標記區段的左、右端點座標為xlxr
  4. 確定新的種子點:在區間[xl,xr]中檢查與當前掃描線y上、下相鄰的兩條掃描線上的畫素。若存在非邊界、未填充的畫素,則把每一區間的最右畫素作為種子點壓入堆疊,返回第2步。
 void ScanFill4(int x, int y, int oldcolor, int newcolor)
 {
     int xl, xr, i;
     bool spanNeedFill;
     Seed pt;
     stack *stack1 =  new stack();
     InitStack(stack1);
     pt.x = x;
     pt.y = y;
     Push(stack1, pt);    //將前面生成的區段壓入堆疊
     while (!IsEmpty(stack1))
     {
         Sleep(10);
         pt = Pop(stack1);
         y = pt.y;

         x = pt.x;
         while (getpixel(x, y) == oldcolor)//向右填充
         {
             putpixel(x, y, newcolor);
             x++;
         }
         xr = x - 1;

         x = pt.x - 1;
         while (getpixel(x, y) == oldcolor) //向左填充
         {
             putpixel(x, y, newcolor);
             x--;
         }
         xl = x + 1;


         //處理上一條掃描線
         x = xl;
         y = y + 1;
         while (x<xr)
         {
             spanNeedFill = false;
             while (getpixel(x, y) == oldcolor)
             {
                 spanNeedFill = true;
                 x++;
             }
             if (spanNeedFill)
             {
                 pt.x = x - 1;
                 pt.y = y;
                 Push(stack1, pt);
                 spanNeedFill = false;
             }
             while (getpixel(x, y) != oldcolor  && x<xr)
                 x++;
         }
         //處理下一條掃描線,程式碼與處理上一條掃描線類似
         x = xl;
         y = y - 2;
         while (x<xr)
         {
             spanNeedFill = false;
             while (getpixel(x, y) == oldcolor)
             {
                 spanNeedFill = true;
                 x++;
             }
             if (spanNeedFill)
             {
                 pt.x = x - 1;
                 pt.y = y;
                 Push(stack1, pt);
                 spanNeedFill = false;
             }
             while (getpixel(x, y) != oldcolor  && x<xr)
                 x++;
         }
     }
 }

上述演算法對於每一個待填充區段,只需要壓棧一次,而在遞迴演算法中每一個畫素都需要壓棧一次。大大提高了區域填充的效率。

演算法中遇到的問題

在編寫簡單的種子演算法中遇到了堆疊溢位的問題,這也是正常所在,遞迴每個畫素都需要壓棧,而Visal Studio的初始設定安全堆疊大小已經過於小了,臨時解決辦法為:

Project->Property->Linker->All Options中找到Stack Reserve Size 儘量將其調大就行了