计算机图形学——区域填充算法

一、区域填充概念

区域:指已经表示成点阵形式的填充图形,是象素的集合。

区域填充:将区域内的一点(常称【种子点】)赋予给定颜色,然后将这种颜色扩展到整个区域内的过程。

区域填充算法要求区域是连通的,因为只有在连通区域中,才可能将种子点的颜色扩展到区域内的其它点。

1、区域有两种表示形式

1)内点表示:枚举出区域内部的所有象素,内部所有象素着同一个颜色,边界像素着与内部象素不同的颜色。
2)边界表示:枚举出区域外部的所有象素,边界上的所有象素着同一个颜色,内部像素着与边界象素不同的颜色。

2、区域连通

1)四向连通区域:从区域上一点出发可通过【上、下、左、右】四个方向移动的组合,在不越出区域的前提下,到达区域内的任意象素。
2)八向连通区域:从区域上一点出发可通过【上、下、左、右、左上、右上、左下、右下】八个方向移动的组合,在不越出区域的前提下,到达区域内的任意象素。

二、简单种子填充算法

基本思想

给定区域G一种子点(x, y),首先判断该点是否是区域内的一点,如果是,则将该点填充为新的颜色,然后将该点周围的四个点(四连通)或八个点(八连通)作为新的种子点进行同样的处理,通过这种扩散完成对整个区域的填充。

这里给出一个四连通的种子填充算法(区域填充递归算法),使用【栈结构】来实现
原理算法原理如下:种子像素入栈,当【栈非空】时重复如下三步:

算法代码

这里给出八连通的种子填充算法的代码:

void flood_fill_8(int[] pixels, int x, int y, int old_color, int new_color)
{
    if(x<w&&x>0&&y<h&&y>0)
    {
        if (pixels[y*w+x]==old_color)
        {
            pixels[y*w+x]== new_color);
            flood_fill_8(pixels, x,y+1,old_color,new_color);
            flood_fill_8(pixels, x,y-1,old_color,new_color);
            flood_fill_8(pixels, x-1,y,old_color,new_color);
            flood_fill_8(pixels, x+1,y,old_color,new_color);
            flood_fill_8(pixels, x+1,y+1,old_color,new_color);
            flood_fill_8(pixels, x+1,y-1,old_color,new_color);
            flood_fill_8(pixels, x-1,y+1,old_color,new_color);
            flood_fill_8(pixels, x-1,y-1,old_color,new_color);
        }
    }
}

简单种子填充算法的不足

a)有些像素会多次入栈,降低算法效率,栈结构占空间
 b)递归执行,算法简单,但效率不高,区域内每一像素都要进/出栈,费时费内存
 c)改进算法,减少递归次数,提高效率

三、扫描线种子填充算法

基本思想

给定的种子点开始,填充当前扫描线上种子点所在的一区段,然后确定与这一段相邻的上下两条扫描线上位于区域内的区段(需要填充的区间),从这些区间上各取一个种子点依次把它们存起来,作为下次填充的种子点。反复进行这过程,直到所保存的各区段都填充完毕。

算法步骤

步骤 1:(初始化)将算法设置的堆栈置为空。将给定的种子点(x, y)压入堆栈
步骤 2:(出栈)如果堆栈为空,算法结束;否则取栈顶元素(x, y)作为种子点
步骤 3:(区段填充)从种子点(x, y)开始,沿纵坐标为y的当前扫描线向左右两个方向逐个像素用新的颜色值进行填充,直到边界为止即象素颜色等于边界色。设区间两边界的横坐标分别为xleftxright
步骤4:在与当前扫描线相邻的上下两条扫描线上,以区间[xleft, xright]为搜索范围,求出需要填充的各小区间,把各小区间中最右边的点并作为种子点压入堆栈,转到步骤2。

算法的关键原则

1)搜索原则:

从前一个填充的区间(边界之间的范围xleft, xright)作为后一条扫描线种子点寻找的范围。

2)填充原则:

从种子点往左,右填,填到边界

实例

上述算法的描述过于抽象,直接看演示

算法代码

Stack stack=new Stack();//堆栈 pixel_stack初始化
Stack.push (point);    //(x,y)是给定的种子像素
while (!stack.empty())
{
    p=(Point)(stack.pop());//出栈,从堆栈中取一像素作种子像素
    x=p.x;
    y=p.y;
    savex=x;//保存种子点的横坐标x的值
    while (pixels [y*w+x]!= boundary_color)
    {
        pixels [y*w+x]= new_color;
        x++;
    } //从种子像素开始向右填充到边界
    xright=x–1; //保存线段的右端点
    x=savex–1;  //设定种子点往左填充的起点
    while (pixels [y*w+x]!= boundary_color)
    {
        pixels [y*w+x] = new_color;
        x=x–1;
    }
    //从种子像素开始向左填充到边界,以上两步完成区间填充。
    xleft=x+1; //保存线段的左端点,加1是因为前面 循环时多减一次
    x=xleft;     //起点是上次的左端点
    y=y+1;     //开始处理上一条扫描线
    while(x<=xright)   //在上一条扫描线上检查是否需要填充
    {
        span_need_fill=false;   //先设定为不需要填充
        while (pixels [y*w+x] ==old_color&&x<=xright )
        {
            //待填充的线段
            span_need_fill=true; //发现有旧象素,需要填充
            x=x+1;
        } //待填充的线段处理完,即遇到边界色,!=old_color跳出

        if (span_need_fill)   //如果区间需要填充,则将其右端点作为种子点压进堆栈
        {
            p=new Point(x-1,y);
            stack.push (p); //进栈
            span_need_fill=false;
        }
        //继续向右检查以防有遗漏
        while (pixels [y*w+x] !=old_color &&x<=xright )
            x=x+1;
    } //在上一条扫描线上检查完
    x=xleft;
    y=y–2; //形成下一条扫描线的y值
//在下一条扫描线上从左向右检查位于区间[xleft,xright]上的像素,其方法与在上一条扫描线上检查的情况完全一样,见书。
}//出栈完

