【寒江雪】区域填充算法——扫描线

区域填充递归算法已经领教过了。内存消耗大,时间效率低,经典的深搜思想。为了解决这个问题,于是有人提出了种子填充扫描线算法。其实就是深搜不行,换宽搜(BFS)

该算法假设已知其中一个像素点,然后从这个像素点出发,去寻找周围可以着色的点。

这个已知点,我们称其为种子点。

每一轮着色之后,记录下着色的区间大小,并对该区间上方和下方的扫描线进行扫描,观察能否对其进行着色,如果能,则把种子点加入队列中,待下次扫描使用。对于一条扫描线,可能有很多可着色区间,因此需要扫描更多的种子点,加入队列中。

 

该算法同样分为两种来讨论

1.    以边色为界限的着色

a)     先将种子点加入队列中

b)     如果队列不为空则继续往下执行,否则算法结束

c)     从队列中取出种子点

d)     以种子点为起点,往右边着色直到边界,记录区间右界xr

e)     以种子点为起点,往左边着色直到边界,记录区间左界xl

f)      对区间[xl,xr]扫描上一条扫描线,遇到颜色不为边界颜色的点,寻找其最右边界,并标记为可以加入队列。遇到边界点则不再往下寻找

g)     如果可以加入队列,则往队列中加入新的种子点

h)     对下边一条扫描线做同样的操作。

代码如下

struct Seed{int x;int y;};

VOID CGraphicDlg::ScanLineBoundaryFill(int x, int y, COLORREF edgeColor, COLORREF newColor)

{

    int xl, xr;

    bool spanNeedFill;

    Seed pt;

    queue<Seed> que;

    que.push(Seed{ x,y });

    while (!que.empty()) {

        pt = que.front();

        que.pop();

        int x = pt.x;

        int y = pt.y;

       

        while (GetCoordinatePixel(x, y) != edgeColor) {//向右填充

            DrawRectange(x, y, 0, 0, newColor);

            x++;

        }

        xr = x - 1;

        x = pt.x - 1;

        while (GetCoordinatePixel(x, y) != edgeColor) {//向左边填充

            DrawRectange(x, y, 0, 0, newColor);

            x--;

        }

        xl = x + 1;

        //处理上一条扫描线

        x = xl;

        y = pt.y+1;

        while (x <= xr) {

            spanNeedFill = false;

            if (GetCoordinatePixel(x, y) == newColor)break;

            while (GetCoordinatePixel(x, y) != edgeColor) {

                spanNeedFill = true;

                x++;

            }

            if (spanNeedFill) {

                que.push(Seed{x - 1, y});

                spanNeedFill = false;

            }

 

            while (GetCoordinatePixel(x, y) == edgeColor ) { x++;}

        }

 

        //处理下一条扫描线

        x = xl;

        y = pt.y - 1;

        while (x <= xr) {

            spanNeedFill = false;

            if (GetCoordinatePixel(x, y) == newColor)break;

            while ( GetCoordinatePixel(x, y) != edgeColor) {

                spanNeedFill = true;

                x++;

            }

 

            if (spanNeedFill) {

                que.push(Seed{ x - 1,y });

                spanNeedFill = false;

            }

            while (GetCoordinatePixel(x, y) == edgeColor) { x++;}

        }

    }

    return VOID();

}

效果图如下:

图片 

2.    以点色为界限的着色

a)     先将种子点加入队列中

b)     如果队列不为空,则算法继续执行,否则算法结束

c)     从队列中取出种子点

d)     以种子点为起点,往右填充,对于颜色与旧颜色一样的像素填充新颜色。如果颜色与旧颜色不一样则不再往下填色。记录区间右边界xr

e)     以种子点为起点,往左填充,对于颜色与旧颜色一样的像素填充新颜色。如果颜色与旧颜色不一样则不再往下填色。记录区间左边界xl

f)      对上一条扫描线区间[xl,xr]进行扫描,如果找到颜色与旧颜色一样的像素,则标记为该扫描线可填充,如果找到颜色与旧颜色不一样的像素则停止寻找。

g)     如果该扫描线有可填充的点,则把该点作为种子点加入队列中。

h)     继续寻找该扫描线其他扫描点,直到x达到xr

i)      对下一条扫描线做同样的操作

代码如下

VOID CGraphicDlg::ScandLinePointFill(int x, int y, COLORREF oldColor, COLORREF newColor)

{

    int xl, xr;

    bool spanNeedFill;

    Seed pt;

    queue<Seed> que;

    que.push(Seed{ x,y });

    while (!que.empty()) {

        pt = que.front();

        que.pop();

        x = pt.x;

        y = pt.y;

        while (GetCoordinatePixel(x, y) == oldColor) {//向右填充

            DrawRectange(x, y,0,0,newColor);

            x++;

        }

        xr = x - 1;

        x = pt.x - 1;

        while (GetCoordinatePixel(x, y) == oldColor) {

            DrawRectange(x, y, 0, 0, newColor);

            x--;

        }

        xl = x + 1;

        //处理上一条扫描线

        x = xl;

        y = pt.y + 1;

        while (x <= xr) {

            spanNeedFill = false;

            while (GetCoordinatePixel(x, y) == oldColor) {

                spanNeedFill = true;

                x++;

            }

            if (spanNeedFill) {

                spanNeedFill = false;

                que.push(Seed{ x - 1,y });

            }

            while (GetCoordinatePixel(x, y) != oldColor&&x <= xr)x++;

        }

 

        //处理下一条扫描线

        x = xl;

        y = pt.y - 1;

        while (x <= xr) {

            spanNeedFill = false;

            while (GetCoordinatePixel(x, y) == oldColor) {

                spanNeedFill = true;

                x++;

            }

            if (spanNeedFill) {

                spanNeedFill = false;

                que.push(Seed{ x - 1,y });

            }

            while (GetCoordinatePixel(x, y) != oldColor&&x <= xr)x++;

           

        }

    }

    return VOID();

}

效果图如下(纯色基础)

图片

 

效果图如下(无纯色基础)

图片

效果图如下(坐标轴点为起始种子点)

图片

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值