c++实现扫描线种子填充算法
今天我们来介绍一种利用堆栈实现的填充算法,这种算法相比于直接使用递归实现的填充算法(如内点表示的四连通种子填充算法)来说,它需要的堆栈大小不需要那么庞大,下面是具体实现:...
·
今天来介绍一种利用堆栈实现的填充算法,这种算法相比于直接使用递归实现的填充算法(如内点表示的四连通种子填充算法)来说,它需要的堆栈大小不需要那么庞大,下面是在MFC中实现方法。
一.基本思想
在任意不间断区间(一条扫描线上的一组相邻像素)中,只取一个种子像素,填充当前扫描线上的该段区间,然后确定与这一段相邻的上下两条扫描线位于区域内的区段,并依次把他们保存起来,反复进行这个过程,直到所保存的每个区段都填充完毕
二.具体算法
- 初始化:堆栈置空,将种子点入栈。
- 出栈:若栈空则结束,否则栈顶元素(x,y)出栈,并以y值作为当前扫描线号。
- 填充并确定种子点所在区段:从种子(x,y)出发,沿当前扫描线向左、向右两个方向逐个像素填充,直到遇到边界像素为止。分别标记区段的左、右端点坐标为xl和xr。
- 确定新的种子点:在区间[xl,xr]中检查与当前扫描线y相邻的上下两条扫描线上的像素。若存在非边界、未填充的像素,则把每一区间的最右像素作为种子点压入堆栈,返回第2步。否则直接返回第2步。
其中确定新的种子点的具体算法如下(以当前扫描线y上侧为例,下侧也类似)
横坐标i从 xl+1开始,当小于xr时进行下面的循环:
- 当以(i,y+1)为坐标的像素点颜色不为边界颜色且也未被填充时,即说明找到一个未填充区域,此时要寻找区域最右端坐标。
- 令j=i+1
- 以(j,y+1)为坐标的像素点颜色不是边界颜色时,循环执行j++,否则退出循环(此时说明到达该区间的最右端)
- 令i=j-1(i下一次寻找的坐标从当前区间的最右像素点开始)
- i++
- 返回步骤1
实现代码
//在当前扫描线上下两端寻找新的种子
//stack为系统堆栈
void FindNewSeed(stack<CPoint>& s, int left, int right, int y, COLORREF bcolor, COLORREF ncolor)
{
for (int i = left + 1; i < right; i++)
{
if (GetPixel(i, y) != bcolor && GetPixel(i, y) != ncolor)
{
int j = i + 1;
while (GetPixel(j, y) != bcolor)
j++;
i = j--;
s.push(CPoint(j, y));
}
}
}
//扫描线种子填充算法
void ScanLineFlood(int x, int y, COLORREF bcolor, COLORREF ncolor)
{
stack<CPoint> s;
CPoint p;
int left, right;
s.push(CPoint(x, y));
while (!s.empty())
{
//栈顶元素出栈
p = s.top();
s.pop();
//向左填充
for (left = p.x; GetPixel(left, p.y) != bcolor; left--)
SetPixel(left, p.y, ncolor);
//向右填充
for (right = p.x + 1; GetPixel(right, p.y) != bcolor; right++)
SetPixel(right, p.y, ncolor);
//在当前行的下一行寻找确定新的种子点
FindNewSeed(s, left, right, p.y-1, bcolor, ncolor);
//在当前行的上一行寻找确定新的种子点
FindNewSeed(s,left,right,p.y+1,bcolor,ncolor);
}
}
若有不对的地方请指正,不胜感激!!!
更多推荐
所有评论(0)