[OpenGL] 不规则区域的填充算法
不规则区域的填充算法
一、简单递归
利用Dfs实现简单递归填充。
核心代码:
// 简单深度搜索填充 (四连通)
void DfsFill(int x, int y)
{
if (x < || y < || x> || y>)
{
return;
}
if (a[x][y] == )
{
a[x][y] = ;
DfsFill(x - , y);
DfsFill(x + , y);
DfsFill(x, y - );
DfsFill(x, y + );
}
}
二、扫描线种子填充算法(四连通)
1. 种子点(x,y)入栈。
2. 栈顶元素(x,y)出栈作为种子点。
3. 从种子点(x,y)开始沿着扫描线向左右两个方向逐个像素进行填充,直到到达边界像素为止。
4. 将上述填充区段的左右端点的横坐标分别记为xleft和xright.
5. 在与当前扫描线相邻的上下两条扫描线的[xleft,xright]范围内进行检查,
看看是否全部为边界像素或已填充像素,若存在着非边界且未填充的像素,那么将该区段的最右端像素作为种子点入栈。
// 扫描线种子填充算法(四连通)
void ScanFill(int x, int y)
{
if (a[x][y]!=)
{
return;
}
Pos first(x, y);
s.push(first);
while (!s.empty())
{
int rightX = ;
int leftX = ;
Pos cur = s.top();
s.pop();
a[cur.x][cur.y] = ;
// 遍历当前行
for (int i = ; i < ; i++)
{
if (cur.x + i < )
{
if (a[cur.x + i][cur.y] == )
a[cur.x + i][cur.y] = ;
else
{
rightX = cur.x + i - ;
break;
}
}
else
{
rightX = ;
}
}
for (int i = ; i < ; i++)
{
if (cur.x - i > -)
{
if (a[cur.x - i][cur.y] == )
a[cur.x - i][cur.y] = ;
else
{
leftX = cur.x - i + ;
break;
}
}
else
{
leftX = ;
}
} cout << leftX <<","<<rightX << endl; // 判断上行
int upRightX = -;
for (int i = leftX;i<=rightX;i++)
{
upRightX = -;
if (a[i][cur.y+]== && cur.y+<)
{
upRightX = i;
}
if (upRightX != -)
{
Pos temPos(upRightX, cur.y + );
s.push(temPos);
}
} // 判断下行
int downRightX = -;
for (int i = leftX; i <= rightX; i++)
{
downRightX = -;
if (a[i][cur.y - ] == && cur.y - >=)
{
downRightX = i;
}
if (downRightX != -)
{
Pos temPos(downRightX, cur.y - );
s.push(temPos);
}
} }
}
完整代码:
#include <cmath>
#include <stack>
#include "gl/glut.h"
#include "iostream"
using namespace std; #define PI 3.14 struct Pos
{
int x;
int y;
Pos(int mx, int my) :x(mx), y(my) {};
Pos() :x(), y() {};
}; stack<Pos> s;
int a[][] = { }; void init(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glMatrixMode(GL_PROJECTION);//设置投影矩阵
gluOrtho2D(0.0, 600.0, 0.0, 600.0);//二维视景区域
glPointSize(12.0f);
}
// 画棋子
void Drawtri(int x,int y,int color)
{
double n = ;//分段数
float R = ;//半径
int i;
if (color == )
{
glColor3f(1.0, 0.0, 0.0);
}
else if (color == )
{
glColor3f(0.0, 1.0, 0.0);
}
glBegin(GL_POLYGON);
glVertex2f(x, y);
for (i = ; i <= n; i++)
glVertex2f(R*cos( * PI / n * i)+x, R*sin( * PI / n * i)+y);
glEnd();
glPopMatrix();
} // 绘制格线
void playMap()
{
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_LINES);
for (int i = ; i < ; i += )
{
glVertex2f(i, );
glVertex2f(i, );
}
for (int j = ; j < ; j += )
{
glVertex2f(, j);
glVertex2f(, j);
}
glEnd();
for (int k = ; k < ; k++)
{
for (int l = ; l < ; l++)
{
if (a[k][l] == )
{
Drawtri(k * + , l * + ,);
}
else if (a[k][l] == )
{
Drawtri(k * + , l * + , );
}
}
}
} // 简单深度搜索填充 (四连通)
void DfsFill(int x, int y)
{
if (x < || y < || x> || y>)
{
return;
}
if (a[x][y] == )
{
a[x][y] = ;
DfsFill(x - , y);
DfsFill(x + , y);
DfsFill(x, y - );
DfsFill(x, y + );
}
} // 扫描线种子填充算法(四连通)
void ScanFill(int x, int y)
{
if (a[x][y]!=)
{
return;
}
Pos first(x, y);
s.push(first);
while (!s.empty())
{
int rightX = ;
int leftX = ;
Pos cur = s.top();
s.pop();
a[cur.x][cur.y] = ;
// 遍历当前行
for (int i = ; i < ; i++)
{
if (cur.x + i < )
{
if (a[cur.x + i][cur.y] == )
a[cur.x + i][cur.y] = ;
else
{
rightX = cur.x + i - ;
break;
}
}
else
{
rightX = ;
}
}
for (int i = ; i < ; i++)
{
if (cur.x - i > -)
{
if (a[cur.x - i][cur.y] == )
a[cur.x - i][cur.y] = ;
else
{
leftX = cur.x - i + ;
break;
}
}
else
{
leftX = ;
}
} cout << leftX <<","<<rightX << endl; // 判断上行
int upRightX = -;
for (int i = leftX;i<=rightX;i++)
{
upRightX = -;
if (a[i][cur.y+]== && cur.y+<)
{
upRightX = i;
}
if (upRightX != -)
{
Pos temPos(upRightX, cur.y + );
s.push(temPos);
}
} // 判断下行
int downRightX = -;
for (int i = leftX; i <= rightX; i++)
{
downRightX = -;
if (a[i][cur.y - ] == && cur.y - >=)
{
downRightX = i;
}
if (downRightX != -)
{
Pos temPos(downRightX, cur.y - );
s.push(temPos);
}
} }
} void displayFcn(void)
{
glClear(GL_COLOR_BUFFER_BIT);
playMap();
glFlush();
} void mouse(GLint button, GLint action, GLint x, GLint y)
{
int curX, curY;
if (button == GLUT_LEFT_BUTTON && action == GLUT_DOWN)
{
curX = x / ;
curY = ( - y) / ;
a[curX][curY] = ;
glutPostRedisplay();//重绘窗口
}
if (button == GLUT_RIGHT_BUTTON && action == GLUT_DOWN)
{
curX = x / ;
curY = ( - y) / ;
ScanFill(curX, curY); glutPostRedisplay();//重绘窗口
}
} void main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowPosition(, );
glutInitWindowSize(, );
glutCreateWindow("mouse"); init();
glutDisplayFunc(displayFcn); glutMouseFunc(mouse); glutMainLoop(); }
[OpenGL] 不规则区域的填充算法的更多相关文章
- Open gl 的不规则图形的4联通种子递归填充和扫描线种子递归填充算法实现
实验题目:不规则区域的填充算法 实验目的:验证不规则区域的填充算法 实验内容:利用VC与OpenGL,实现不规则区域的填充算法. 1.必做:实现简单递归的不规则区域填充算法. 2.选做:针对简单递归算 ...
- openGL实现图形学扫描线种子填充算法
title: "openGL实现图形学扫描线种子填充算法" date: 2018-06-11T19:41:30+08:00 tags: ["图形学"] cate ...
- 【GIS新探索】算法实现在不规则区域内均匀分布点
1 概要 在不规则区域内均匀分布点,这个需求初看可能不好理解.如果设想一下需求场景就比较简单了. 场景1:在某个地区范围内,例如A市区有100W人口,需要将这100W人口在地图上面相对均匀的标识出来. ...
- CGA填充算法之种子填充算法
CGA填充算法之种子填充算法 平面区域填充算法是计算机图形学领域的一个很重要的算法,区域填充即给出一个区域的边界 (也可以是没有边界,只是给出指定颜色),要求将边界范围内的所有象素单元都修改成指定的颜 ...
- 种子填充算法描述及C++代码实现
项目需要看了种子填充算法,改进了算法主要去除面积小的部分.种子填充算法分为两种,简单的和基于扫描线的方法,简单的算法如下描述(笔者针对的是二值图像): (1)从上到下,从左到有,依次扫描每个像素: ( ...
- 图像处理之泛洪填充算法(Flood Fill Algorithm)
泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是 windows paint的油漆桶功能.算法的原理很简单,就 ...
- 漫水填充算法 - cvFloodFill() 实现
前言 漫水填充算法是用来标记一片区域的:设置一个种子点,然后种子点附近的相似点都被填充同一种颜色. 该算法应用性很广,比如目标识别,photoshop 的魔术棒功能等等,是填充类算法中应用最为广泛的一 ...
- 图像处理------泛洪填充算法(Flood Fill Algorithm) 油漆桶功能
泛洪填充算法(Flood Fill Algorithm) 泛洪填充算法又称洪水填充算法是在很多图形绘制软件中常用的填充算法,最熟悉不过就是 windows paint的油漆桶功能.算法的原理很简单,就 ...
- OpenCV空洞填充算法
讨论帖: http://bbs.csdn.net/topics/391542633 在Matlab下,使用imfill可以很容易的完成孔洞填充操作,感觉这是一个极为常用的方法,然而不知道为什么Op ...
随机推荐
- IdHTTP设置SSL证书,乱码问题也解决了
要跟银行做接口,需要使用delphi来post数据,但对方提供的是https开头的网址,需要使用证书,对方已提供证书了,但是还是调用不成功,使用的是idhttp和TIdSSLIOHandlerSock ...
- ubuntu QT开发环境(三种方法安装Qt4.8,其中apt-get方法安装QT库最简单)good
方法一 QT4.8.0库+QT Creator 2.4.1 特别声明:此方法极其耗时间,看电脑性能了.配置configure可减少编译时间 1.下载Qt .进入网址http://qt.nokia.co ...
- ACL 我为什么要发明一个轮子?
现在成熟的开发库与开发框架有很多,所以平时我们在开发自己的应用程序时一般直接拿来用就可以了,所以当我先是开发出 C 语言版的 acl 框架库时有人认为是这个轮子是否值得发明,而当我再开发出基于 acl ...
- Laravel中我们登录服务器通过 Tinker 手动创建后台管理用户
Laravel中我们可以登录到服务器通过 Tinker 手动创建后台用户 laravel中tinker命令的作用是用来调试laravel,可以打印变量或对象信息,显示函数代码,对数据库写入和查询数据. ...
- 使用Core Audio实现VoIP通用音频模块
最近一直在做iOS音频技术相关的项目,由于单项直播SDK,互动直播SDK(iOS/Mac),短视频SDK,都会用到音频技术,因此在这里收集三个SDK的音频技术需求,开发一个通用的音频模块用于三个SDK ...
- Java学习笔记——设计模式之十.观察者模式
观察者模式(Observer),定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象.这个主题对象在状态发生变化时,会通知所有观察者对象,使他们能够自动更新自己. Subject类: ...
- Axure中怎么制作锚点
实现目标 点击导航条不同的菜单,页面跳到菜单相应的位置,实现页面自动滚动. 1. 拖入编辑区3个矩形,并相应命名为菜单1,菜单2 ,菜单3: 2. 再新建3个想要制作的文本框准备进行锚点滚动: 3 ...
- Python批量自动裁剪图片
"""用Pythonp批量裁剪图片""" from PIL import Image import matplotlib.pyplot as ...
- android开发环境配置和一些坑
要开发安卓应用,首先就是要配置安卓的开发环境. 新手在这个步骤时,会发现安卓的开发环境配置不是一般的麻烦,因为一般人是选择eclipse+a sdk+adt的,需要java环境,需要翻 墙,需要有非一 ...
- 【半小时大话.net依赖注入】(一)理论基础+实战控制台程序实现AutoFac注入
系列目录 第一章|理论基础+实战控制台程序实现AutoFac注入 第二章|AutoFac的常见使用套路 第三章|实战Asp.Net Framework Web程序实现AutoFac注入 第四章|实战A ...