理解区域填充问题与基本思想、原理;
掌握区域填充的常见算法如简单种子填充算法和扫描线种子填充算法;
用代码实现简单种子填充算法。
(1) 阅读掌握教材所给简单种子填充算法伪代码;
(2) 在教材所给伪代码的基础上,结合附件所给的代码实现一个多边形区域的简单种子填充算法
//算法核心代码
void FloodFill(Point one, Color fillColor, Color boarderColor)
{
pixelStack.push(one); // 种子点入栈
Color tmpcolor; //存储种子点的颜色
Point pointt; //存储出栈元素
while (!pixelStack.empty()) { //栈不为空 执行
pointt = pixelStack.top(); // 取栈顶
pixelStack.pop(); //出栈
tmpcolor = getPixelColor(pointt);//获取栈顶 元素 颜色
if ((compareColor(tmpcolor, fillColor)) == 0 && (compareColor(tmpcolor, boarderColor)) == 0) { //进行比较颜色
setpixel(pointt,fillColor); //绘制像素 填充颜色
int xx = pointt.x;
int yy = pointt.y;
pixelStack.push(Point{ xx - 1, yy });//其他四个方向像素入栈
pixelStack.push(Point{ xx, yy + 1 });
pixelStack.push(Point{ xx + 1, yy });
pixelStack.push(Point{ xx, yy - 1 });
}
}
}
void onMouseClick(int button, int state, int x, int y) //点击事件函数
{
Color fillColor = { 0, 1.0, 0 };//填充色
Color boarderColor = { 1.0, 0.0, 0.0 };//边界色
Point one;
if (state == GLUT_DOWN)
{
if (button == GLUT_LEFT_BUTTON)
{
one = { x, 500-y }; //500 窗口高度
//one = { 100, 50 }; // 设置起始点
FloodFill(one, fillColor, boarderColor);
glFlush();
}
}
}
效果图
完整代码
#include<GL/glut.h>
#include<stack>
#include<iostream>
using namespace std;
struct Point {
int x;
int y;
};
stack<Point> pixelStack;
struct Color {
GLfloat r;
GLfloat g;
GLfloat b;
};
//获取像素点的颜色
Color getPixelColor(Point one) {
Color color;
glReadPixels(one.x, one.y, 1, 1, GL_RGB, GL_FLOAT, &color);
return color;
}
//比较颜色
int compareColor(Color color1, Color color2) {
if ((color1.r != color2.r) || (color1.g != color2.g) || (color1.b != color2.b)) {
return 0;
}
else {
return 1;
}
}
//画点函数
void setpixel(Point one, Color color) {
glBegin(GL_POINTS);
glColor3f(color.r, color.g, color.b);
glVertex2i(one.x, one.y);
glEnd();
glFlush();
}
//算法核心代码
void FloodFill(Point one, Color fillColor, Color boarderColor)
{
pixelStack.push(one); // 种子点入栈
Color tmpcolor; //存储种子点的颜色
Point pointt; //存储出栈元素
while (!pixelStack.empty()) { //栈不为空 执行
pointt = pixelStack.top(); // 取栈顶
pixelStack.pop(); //出栈
tmpcolor = getPixelColor(pointt);//获取栈顶 元素 颜色
if ((compareColor(tmpcolor, fillColor)) == 0 && (compareColor(tmpcolor, boarderColor)) == 0) { //进行比较颜色
setpixel(pointt,fillColor); //绘制像素 填充颜色
int xx = pointt.x;
int yy = pointt.y;
Point s = { xx - 1, yy };
Point d={ xx, yy + 1 };
Point e={ xx + 1, yy };
Point f={ xx, yy - 1 };
pixelStack.push(s);//其他四个方向像素入栈
pixelStack.push(d);
pixelStack.push(e);
pixelStack.push(f);
}
}
}
//点击事件函数
void onMouseClick(int button, int state, int x, int y)
{
Color fillColor = { 0, 1.0, 0 };//填充色
Color boarderColor = { 1.0, 0.0, 0.0 };//边界色
Point one;
if (state == GLUT_DOWN)
{
if (button == GLUT_LEFT_BUTTON)
{
one = { x, 500-y }; //500 窗口高度
//one = { 100, 50 }; // 设置起始点
FloodFill(one, fillColor, boarderColor);
glFlush();
}
}
}
void draw() { //绘制要填充的多边形
glBegin(GL_LINE_LOOP);
glColor3f(1.0, 0.0, 0.0); //将边框颜色存入缓冲区
glVertex2i(100, 0);
glVertex2i(50, 50);
glVertex2i(100, 100);
glVertex2i(150, 50);
glEnd();
}
void display(void)
{
glClearColor(1.0, 1.0, 1.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, 500, 500);
draw();
glFlush();
}
int main(int argc, char** argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RED);
glutInitWindowSize(500, 500);
glutInitWindowPosition(100, 100);
glutCreateWindow("BoundaryFillFlood");
glClearColor(1, 1, 1, 0.0);
glMatrixMode(GL_PROJECTION);//投影模型
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glutDisplayFunc(display);
glutMouseFunc(onMouseClick);
glutMainLoop();
return 0;
}
实验前首先学习了书上简单种子填充算法的伪代码。理解伪代码逻辑,开始动手实践。
实践过程中,遇到了以下问题:
获取像素点的颜色值,通过自定义颜色结构体,编写函数getPixelColor()获取颜色。代码的细小bug,绘制点的函数没有刷新以及浮点小数无法比较。
鼠标点击事件获取像素位置,通过网上查找学习,学到了glutMouseFunc()函数使用方法。但是,当点击在多边形外部时,并没有编写代码。普通递归函数,深度过大,代码无法完全执行。通过堆栈的方式,可以完整执行代码。