图形学种子填充算法
种子填充算法
![种子填充算法](https://img.taocdn.com/s3/m/45b69139647d27284b735148.png)
一、实验目标1.了解基于种子填充算法的基本思想;2.掌握基于种子填充算法的算法实现;3.掌握栈的使用。
二、实验内容本次实验主要是实现递归种子填充算法、简单种子填充算法、扫描线种子填充算法以及区域图案填充算法。
种子填充算法原理简述:在开始介绍种子填充算法之前,首先也介绍两个概念,就是“4-连通算法”和“8-连通算法”。
既然是搜索就涉及到搜索的方向问题,从区域内任意一点出发,如果只是通过上、下、左、右四个方向搜索到达区域内的任意像素,则用这种方法填充的区域就称为四连通域,这种填充方法就称为“4-连通算法”。
如果从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下全部八个方向到达区域内的任意像素,则这种方法填充的区域就称为八连通域,这种填充方法就称为“8-连通算法”。
种子填充算法采用的边界定义是区域边界上所有像素均具有某个特定的颜色值,区域内部所有像素均不取这一特定颜色,而边界外的像素则可以具有和边界相同的颜色值。
程序从(x,y)开始,先检测该点的颜色,如果它与边界色和填充色均不相同,就用填充色填充该点,然后检测相邻位置,以确定它们是否边界色和填充色,若不是,就填充该相邻点。
这个过程延续到已经检测完边界范围内的所有像素为止。
扫描线种子填充算法原理简述:当给定种子点(x, y)时,首先分别向左和向右两个方向填充种子点所在扫描线上的位于给定区域的一个区段,同时记下这个区段的范围[xLeft, xRight],然后确定与这一区段相连通的上、下两条扫描线上位于给定区域内的区段,并依次保存下来。
反复这个过程,直到填充结束。
扫描线种子填充算法可由下列四个步骤实现:(1)初始化一个空的栈用于存放种子点,将种子点(x, y)入栈;(2)判断栈是否为空,如果栈为空则结束算法,否则取出栈顶元素作为当前扫描线的种子点(x, y),y是当前的扫描线;(3)从种子点(x, y)出发,沿当前扫描线向左、右两个方向填充,直到边界。
计算机图形学实验报告8-种子点填充
![计算机图形学实验报告8-种子点填充](https://img.taocdn.com/s3/m/43d4ef04a300a6c30c229fd0.png)
《计算机图形学实验》报告2016年春季学期实验四:种子点填充算法Seed Filling实验时间:2016年9月底实验地点:实验目的:掌握使用opengl 的种子点填充算法,观察改变参数对生成图形的改变(改变点的位置、颜色等)如果要填充的区域是以图像元数据方式给出的,通常使用种子填充算法进行区域填充。
种子填充算法的核心是一个递归算法,都是从指定的种子点开始,向各个方向上搜索,逐个像素进行处理,直到遇到边界。
种子填充算法常用四连通域和八连通域技术进行填充操作。
从区域内任意一点出发,通过上、下、左、右四个方向到达区域内的任意像素。
用这种方法填充的区域就称为四连通域;这种填充方法称为四向连通算法。
从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下八个方向到达区域内的任意像素。
用这种方法填充的区域就称为八连通域;这种填充方法称为八向连通算法。
算法的优点是非常简单,缺点是需要大量栈空间来存储相邻的点。
程序代码:使用的运行环境是vc++6.0#include <glut.h>#include <fstream>typedef float Color[3];//获取像素点的颜色void getpixel(GLint x, GLint y, Color color) {glReadPixels(x, y, 1, 1, GL_RGB, GL_FLOAT, color); //OPENGL自带}//画点函数void setpixel(GLint x, GLint y) {glBegin(GL_POINTS);glVertex2f(x, y);glEnd();}//比较颜色是否相等int compareColor(Color color1, Color color2) {if (color1[0] != color2[0] || color1[1] != color2[1] || color1[2] != color2[2]) { return 0; }else { return 1; }}void boundaryFill4(int x, int y, Color fillColor, Color boarderColor) {Color interiorColor;getpixel(x, y, interiorColor);if (compareColor(interiorColor, fillColor) == 0 && compareColor(interiorColor, boarderColor) == 0) { setpixel(x, y);boundaryFill4(x + 1, y, fillColor, boarderColor);boundaryFill4(x - 1, y, fillColor, boarderColor);boundaryFill4(x, y + 1, fillColor, boarderColor);boundaryFill4(x, y - 1, fillColor, boarderColor);}}void boundaryFill8(int x, int y, Color fillColor, Color boarderColor) {Color interiorColor, a, b, c, d;getpixel(x, y, interiorColor);getpixel(x + 1, y, a);getpixel(x, y - 1, b);getpixel(x, y + 1, c);getpixel(x - 1, y, d);int i = 0;if (compareColor(a, boarderColor) == 1) i++;if (compareColor(b, boarderColor) == 1) i++;if (compareColor(c, boarderColor) == 1) i++;if (compareColor(d, boarderColor) == 1) i++;if (i <= 1) {if (compareColor(interiorColor, fillColor) == 0 && compareColor(interiorColor, boarderColor) == 0) {setpixel(x, y);boundaryFill8(x+1,y,fillColor,boarderColor);boundaryFill8(x-1,y,fillColor,boarderColor);boundaryFill8(x,y+1,fillColor,boarderColor);boundaryFill8(x,y-1,fillColor,boarderColor);boundaryFill8(x-1,y+1,fillColor,boarderColor);boundaryFill8(x-1,y-1,fillColor,boarderColor);boundaryFill8(x+1,y+1,fillColor,boarderColor);boundaryFill8(x+1,y-1,fillColor,boarderColor);}}}void polygon() {glBegin(GL_LINE_LOOP);glLineWidth(5);//此处修改坐标,绘制多边形glVertex2f(100, 150);glVertex2f(150, 200);glVertex2f(200, 200);glVertex2f(200, 160);glEnd();}void display(void) {Color fillColor = {0.0, 1.0, 1.0};//填充颜色Color boarderColor = {0.0, 1.0, 0.0};//边界颜色glClear(GL_COLOR_BUFFER_BIT);glViewport(0, 0, 500, 500);glColor3fv(boarderColor);polygon();glColor3fv(fillColor);//boundaryFill4(150, 150, fillColor, boarderColor);//设置起点坐标及颜色boundaryFill8(120, 160, fillColor, boarderColor);glFlush();}int main(int argc, char **argv) {glutInit(&argc, argv);glutInitDisplayMode(GLUT_SINGLE | GLUT_RED);glutInitWindowSize(500, 500);glutInitWindowPosition(100, 100);glutCreateWindow("BoundaryFill1");glClearColor(1, 1, 1, 0.0);glMatrixMode(GL_PROJECTION);//投影模型gluOrtho2D(0.0, 500.0, 0.0, 500.0);glutDisplayFunc(display);glutMainLoop();return 0;}实验结果:(更改颜色)(更改形状)。
案例9 区域八邻接点种子填充算法
![案例9 区域八邻接点种子填充算法](https://img.taocdn.com/s3/m/8b1c0c14ba1aa8114431d9e7.png)
总结
八邻接点种子填充算法的种子像素可以位于区域的上方 多边形内或下方多边形内,填充过程不同,但都可以获得一 致的填充效果。
(a)多边形
(b)连接点放大效果图 图9-1八连通域
效果图
图9-2 效果图
原理算法
(1)调用颜色对话框读取填充色。 (2)绘制多边形区域。 (3)设置默认边界色为黑色,默认种子色为蓝色。 (4)鼠标选择种子的像素的坐标(x0,y0)位置,执行x=x0±1与 y=y0±1操作,判断x或y是否到达客户区边界。如果x或y到达客户区边 界,给出“种子不在图形之内”的警告信息,重新选择种子像素的位 置。 (5)将多边形区域内的种子像素入栈。 (6)如果栈不为空,将栈顶像素出栈,用种子色绘制出栈像素。 (7)按左、左上、上、右上、右、右下、下、左下顺序搜索出栈像素 的八个邻接点像素。如果相邻像素的颜色不是边界色并且不是种子色 ,将其入栈,否则丢弃。 (8)重复步骤(6),直到栈为空。
程序代码
填充函数 while(pHead->pNext!=NULL)//如果栈不为空 { CP2 PopPoint; Pop(PopPoint); pDC->SetPixelV(Round(PopPoint.x),Round(PopPoint.y),SeedClr); Left.x=PopPoint.x-1;//搜索出栈结点的左方像素 Left.y=PopPoint.y; PixelClr=pDC->GetPixel(Round(Left.x),Round(Left.y)); if(BoundaryClr!=PixelClr && SeedClr!=PixelClr)//不是边界色并且未置成填充色 Push(Left);//左方像素入栈 LeftTop.x=PopPoint.x-1; LeftTop.y=PopPoint.y+1;//搜索出栈结点的左上方像素 PixelClr=pDC->GetPixel(Round(LeftTop.x),Round(LeftTop.y));
计算机图形学图形区域填充效果
![计算机图形学图形区域填充效果](https://img.taocdn.com/s3/m/aee4b87327284b73f24250d9.png)
// Fill.cpp : implementation file
#include "stdafx.h"
#include "FloodFill.h"
#include "Fill.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
(1)种子填充算法原理
在多边形内部找到一个已知的象素点作为种子点,由此开始,利用区域的连通性找到多边形内部的 其它所有象素点进行填充。
(i)四向连通区域
①四向连通区域概念:从区域上任一点出发,在不超出区域边界的前提下,可通过4个方向:上、下、左、右的移动组合到达区域中的任意象素点,称此区域为四向连通区域。
{
//有需要填充的区域
if(spanNeedFill==FALSE)
{
spanNeedFill = TRUE;
}
x++;
}
if(spanNeedFill)
{
CPoint rightp(x-1,y);
stack.Push(x-1);
stack.Push(y);
spanNeedFill = FALSE;
virtual ~CStack();
};
#endif // !defined(AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_)
CStack.cpp参考代码:
// Stack.cpp: implementation of the CStack class.
#if !defined(AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_) #define AFX_STACK_H__D198F788_4ED1_4C09_98E5_433BAB24D864__INCLUDED_
种子填充算法
![种子填充算法](https://img.taocdn.com/s3/m/a680b7de76eeaeaad1f3308f.png)
Hale Waihona Puke a) 连通域及其内点 b) 填充四连通域
四向连通填充算法:
a) 种子像素压入栈中;
b) 如果栈为空,则转e);否则转c);
c) 弹出一个像素,并将该像素置成填充色;并判断该像素相邻的四连通像素是否为边界色或已经置成多边形的填充色,若不是,则将该像素压入栈;
d) 转b);
从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下八个方向到达区域内的任意像素。用这种方法填充的区域就称为八连通域;这种填充方法称为八向连通算法。
一般来说,八向连通算法可以填充四向连通区域,而四向连通算法有时不能填充八向连通区域。例如,八向连通填充算法能够正确填充如图2.4a所示的区域的内部,而四向连通填充算法只能完成如图2.4b的部分填充。
种子填充算法又称为边界填充算法。其基本思想是:从多边形区域的一个内点开始,由内向外用给定的颜色画点直到边界为止。如果边界是以一种颜色指定的,则种子填充算法可逐个像素地处理直到遇到边界颜色为止。
种子填充算法常用四连通域和八连通域技术进行填充操作。
从区域内任意一点出发,通过上、下、左、右四个方向到达区域内的任意像素。用这种方法填充的区域就称为四连通域;这种填充方法称为四向连通算法。
e) 结束。
图形填充之种子填充算法
![图形填充之种子填充算法](https://img.taocdn.com/s3/m/4540ddd30d22590102020740be1e650e52eacf00.png)
图形填充之种⼦填充算法编译器:VS2013算法:在图形内选择⼀个点为种⼦,然后对这个种⼦四⽅位坐标未着⾊的⼊栈,出栈便着⾊,如此重复,等到栈内为空,则着⾊完成代码:1 #include "stdafx.h"2 #include<stdio.h>3 #include"graphics.h"4 #include<stdlib.h>5 #include<stack>67using namespace std;89//定义结构体存储像素坐标10struct Point11 {12int x;13int y;14 };1516//函数声明17void Boundaryfilling(Point a[], int n);18void judgecolor(int x, int y, stack<int> &sx, stack<int> &sy);1920int main()21 {22int gdriver = DETECT, gmode, n, i;2324 printf("please input number of point:\n");25 scanf_s("%d", &n);2627 Point *p=(Point *)malloc(n*sizeof(Point)); //动态分配内存2829 printf("please input point :\n");30for (i = 0; i < n; i++)31 scanf_s("%d%d", &p[i].x, &p[i].y);3233 initgraph(&gdriver, &gmode, "");3435 setcolor(BLUE);36 setbkcolor(BLACK);3738//画出多边形39for (i = 0; i < n-1; i++)40 line(p[i].x, p[i].y, p[i + 1].x, p[i + 1].y);4142 Boundaryfilling(p, n);4344 system("pause");45 closegraph();4647return0;48 }4950void Boundaryfilling(Point a[], int n)51 {52 stack<int> sx,sy;53int x=0 , y=0 ,x0,y0,i;5455for (i = 0; i < n; i++)56 {57 x += a[i].x;58 y += a[i].y;59 }6061 x = x / (n-1);62 y = y / (n-1);6364 sx.push(x);//x坐标⼊栈65 sy.push(y);//y坐标⼊栈6667while (!sx.empty()) //判断栈是否为空68 {69 x0 = sx.top();70 y0 = sy.top();7172 putpixel(sx.top(), sy.top(), YELLOW); //栈顶元素着⾊73 sx.pop();//栈顶元素出栈74 sy.pop();//栈顶元素出栈7576 judgecolor(x0 - 1, y0, sx, sy);//左边点77 judgecolor(x0 + 1, y0, sx, sy);//右边点78 judgecolor(x0, y0 - 1, sx, sy);//下边点79 judgecolor(x0, y0 + 1, sx, sy);//上边点80 }81 }8283//判断该像素是否没有着⾊84void judgecolor(int x, int y,stack<int> &sx,stack<int> &sy) 85 {86if (getpixel(x, y) == BLACK)87 {88 sx.push(x);89 sy.push(y);90 }91 }结果:。
实验二:图形填充算法实验报告
![实验二:图形填充算法实验报告](https://img.taocdn.com/s3/m/b2ade0d533d4b14e85246829.png)
《计算机图形学》实验报告(实验二:图形填充算法)一、实验目的及要求用两种方法做图形的填充算法!二、理论基础1.边填充算法对于每一条扫描线和每条多边形的交点(x1,y1),将该扫描线上的交点右方的所有像素取补。
2.种子填充算法利用栈来实现种子填充算法。
种子像素入栈,当栈非空时重复执行如下步骤:将栈顶像素出栈,将出栈像素置成多边形色,按左,上,右,下顺序检查与出栈像素相邻的四个像素,若其中某个像素不再边界且未置成多边形,则把该像素入栈!三、算法设计与分析1、边填充算法void CEdge_mark_fillView::OnDraw(CDC* pDC){CEdge_mark_fillDoc* pDoc = GetDocument();ASSERT_V ALID(pDoc);int d[500][500]={0};int inside;int x,y;Bresenham(80,101,100,400,d);Bresenham(100,300,290,400,d);Bresenham(292,400,382,50,d);Bresenham(380,50,202,150,d);Bresenham(200,150,82,101,d);for(y=0;y<500;y++){inside=0;for(x=0;x<500;x++){if(d[x][y]==1)if(d[x+1][y]!=1){inside=!(inside);}if(inside!=0)pDC->SetPixel(x,y,12);}}}2、种子填充int x=299,y=51;COLORREF oldcolor;COLORREF newcolor;oldcolor=RGB(256,256,256);newcolor=RGB(123,123,123);pDC->MoveTo (40,40);pDC->LineTo (80,40);pDC->LineTo (70,80);pDC->LineTo (40,40);FloodFill(51,51,RGB(255,255,255),RGB(0,0,255));pDC->LineTo (40,40);void CMyView::FloodFill(int x,int y,COLORREF oldcolor,COLORREF newcolor) {CDC* pDC;pDC=GetDC();if(pDC->GetPixel(x,y)==oldcolor){pDC->SetPixel(x,y,newcolor);FloodFill(x,y-1,oldcolor,newcolor);FloodFill(x,y+1,oldcolor,newcolor);FloodFill(x-1,y,oldcolor,newcolor);FloodFill(x+1,y,oldcolor,newcolor);}四、程序调试及结果的分析1、2、四、实验心得及建议由于很多不会,所以这次没能按时当堂完成,下来花了不少时间才弄出来,第二种尤其比较麻烦,在同学的帮助下才做出来了。
计算机图形学扫描线种子填充算法
![计算机图形学扫描线种子填充算法](https://img.taocdn.com/s3/m/2f5cb3d050e2524de5187e49.png)
2.1 深度递归的种子填充算法
2.2 扫描线种子填充算法
2.1 深度递归的种子填充算法
种子填色又称边界填色(Boundary Filling)。 它的功能是,给出多边形光栅化后的边界位置及边 界色代码oundary_color,以及多边形内的一点(x, y)位置,要求将颜色fill_color填满多边形。
动画演示
扫描线种子填充算法特点
1. 该算法考虑了扫描线上象素的相关性,种子象 素不再代表一个孤立的象素,而是代表一个尚 未填充的区段。 2. 进栈时,只将每个区段选一个象素进栈(每个 区段最右边或最左边的象素),这样解决了堆 栈溢出的问题。 3. 种子出栈时,则填充整个区段。 4. 这样有机的结合:一边对尚未填充象素的登记 (象素进栈),一边进行填充(象素出栈), 既可以节省堆栈空间,又可以实施快速填充。
3. 已知有一个5边形如下。建立新边表 NET,并写出每一条扫描线经过时活性边 表AET中的数据状态。
X ΔX Ymax
第1项存当前扫描线与边的交点坐标x值; 第2项存从当前扫描线到下一条扫描线间x的增量Dx; 第3项存该边所交的最高扫描线号ymax; 第4项存指向下一条边的指针。
假定当前扫描线与多边形某一条边的交点的x 坐标为x,则下一条扫描线与该边的交点不要重计 算,只要加一个增量△x。(连贯性) 设该边的直线方程为:ax+by+c=0; 若y=yi,x=x i;则当y = y i+1时, x i+1=xi-b/a 其中ΔX= -b/a为常数, 另外使用增量法计算时,我们需要知道一条边 何时不再与下一条扫描线相交,以便及时把它从 活性边表中删除出去。
建立或调整AET(ActiveEdgeList);
fill相关知识点
![fill相关知识点](https://img.taocdn.com/s3/m/32f90841b42acfc789eb172ded630b1c59ee9bd1.png)
填充(Fill)相关知识点填充(Fill)是一种常见的计算机图形学技术,用于在图像或物体的内部或边界区域中填充颜色或纹理。
填充技术在许多领域中被广泛应用,如图像处理、计算机辅助设计(CAD)和计算机游戏开发等。
本文将介绍填充相关的知识点,从基本原理到常见算法,让读者对填充技术有一个全面的了解。
基本原理填充技术的基本原理是通过某种规则或算法,在给定的区域内部或边界上填充颜色或纹理。
这个区域可以是一个简单的几何形状,如矩形或圆形,也可以是一个复杂的多边形。
填充通常从区域内部的某个点开始,按照一定的规则或算法进行扩散,直到填充满整个区域。
基本算法以下是一些常见的填充算法:扫描线填充算法扫描线填充算法是一种基于扫描线的填充方法。
它通过将扫描线与区域的边界进行比较,确定扫描线与区域的交点,并根据规则填充扫描线上的像素。
该算法的优点是简单易懂,并且适用于任意形状的区域。
边界填充算法边界填充算法是一种基于区域边界的填充方法。
它通过检测区域的边界像素,并根据规则填充区域内部的像素。
该算法的优点是填充效果清晰,但对于复杂的区域边界可能会存在一些问题。
种子填充算法种子填充算法是一种基于种子点的填充方法。
它通过选择一个种子点作为起始点,并按照一定的规则或算法进行扩散填充。
种子填充算法适用于复杂的区域填充,但可能存在堆栈溢出的问题。
填充的应用领域填充技术在许多领域中都有广泛的应用,以下是其中一些常见的应用领域:图像处理在图像处理中,填充技术可以用于图像的增强、修复和合成等方面。
例如,可以使用填充技术修复图像中的缺陷、填充图像的边界以及合成多个图像。
计算机辅助设计(CAD)在计算机辅助设计中,填充技术可以用于填充图形对象的内部或边界,以增加图形的真实感和细节。
例如,可以使用填充技术填充建筑物的内部、道路的纹理以及地形的颜色。
计算机游戏开发在计算机游戏开发中,填充技术可以用于填充游戏场景的地形、角色的纹理以及特效的颜色。
通过使用填充技术,可以使游戏画面更加精美和逼真。
种子填充算法
![种子填充算法](https://img.taocdn.com/s3/m/23c1bf21ba68a98271fe910ef12d2af90242a838.png)
种子填充算法
填充算法是随机化的有益的近似算法中的经典例子,用它来解决最大问题可以产生出理想的解决方案。
种子填充算法作为该算法的一种,经常被用来解决贪婪的最大化问题或者寻优,在有限的时间内求解传统最大化目标函数的最优解。
种子填充算法是一种常用的函数字符串优化技术,能以有限的步骤实现最大化随机化优化,在计算图形和调度任务中常用种子填充算法。
主要包括:
1.根据求解的问题,选择最优解种子。
种子是随机产生的群体或者求解器方程,用于准确确定最佳参数;
2.利用种子初始化函数字符串,以较小的步骤完成最大化优化,扩展函数字符串;
3.根据优化的状态和步骤,重新选择种子来改变最大化的结果;
4.重复多步优化,可以得到不同的最优解,对于优化准确率很高。
种子填充算法的优势在于准确地得到期望解,比其它采用搜索的近似解决办法更加精确,且由于经过多次记录,每次重播都能产生一样的最优解。
另外,由于每次迭代中用到种子,可以在不影响目标函数的性能情况下改变最终的优化结果。
种子填充算法目前在理论上和实际应用中都得到了广泛的使用,如求解细胞自动机的模拟、排列调度问题、视觉语义地图等,所有这些问题都是可行空间有限,而且受限于时间和空间,在这些情况下种子填充算法可以有效提高解决问题的效率。
种子填充_计算机图形学教程(第3版)_[共2页]
![种子填充_计算机图形学教程(第3版)_[共2页]](https://img.taocdn.com/s3/m/fef6ddcda8114431b80dd8d7.png)
123 如果用软件实现,边填充算法与多边形区域填充算法的执行速度几乎是相同的。
但是,由于边填充算法最适合具有帧缓冲存储器的图形系统,在帧缓冲存储器中应用该算法时,不必建立和维护边表以及对它进行排序,所以边填充算法比较适合用硬件来实现,此时其执行速度必比多边形区域填充要快一个数量级以上。
4.4.3 种子填充以上讨论的多边形区域填充算法是按扫描线的顺序进行的,而种子填充算法采用的是不同的原理。
它的基本思路是:首先假设在多边形区域的内部,至少有一个像素点(称为种子)是已知的,然后算法开始搜索与种子点相邻且位于区域内的其他像素。
如果相邻点不在区域内,那么到达区域的边界;如果相邻点位于区域内,那么这一点就成为新的种子点,然后继续递归地搜索下去。
这种算法比较适用于光栅扫描设备。
区域的连通情况可以分为四连通和八连通两种。
四连通区域是指各像素在水平和垂直4个方向上是连通的,如图4.46(a )所示。
八连通区域是指各像素在水平、垂直以及4个对角线方向上都是连通的,如图4.46(b )所示。
在种子填充算法中,如果允许从4个方向搜寻下一个像素点,则该算法称为四向算法;如果允许从8个方向搜寻下一个像素点,则该算法称为八向算法。
一个八向算法可以用在四连通区域的填充上,也可用在八连通区域的填充上;而一个四向算法只能用于填充四连通区域。
无论是四向算法还是八向算法,它们的填充算法的基本思想是相同的。
为简单起见,下面只讨论四向种子填充算法。
1.简单种子填充算法这是对定义区域进行填充的算法,此算法所采用的基本方法是:将(x ,y )点与边界值相比较,检测该点的像素是否处在区域之内;同时与新值相比,以确定该点是否已被访问过。
这种测试的前提条件是:在初始状态下,区域内没有一个像素已被设置为新值;同时允许新值等于边界值。
如果用堆栈的方法来实现简单种子填充算法,则算法的基本步骤如下。
(1)种子像素压入堆栈。
(2)当堆栈非空时,重复执行以下操作。
计算机图形学四连通区域种子填充算法实验
![计算机图形学四连通区域种子填充算法实验](https://img.taocdn.com/s3/m/dc0f800af121dd36a32d82e5.png)
计算机图形学四连通区域种子填充算法实验————————————————————————————————作者: ————————————————————————————————日期:ﻩ《计算机图形学实验》报告任课教师:钱文华2016年春季学期实验:四连通区域种子填充算法实验时间:2016年12月8日实验地点:信息学院2204实验目的:掌握种子填充算法的原理,并会用种子填充算法和opengl并结合使用c++语言编写程序绘制多边形。
实验原理:种子填充算法又称为边界填充算法。
其基本思想是:从多边形区域的一个内点开始,由内向外用给定的颜色画点直到边界为止。
如果边界是以一种颜色指定的,则种子填充算法可逐个像素地处理直到遇到边界颜色为止。
内点的检测条件:if(interiorColor!=bo rderColor&&interiorColor!=fillColor)。
种子填充算法常用四连通域和八连通域技术进行填充操作。
从区域内任意一点出发,通过上、下、左、右四个方向到达区域内的任意像素。
用这种方法填充的区域就称为四连通域;这种填充方法称为四向连通算法。
从区域内任意一点出发,通过上、下、左、右、左上、左下、右上和右下八个方向到达区域内的任意像素。
用这种方法填充的区域就称为八连通域;这种填充方法称为八向连通算法。
一般来说,八向连通算法可以填充四向连通区域,而四向连通算法有时不能填充八向连通区域。
四向连通填充算法:a)种子像素压入栈中;b)如果栈为空,则转e);否则转c);c) 弹出一个像素,并将该像素置成填充色;并判断该像素相邻的四连通像素是否为边界色或已经置成多边形的填充色,若不是,则将该像素压入栈;d)转b);e)结束。
四连通填充算法利用到了递归的思想。
本实验只包括四连通填充算法程序代码:#include<glut.h>#include<stdlib.h>#include<math.h>#include<windows.h>voidinit(void){ glClearColor(1.0,1.0,1.0,0.0);glMatrixMode(GL_PROJECTION);gluOrtho2D(0.0,300.0,0.0,300.0);}void setPixel(intx,inty,longfillColor){ glColor3f(fillColor<<16,fillColor<<8,fillColor);glBegin(GL_POINTS);glVertex2i(x,y);glEnd();}voidboundaryFill4(int x,inty,long fillColor,long borderColor){ unsignedchar params[3];long interiorColor;glReadPixels(x,y,1,1,GL_RGB,GL_UNSIGNED_BYTE,par ams);interiorColor=RGB(params[0],params[1],params[2]);if(interiorColor!=borderColor&&interiorColor!=fillColor){ setPixel(x,y,fillColor);boundaryFill4(x+1,y,fillColor,borderColor);boundaryFill4(x-1,y,fillColor,borderColor); boundaryFill4(x,y+1,fillColor,borderColor);boundaryFill4(x,y-1,fillColor,borderColor);} }voidlineSegment(void) {long borderColor=RGB(255,0,0);longfillColor=RGB(0,0,255);glClear(GL_COLOR_BUFFER_BIT); glColor3f(255,0,0); glBegin(GL_LINE_LOOP);glVertex2i(0,40);glVertex2i(20,0);glVertex2i(60,0);glVertex2i(80,40);glVertex2i(60,80);glVertex2i(20,80);glEnd();boundaryFill4(60,60,fillColor,borderColor);glFlush();}voidmain(int argc,char**argv){glutInit(&ar gc,argv);glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowPosition(150,100);glutInitWindowSize(300,300);glutCreateWindow("种子填充");init();glutDisplayFunc(lineSegment);glutMainLoop();}上实验课时机房的实验结果:后来的实验结果:glVertex2i(0,40);glVertex2i(20,0);glVertex2i(60,0);glVertex2i(80,40);glVertex2i(60,80);glVertex2i(20,80);glEnd();boundaryFill4(60,60,fillColor,borderColor);以上这段程序改成如下glVertex2i(90,40);glVertex2i(120, 100);glVertex2i(90,160);glVertex2i(60, 160);glVertex2i(60, 40);glEnd();boundaryFill4(70,60,fillColor,borderColor); 改变参数后:再把glVertex2i(90,40);glVertex2i(120, 100);glVertex2i(90,160);glVertex2i(60, 160);glVertex2i(60, 40);glEnd();boundaryFill4(70,60,fillColor,borderColor);改成glVertex2i(100, 100);glVertex2i(200, 100);glVertex2i(150,150);//glVertex2i(60, 160);//glVertex2i(60, 40);glEnd();boundaryFill4(150,120,fillColor,borderColor);后的结果如下图:实验总结:通过多组数据的测试,知道了上面算法的正确,普适性。
计算机图形学实验扫描线种子填充算法
![计算机图形学实验扫描线种子填充算法](https://img.taocdn.com/s3/m/1093a667af1ffc4ffe47acbd.png)
实验二4-10一、实验题目扫描线种子填充算法是通过扫描线来填充多边形内的水平像素段,处理每条扫描线时仅需将其最右端像素入栈,可以有效提高填充效率。
请使用MFC编程填充图4-60所示的空心体汉字(四连通),填充效果如图4-61所示。
二、实验思想扫描线种子填充算法:先将种子像素入栈,种子像素为栈底像素,如果栈不为空,执行如下4步操作。
(1)栈顶像素出栈。
(2)沿扫描线对出栈像素的左右像素进行填充,直至遇到边界像素为止。
即每出栈一个像素,就对区域内包含该像素的整个连续区间进行填充。
(3)同时记录该区间,将区间最左端像素记为x left,最右端像素记为x right。
(4)在区间〔x left,x right〕中检查与当前扫描线相邻的上下两条扫描线的有关像素是否全为边界像素或已填充像素,若存在非边界且未填充的像素,则把未填充区间的最右端像素取作种子像素入栈。
三、实验代码void CTestView::OnLButtonDown(UINT nFlags, CPoint point)//左键按下函数{// TODO: Add your message handler code here and/or call defaultSeed=point;//选择种子位置CharFill();//进行填充CView::OnLButtonDown(nFlags, point);}void CTestView::CharFill()//文字填充函数{CRect Rect;GetClientRect(&Rect);CClientDC dc(this);COLORREF BoundColor;//边界色int Width=Rect.right-Rect.left;int Hight=Rect.bottom-Rect.top ;int Flag;int x0,y0,x,y;CPoint Point;std::vector<CPoint> FillBuffle;//定义CPoint类型的数组序列对象FillBuffle.reserve(10);//定义数组序列的大小FillBuffle.push_back(CPoint(Seed)); //把种子结点压入数组序列BoundColor=RGB(0,0,0);//定义边界色为黑色while(!FillBuffle.empty())//如果数组序列非空{Point=FillBuffle.front();//弹出数组序列头元素x=Point.x;y=Point.y;FillBuffle.erase(FillBuffle.begin());//清除数组序列内的元素dc.SetPixel(Point,Fillcolor);//绘制像素//判断像素的位置是否在图形内部x0=x+1;//右方判断while(dc.GetPixel(x0,y)!=BoundColor&&dc.GetPixel(x0,y)!=Fillcolor) {x0=x0+1;if(x0>=Width)//到达屏幕最右端{MessageBox("种子超出范围","警告");RedrawWindow();return;}}y0=y+1;//下方判断while(dc.GetPixel(x,y0)!=BoundColor&&dc.GetPixel(x,y0)!=Fillcolor) {y0=y0+1;if(y0>=Hight)//到达屏幕最下端{MessageBox("种子超出范围","警告");RedrawWindow();return;}}RightPoint.x=x0;//右边界内的左邻点x0=x-1;while(dc.GetPixel(x0,y)!=Fillcolor&&dc.GetPixel(x0,y)!=BoundColor){dc.SetPixel(x0,y,Fillcolor);x0=x0-1;if(x0<=0)//到达屏幕最左端{MessageBox("种子超出范围","警告");RedrawWindow();return;}}y0=y-1;while(dc.GetPixel(x,y0)!=BoundColor&&dc.GetPixel(x,y0)!=Fillcolor){y0=y0-1;if(y0<=0)//到达屏幕最上端{MessageBox("种子超出范围","警告");RedrawWindow();return;}}LeftPoint.x=x0+1;//左边界内的右邻点x0=LeftPoint.x;y=y+1;//下一条扫描线while(x0<RightPoint.x){Flag=0;while((dc.GetPixel(x0,y)!=Fillcolor)&&(dc.GetPixel(x0,y)!=BoundColor)) {if(Flag==0)Flag=1;x0++ ;}if(Flag==1){if((x0==RightPoint.x)&&(dc.GetPixel(x0,y)!=Fillcolor)&&(dc.GetPixel(x0,y)!=BoundColor))FillBuffle.push_back(CPoint(x0,y));//进入数组序列else{FillBuffle.push_back(CPoint(x0-1,y));}Flag=0;}PointNext.x=x0;while(((dc.GetPixel(x0,y)==Fillcolor)&&(x0<RightPoint.x))||((dc.GetPixel(x0,y)==BoundColor) &&(x0<RightPoint.x))){x0 ++;}}x0=LeftPoint.x;y=y-2;while(x0<RightPoint.x){Flag=0;while((dc.GetPixel(x0,y)!=Fillcolor)&&(dc.GetPixel(x0,y)!=BoundColor)&&(x0<RightPoint.x)) {if(Flag==0)Flag=1;x0++ ;}if(Flag==1){if((x0==RightPoint.x)&&(dc.GetPixel(x0,y)!=Fillcolor)&&(dc.GetPixel(x0,y)!=BoundColor))FillBuffle.push_back(CPoint(x0,y));else{FillBuffle.push_back(CPoint(x0-1,y));}Flag=0;}PointNext.x=x0;while((dc.GetPixel(x0,y)==Fillcolor&&x0<RightPoint.x)||(dc.GetPixel(x0,y)==BoundColor&&x 0<RightPoint.x)){x0++;}}}FillBuffle.clear();return;}void CTestView::OnMENUFill(){// TODO: Add your command handler code hereRedrawWindow();MessageBox("请在空心字体内部单击鼠标左键!","提示");}四、实验结果截图。
计算机图形学——区域填充算法(基本光栅图形算法)
![计算机图形学——区域填充算法(基本光栅图形算法)](https://img.taocdn.com/s3/m/b68a02fa18e8b8f67c1cfad6195f312b3169eb4f.png)
计算机图形学——区域填充算法(基本光栅图形算法)⼀、区域填充概念区域:指已经表⽰成点阵形式的填充图形,是象素的集合。
区域填充:将区域内的⼀点(常称【种⼦点】)赋予给定颜⾊,然后将这种颜⾊扩展到整个区域内的过程。
区域填充算法要求区域是连通的,因为只有在连通区域中,才可能将种⼦点的颜⾊扩展到区域内的其它点。
1、区域有两种表⽰形式1)内点表⽰:枚举出区域内部的所有象素,内部所有象素着同⼀个颜⾊,边界像素着与内部象素不同的颜⾊。
2)边界表⽰:枚举出区域外部的所有象素,边界上的所有象素着同⼀个颜⾊,内部像素着与边界象素不同的颜⾊。
21)四向连通区域:从区域上⼀点出发可通过【上、下、左、右】四个⽅向移动的组合,在不越出区域的前提下,到达区域内的任意象素。
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)改进算法,减少递归次数,提⾼效率三、扫描线种⼦填充算法基本思想从给定的种⼦点开始,填充当前扫描线上种⼦点所在的⼀区段,然后确定与这⼀段相邻的上下两条扫描线上位于区域内的区段(需要填充的区间),从这些区间上各取⼀个种⼦点依次把它们存起来,作为下次填充的种⼦点。
图形学种子填充算法
![图形学种子填充算法](https://img.taocdn.com/s3/m/81b9ffb3eff9aef8951e0646.png)
图形学种子填充算法./种子填充算法void CZhztchView::boundaryfill4(int x, int y, int boundarycolor, int newcolor){int color;获取客户区设备描述表CClientDC dc(this); //color=dc.GetPixel(x,y); if(color!=newcolor&&color!=boundarycolor){dc.SetPixel(x,y,newcolor);boundaryfill4(x,y+1,boundarycolor,newcolor);boundaryfill4(x,y-1,boundarycolor,newcolor);boundaryfill4(x-1,y,boundarycolor,newcolor);boundaryfill4(x+1,y,boundarycolor,newcolor);}}///////////////////////////////////////////////////////////////////// /////////////扫描线填充算法void CZhztchView::OnScanfill(){RedrawWindow();CDC* pDC=GetDC();CPen newpen(PS_SOLID,3,RGB(255,0,0));CPen *old=pDC->SelectObject(&newpen);spt[0]=CPoint(100,100); //绘制多边形区域spt[1]=CPoint(300,100);spt[2]=CPoint(250,250);spt[3]=CPoint(100,250);spt[4]=CPoint(150,200);spt[5]=CPoint(90,180);spt[6]=CPoint(150,150);spt[7]=CPoint(100,100);pDC->Polyline(spt,8);//pDC->SelectObject(old);//ReleaseDC(pDC);// TODO: Add your command handler code here //CDC* pDC=GetDC();CPen newpen2(PS_SOLID,1,RGB(0,255,0)); CPen *old2=pDC->SelectObject(&newpen2);int j,k,s = 0;int p[5]; //每根扫描线交点int pmin = 0,pmax = 0;for(int i=0;i<=6;i++)//建立边表{edge[i].dx=(float)(spt[i+1].x-spt[i].x)/(spt[i+1].y-spt[i].y); if(spt[i].y<=spt[i+1].y){edge[i].num=i;edge[i].ymin=spt[i].y;edge[i].ymax=spt[i+1].y;edge[i].xmin=(float)spt[i].x;edge[i].xmax=(float)spt[i+1].x;if(spt[i+1].y > pmax)pmax = spt[i+1].y;if(spt[i].y < pmin)pmin = spt[i].y;}else{edge[i].num=i;edge[i].ymin=spt[i+1].y;edge[i].ymax=spt[i].y;edge[i].xmax=(float)spt[i].x;edge[i].xmin=(float)spt[i+1].x;if(spt[i].y > pmax)pmax = spt[i].y;if(spt[i+1].y < pmin)pmin = spt[i+1].y;}}for(int r=1;r<=6;r++) //排序edge(yUpper,xIntersect),结果为从大到小{for(int q=0;q<=6-r;q++){if(edge[q].ymin<edge[q+1].ymin){newedge[0]=edge[q]; edge[q]=edge[q+1];edge[q+1]=newedge[0];}}}if((s;for(j=k;j<=6;j++)intb=0;for(intscan=pmax-1;scan&;;k=s;;bif(spt[edge[j].num+1].y&;can>edge[j].ymin;if(scan==edge[j].ymax);elseif(spt[edge[j].;++;p[b]=(int)edge[j].xmax;;for(int scan=pmax-1;scan>=pmin+1;scan--){int b=0;k=s;for(j=k;j<=6;j++){if((scan>edge[j].ymin)&&(scan<=edge[j].ymax))//判断与线段相交{if(scan==edge[j].ymax){if(spt[edge[j].num+1].y<edge[j].ymax){b++;p[b]=(int)edge[j].xmax;}else if(spt[edge[j].num-1].y<edge[j].ymax) {b++;p[b]=(int)edge[j].xmax;}}if((scan>edge[j].ymin)&&(scan<edge[j].ymax)){b++;p[b]=(int)(edge[j].xmax+edge[j].dx*(scan-edge[j].ymax)); } }//pDC->LineTo(spt[edge[0].num].x,spt[edge[0].num].y);if(scan<=edge[j].ymin)//s=j;}if(b>1){for(int u=1;u<b;u++){pDC->MoveTo(p[u]-1,scan);u++;pDC->LineTo(p[u],scan);}}}pDC->SelectObject(old); pDC->SelectObject(old2); }。
区域填充算法
![区域填充算法](https://img.taocdn.com/s3/m/06d7b2ac18e8b8f67c1cfad6195f312b3169ebc9.png)
3、基于曲线积分的区域填充算法
• 算法的实现: ➢对一个区域进行轮廓跟踪,求出区域的边
• 改进算法的基本思想是:每找到一个新的内部
区段时,不仅将新区段的y值(yn)和左右列值xnl, xnr压入堆栈,而且同时把当前区段的y值和左右 列值xl,xr也压入堆栈,以保存和传递有关的信息。
3、基于曲线积分的区域填充算法
基于曲线积分的区域填充算法是邓国强,孙 景鳌等(2001)提出的一种以格林公式求区域面 积为基本原理进行区域填充的特殊算法。
1、递归种子填充算法
递归种子填充算法,又称边界填色算 法。
算法的原理是:让单个像元作为填充 胚,在给定的区域范围内,通过某种方法 进行蔓延,最终填充满整个多边形区域。 为了实现填充胚的蔓延,可采用四邻法或 八邻法进行填充。
2、扫描线种子填充算法
(1)扫描线种子填充算法
扫描线种子填充算法的对象是一个个扫描 线段。扫描线段是指区域内同值相邻像素 在水平方向的组合,它的两端以具有边界 值的像素为边界,即一段扫描线段的中间 只有同一种像素。
(2)计算多边形面积
4、区域填充算法在地图制图中的应用
(2)计算多边形面积
Sa
24
1 5 2
1 13 33 2
Sb
30
1 2
5
1 2
17
41
ScΒιβλιοθήκη 1031 213
1 2
17
CGA填充算法之种子填充算法
![CGA填充算法之种子填充算法](https://img.taocdn.com/s3/m/490bea2a86c24028915f804d2b160b4e767f81cf.png)
CGA填充算法之种⼦填充算法CGA填充算法之种⼦填充算法 平⾯区域填充算法是计算机图形学领域的⼀个很重要的算法,区域填充即给出⼀个区域的边界(也可以是没有边界,只是给出指定颜⾊),要求将边界范围内的所有象素单元都修改成指定的颜⾊(也可能是图案填充)。
区域填充中最常⽤的是多边形填⾊,本⽂讨论种⼦填充算法(Seed Filling) 如果要填充的区域是以图像元数据⽅式给出的,通常使⽤种⼦填充算法(Seed Filling)进⾏区域填充。
种⼦填充算法需要给出图像数据的区域,以及区域内的⼀个点,这种算法⽐较适合⼈机交互⽅式进⾏的图像填充操作,不适合计算机⾃动处理和判断填⾊。
根据对图像区域边界定义⽅式以及对点的颜⾊修改⽅式,种⼦填充⼜可细分为⼏类: ⽐如:①注⼊填充算法(Flood Fill Algorithm)、 ②边界填充算法(Boundary Fill Algorithm)以及 ③为减少递归和压栈次数⽽改进的扫描线种⼦填充算法等等。
所有种⼦填充算法的核⼼其实就是⼀个递归算法,都是从指定的种⼦点开始,向各个⽅向上搜索,逐个像素进⾏处理,直到遇到边界,各种种⼦填充算法只是在处理颜⾊和边界的⽅式上有所不同。
在开始介绍种⼦填充算法之前,⾸先也介绍两个概念,就是“4-联通算法”和“8-联通算法”。
既然是搜索就涉及到搜索的⽅向问题,从区域内任意⼀点出发,如果只是通过上、下、左、右四个⽅向搜索到达区域内的任意像素,则⽤这种⽅法填充的区域就称为四连通域,这种填充⽅法就称为 “4-联通算法”。
如果从区域内任意⼀点出发,通过上、下、左、右、左上、左下、右上和右下全部⼋个⽅向到达区域内的任意像素,则这种⽅法填充的区域就称为⼋连通域,这种填充⽅法就称为“8-联通算法”。
如图1(a)所⽰,假设中⼼的蓝⾊点是当前处理的点,如果是“4-联通算法”,则只搜索处理周围蓝⾊标识的四个点,如果是“8-联通算法”则除了处理上、下、左、右四个蓝⾊标识的点,还搜索处理四个红⾊标识的点。
计算机图形学第3章二维基本图(4)
![计算机图形学第3章二维基本图(4)](https://img.taocdn.com/s3/m/5b2231f3f705cc17552709fa.png)
二、扫描线种子填充算法实现
借助于堆栈,上述算法实现步骤如下:
1、初始化堆栈。 2、种子压入堆栈。 3、while(堆栈非空) { (1)从堆栈弹出种子象素。 (2)如果种子象素尚未填充,则:
a.求出种子区段:xleft、xright; b.填充整个区段。 c.检查相邻的上扫描线的xleft≤x≤xright区间内, 是否存在需要填充的新区段,如果存在的话, 则把每个新区段在xleft≤x≤xright范围内的最 右边的象素,作为新的种子象素依次压入堆栈。 d.检查相邻的下扫描线的xleft≤x≤xright区间内, 是否存在需要填充的新区段,如果存在的话, 则把每个新区段在 xleft≤x≤xright范围内的 最右边的象素,作为新的种子象素依次压入堆 栈。 }
扫描线种子填充算法步骤 (1)种子象素入栈。 (2)栈非空时象素出栈,否则结束。 (3)对出栈象素及左、右两边象素填充,直到遇边界XL、XR。 (4)在(XL ,XR) 内查相临的上、下两条扫描线是否为边界或已填充, 如不是,则将每区间的最右边的象素入栈。回到(2)。
练习: 用扫描线种子填充算法,写出图中顺序进栈的种子坐标及 所需最大栈空间
2、国标码 我国除了采用ASCII码外,还制定了汉字编 码的国家标准字符集:中华人民共和国国家标准 信息交换编码,代号为“GB2312-80”。该字符 集共收录常用汉字6763个,图形符号682个。 它规定所有汉字和图形符号组成一个94×94 的矩阵,在此方阵中,每一行称为“区”,用区 码来标识;每一列称为“位”,用位码来标识, 一个符号由一个区码和一个位码共同标识。 区码和位码分别需要7个二进制位,同样, 为了方便,各采用一个字节表示。所以在计算机 中,汉字(符号)国标码占用两个字节。
计算机图形学-4实区域填充
![计算机图形学-4实区域填充](https://img.taocdn.com/s3/m/889a2ac9700abb68a982fbcb.png)
表5
4∧
3
2
1 0∧
P4P5
528 .
P5P6
5 -1.5 7 ∧
11 0 8 ∧ P3P4
2 0 7 ∧ P6P1
5 -3 2 . 5 3 3 ∧
P1P2
P2P3
P4P5
P3P4
y=7
9 2 8 . 11 0 8 ∧
更新边表,删除P6P1和P5P6,填充交点之间的区域
更新边表,删除P4P5和P3P4,有效边表为空,没有新边,填充算法结束
扫描线与多边形相交的边分处扫描线的两侧,则计 一个交点。设yi是扫描线,yi-1,yi+1分别是共享该顶 点的另外两个顶点,即 yi>yi-1,yi<yi+1,则计1个交 点,如P1。
扫描线与多边形相交的边分处扫描线同侧,且 yi<yi-1,yi<yi+1,则计2个交点(填色),如P2。
扫描线与多边形相交的边分处扫描线同侧,且 yi>yi-1,yi>yi+1,则计0个交点(不填色),如P6。
八向连通算法种子填充算法八向连通区域连通方式对填充结果的影响4连通区域填充算法的填充结果8连通区域填充算法的填充结果简单的种子填充算法4连通边界按右上左下顺序检查与出栈象素相邻的四象素若其中某象素不在边界上且未被置成填充色则将其入栈填充算法演示简单的种子像素入栈有些象素会入栈多次这样一方面降低了算法的效率另一方面还要求很大的存储空间以实现栈的结构解决这个问题的一个办法是在任意一个扫描线与多边形的相交区间含有若干个连续象素中只取一个种象素入栈相应的算法称为扫描线填充算法
扫描线填充算法规则
规则1: 边界上象素的取舍问题,避免填充扩大化。 解决方法: 边界象素:规定落在右上边界的象素不予填充。 具体实现时,只要对扫描线与多边形的相交区间左闭 右开,下闭上开。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
/种子填充算法
void CZhztchView::boundaryfill4(int x, int y, int boundarycolor, int newcolor)
{
int color;
CClientDC dc(this); //获取客户区设备描述表
color=dc.GetPixel(x,y);
if(color!=newcolor&&color!=boundarycolor)
{
dc.SetPixel(x,y,newcolor);
boundaryfill4(x,y+1,boundarycolor,newcolor);
boundaryfill4(x,y-1,boundarycolor,newcolor);
boundaryfill4(x-1,y,boundarycolor,newcolor);
boundaryfill4(x+1,y,boundarycolor,newcolor);
}
}
///////////////////////////////////////////////////////////////// ///////////////
//扫描线填充算法
void CZhztchView::OnScanfill()
{
RedrawWindow();
CDC* pDC=GetDC();
CPen newpen(PS_SOLID,3,RGB(255,0,0));
CPen *old=pDC->SelectObject(&newpen);
spt[0]=CPoint(100,100); //绘制多边形区域
spt[1]=CPoint(300,100);
spt[2]=CPoint(250,250);
spt[3]=CPoint(100,250);
spt[4]=CPoint(150,200);
spt[5]=CPoint(90,180);
spt[6]=CPoint(150,150);
spt[7]=CPoint(100,100);
pDC->Polyline(spt,8);
//pDC->SelectObject(old);
//ReleaseDC(pDC);
// TODO: Add your command handler code here //CDC* pDC=GetDC();
CPen newpen2(PS_SOLID,1,RGB(0,255,0)); CPen *old2=pDC->SelectObject(&newpen2);
int j,k,s = 0;
int p[5]; //每根扫描线交点
int pmin = 0,pmax = 0;
for(int i=0;i<=6;i++)//建立边表
{
edge[i].dx=(float)(spt[i+1].x-spt[i].x)/(spt[i+1].y-spt[i].y); if (spt[i].y<=spt[i+1].y){
edge[i].num=i;
edge[i].ymin=spt[i].y;
edge[i].ymax=spt[i+1].y;
edge[i].xmin=(float)spt[i].x;
edge[i].xmax=(float)spt[i+1].x;
if(spt[i+1].y > pmax)
pmax = spt[i+1].y;
if(spt[i].y < pmin)
pmin = spt[i].y;
}
else{
edge[i].num=i;
edge[i].ymin=spt[i+1].y;
edge[i].ymax=spt[i].y;
edge[i].xmax=(float)spt[i].x;
edge[i].xmin=(float)spt[i+1].x;
if(spt[i].y > pmax)
pmax = spt[i].y;
if(spt[i+1].y < pmin)
pmin = spt[i+1].y;
}
}
for(int r=1;r<=6;r++) //排序edge(yUpper,xIntersect),结果为从大到小
{
for(int q=0;q<=6-r;q++)
{
if(edge[q].ymin<edge[q+1].ymin)
{
newedge[0]=edge[q]; edge[q]=edge[q+1];
edge[q+1]=newedge[0];
}
}
}
for(intscan=pmax-1;scan&;intb=0;;k=s;;for(j=k;j<=6;j++);if((sc an>edge[j].ymin;if(scan==edge[j].ymax);if(spt[edge[j].num+1].y&;b+ +;;p[b]=(int)edge[j].xmax;;elseif(spt[edge[j].
for(int scan=pmax-1;scan>=pmin+1;scan--)
{
int b=0;
k=s;
for(j=k;j<=6;j++)
{
if((scan>edge[j].ymin)&&(scan<=edge[j].ymax))//判断与线段相交
{
if(scan==edge[j].ymax)
{
if(spt[edge[j].num+1].y<edge[j].ymax)
{
b++;
p[b]=(int)edge[j].xmax;
}
else if(spt[edge[j].num-1].y<edge[j].ymax) {
b++;
p[b]=(int)edge[j].xmax;
}
}
if((scan>edge[j].ymin)&&(scan<edge[j].ymax))
{
b++;
p[b]=(int)(edge[j].xmax+edge[j].dx*(scan-edge[j].ymax)); }
}
//pDC->LineTo(spt[edge[0].num].x,spt[edge[0].num].y); if(scan<=ed ge[j].ymin)//
s=j;
}
if(b>1)
{
for(int u=1;u<b;u++)
{
pDC->MoveTo(p[u]-1,scan);
u++;
pDC->LineTo(p[u],scan);
}
}
}
pDC->SelectObject(old); pDC->SelectObject(old2); }。