四、多边形的扫描转换与区域填充算法小结

上一篇博客讲述了多边形的扫描转换,这里将多边形扫描转换和区域填充算法进行比较总结。

基本思想不同

多边形扫描转换是指将多边形的顶点表示转化为点阵表示

区域填充只改变填充颜色,不改变区域表示方式

基本条件不同

在区域填充算法中,要求给定区域内的一点作为种子点,然后从这一点根据连通性将新的颜色扩展到整个区域。

扫描转换多边形是从多边形的边界(顶点)信息出发,利用多种形式的连贯性进行填充的。

扫描转换区域填充的核心是知道多边形的边界,要得到多边形内部的像素集,有很多种办法。其中扫描线算法是利用一套特殊的数据结构,避免求交,然后一条条扫描线确定。

区域填充条件更强一些,不但要知道边界,而且要知道区域内的一点,可以利用四连通或八连通区域不断向外扩展。

填充一个定义的区域的选择包括:

a)选择实区域颜色或图案填充方式

b)选择某种颜色和图案

这些填充选择可以应用于多边形区域或用曲线边界定义的区域;此外,区域可用多种画笔、颜色和透明度参数来绘制

原文地址:https://www.cnblogs.com/wkfvawl/p/11625712.html

时间: 2024-08-29 14:15:03

计算机图形学——区域填充算法的相关文章

[计算机图形学] 基于C#窗口的Bresenham直线扫描算法、种子填充法、扫描线填充法模拟软件设计(一)

一.首先说明: 这是啥? —— 这是利用C#FORM写的一个用来演示计算机图形学中 ①Bresenham直线扫描算法(即:连点成线):②种子填充法(即:填充多边形):③扫描线填充法 有啥用? ——  无论是连点成线还是区域填充在高级编程中基本上都提供很高效的库函数来调用.这里拿出这些算法一方面有利于大家理解那些封装的函数底层是实现:另一方面是方便嵌入式TFT屏幕底层驱动开发时借鉴的. 是啥样? ——  如下面的操作,不言而喻. 二.进入正题: 2-1.直线的扫描转换 图形的扫描转换实质就是在光栅

计算机图形学(三种画线算法)

第二章:光栅图形学算法 1.光栅显示器:光栅扫描式图形显示器简称光栅显示器,是画点设备,可看作是一个点阵单元发生器,并可控制每个点阵单元的亮度 2.由来:随着光栅显示器的出现,为了在计算机上处理.显示图形,需要发展一套与之相适应的算法. 3.研究内容: 1>直线段的扫描转换算法 2>多边形的扫描转换与区域填充算法 3>裁剪算法 4>反走样算法 5>消隐算法 一.直线段的扫描转换算法 1.为了显示一条直线,就在光栅显示器上用离散的像素点逼近直线,所以我们就要知道这些像素点的坐标

计算机图形学 有效边表填充算法(6)

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40154077 本文通过一个完整的实例,展示多边形有效边表填充算法. 1)创建CAET类 头文件:AET.h // AET.h: interface for the CAET class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_AET_

计算机图形学 直线反走样Wu算法(4)

作者:卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40048285 本文通过一个完整的实例来演示,直线反走样Wu算法. 1)创建CP2类 头文件:P2.h // P2.h: interface for the CP2 class. // ////////////////////////////////////////////////////////////////////// #if !defined(AFX_P2_H__DD2

计算机图形学之光栅图形学——多边形的扫描转换之 X-扫描算法及改进

本文是对 赵明老师 <计算机图形学>MOOC课程 部分章节的小总结. 多边形有两种表示方法:顶点表示和点阵表示. X-扫描线算法: 算法步骤概括如下: 注意: 改进: 为了避免求交运算,引进一套特殊的数据结构:

计算机图形学 Cohen-Sutherland直线段裁剪算法

作者 : 卿笃军 原文地址:http://blog.csdn.net/qingdujun/article/details/40822977 本文通过一个完整的实例演示Cohen-Sutherland直线段裁剪算法. 1)创建类CP2 头文件:P2.h // P2.h: interface for the CP2 class. // ////////////////////////////////////////////////////////////////////// #if !defined

计算机图形学——光栅图形学直线算法简介

本文是对 赵明老师 <计算机图形学>MOOC课程 部分章节的小总结. 直线是组成图形的基础,其算法往往被多次调用,其好坏直接影响图形的显示效果和速度.以下是一些画直线的常用算法. 1.DDA算法: 此算法基于增量思想. 对于直线的斜截式:y=kx+b,考虑每次 x 递增 1, 都有 y[i+1] = y[i] + k,这样就将 kx 部分的乘法转换成递推的加法. 由于像素点都是整数坐标,所以每次求得的 y 都要取整操作,采用加 0.5 取整数部分的方法:(int)(y[i]+0.5). 但是,

计算机图形学之光栅图形学——反走样算法简介

本文是对 赵明老师 <计算机图形学>MOOC课程 部分章节的小总结. 走样是数字化不可避免的. 简化:

计算机图形学中的种子填充算法c++程序实现

种子填充其实很简单,计算机图形学中介绍的使用栈,感觉作者是不是脑子进水了,直接使用一个队列用广搜就可以了啊,但是我就懒得写了,直接一个递归算了,有兴趣的同学自己试一试 #include<graphics.h>#include<conio.h>  #include<stdio.h>#include<math.h>int Graph[500][500] ; void scanline_seed_fill(int color,int sx,int sy){ Gra