c++实现种子填充算法与扫描线算法

前言

默认您已经配置好相关环境。
如若没有,可以自行搜索“EasyX”下载安装。
本教程主要从代码方面讲解算法的实现。
至于理论部分还请大家自行搜索其他文章。(该类文章非常多)

种子填充算法

演示视频
在这里插入图片描述
核心代码

void FloodFILL(int x, int y, int bodercolor, int newcolor)
{
	int color = getpixel(x,y);//获取该点的颜色
	if (color != bodercolor && color != newcolor)//该点不是边界点/该点颜色未发生改变
	{
		putpixel(x, y, newcolor);//更改该点颜色为新颜色
		//递归向四个方向调用该函数
		FloodFILL(x, y + 1, bodercolor, newcolor);
		FloodFILL(x, y - 1, bodercolor, newcolor);
		FloodFILL(x - 1, y, bodercolor, newcolor);
		FloodFILL(x + 1, y, bodercolor, newcolor);
	}
}

完整代码

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
void FloodFILL(int x, int y, int bodercolor, int newcolor)
{
	int color = getpixel(x,y);
	if (color != bodercolor && color != newcolor)
	{
		putpixel(x, y, newcolor);
		FloodFILL(x, y + 1, bodercolor, newcolor);
		FloodFILL(x, y - 1, bodercolor, newcolor);
		FloodFILL(x - 1, y, bodercolor, newcolor);
		FloodFILL(x + 1, y, bodercolor, newcolor);
	}
}


int main()
{
	initgraph(640, 480);
	setcolor(BLUE);
	moveto(80, 80);
	lineto(280, 160);
	lineto(520, 0);
	lineto(520, 220);
	lineto(280, 400);
	lineto(80, 320);
	lineto(80, 80);
	FloodFILL(280, 200, BLUE, RED);
	_getch();
	closegraph();
	return 0;
}

PS:如果该代码运行时报错,共两种情况:1.未配置EASYX 2.递归次数过多超出最大栈上限
自行百度这两种问题就可以解决啦~

扫描线算法

个人这个原始版本实现的稍微有点啰嗦,优化的空间很大。
希望可以带给大家一点思路,剩下的完善就交给你们自己啦。
演示效果
在这里插入图片描述
首先,将线段作为一个类,进行声明

class Line
{
public:
	Line(int x1, int y1, int x2, int y2) :Start_x(x1), Start_y(y1), End_x(x2), End_y(y2) 
	{ 
		k = float(End_y - Start_y) / float(End_x - Start_x); 
		moveto(x1, y1);
		lineto(x2, y2);
	}
	//y=kx+b,然后通过反函数,通过y的值获得x的值
	float getX(int y)
	{
		if (Start_y < End_y && (y<Start_y || y>End_y))
			return 0;
		else if (Start_y > End_y && (y > Start_y || y < End_y))
			return 0;
		float x = Start_x + float(y - Start_y) / k;
		return x;
	}
private:
	int Start_x;
	int Start_y;
	int End_x;
	int End_y;
	float k;
};

//以演示图的效果来看,就是将线段的点的纵坐标从上到下排序
void Sort(float S[],int y)
{
	int i, j,num=0;
	for (i = 0; i < 6; i++)
	{
		if (S[i] != 0)
			num++;
	}
	for (i = 0; i < 6; i++)
	{
		for (j = 0; j < 5; j++)
		{
			if (S[j] < S[j + 1])
			{
				float temp = S[j];
				S[j] = S[j + 1];
				S[j + 1] = temp;
			}
		}
	}
	if (num == 2)
	{
		int Ex = int(S[0]);
		int Sx = int(S[1]);
		for (int x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if (num == 3)
	{
		int Ex = int(S[0]);
		int Sx = int(S[2]);
		for (int x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if (num == 4)
	{
		int Ex, Sx,x;
		Ex = int(S[0]);
		Sx = int(S[1]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[2]);
		Sx = int(S[3]);
		for (x= Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if(num==6)
	{
		int Ex, Sx,x;
		Ex = int(S[0]);
		Sx = int(S[1]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[2]);
		Sx = int(S[3]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[4]);
		Sx = int(S[5]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
}

核心代码

//六条线段(自行定义
void ScanLines(int y,Line l1,Line l2,Line l3,Line l4,Line l5,Line l6)
{
	float S[6] = { 0 };
	if (y < 400)
	{
		S[0] = l1.getX(y);
		S[1] = l2.getX(y);
		S[2] = l3.getX(y);
		S[3] = l4.getX(y);
		S[4] = l5.getX(y);
		S[5] = l6.getX(y);
		Sort(S, y);
		Sleep(10);
		ScanLines(y + 1, l1, l2, l3, l4, l5, l6);
	}
}

完整代码

#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<Windows.h>
void PointFill(int x, int y,int newcolor)
{
	putpixel(x, y, newcolor);
}

class Line
{
public:
	Line(int x1, int y1, int x2, int y2) :Start_x(x1), Start_y(y1), End_x(x2), End_y(y2) 
	{ 
		k = float(End_y - Start_y) / float(End_x - Start_x); 
		moveto(x1, y1);
		lineto(x2, y2);
	}
	float getX(int y)
	{
		if (Start_y < End_y && (y<Start_y || y>End_y))
			return 0;
		else if (Start_y > End_y && (y > Start_y || y < End_y))
			return 0;
		float x = Start_x + float(y - Start_y) / k;
		return x;
	}
private:
	int Start_x;
	int Start_y;
	int End_x;
	int End_y;
	float k;
};

void Sort(float S[],int y)
{
	int i, j,num=0;
	for (i = 0; i < 6; i++)
	{
		if (S[i] != 0)
			num++;
	}
	for (i = 0; i < 6; i++)
	{
		for (j = 0; j < 5; j++)
		{
			if (S[j] < S[j + 1])
			{
				float temp = S[j];
				S[j] = S[j + 1];
				S[j + 1] = temp;
			}
		}
	}
	if (num == 2)
	{
		int Ex = int(S[0]);
		int Sx = int(S[1]);
		for (int x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if (num == 3)
	{
		int Ex = int(S[0]);
		int Sx = int(S[2]);
		for (int x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if (num == 4)
	{
		int Ex, Sx,x;
		Ex = int(S[0]);
		Sx = int(S[1]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[2]);
		Sx = int(S[3]);
		for (x= Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
	else if(num==6)
	{
		int Ex, Sx,x;
		Ex = int(S[0]);
		Sx = int(S[1]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[2]);
		Sx = int(S[3]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
		Ex = int(S[4]);
		Sx = int(S[5]);
		for (x = Sx; x <= Ex; x++)
			PointFill(x, y, RED);
	}
}


void ScanLines(int y,Line l1,Line l2,Line l3,Line l4,Line l5,Line l6)
{
	float S[6] = { 0 };
	if (y < 400)
	{
		S[0] = l1.getX(y);
		S[1] = l2.getX(y);
		S[2] = l3.getX(y);
		S[3] = l4.getX(y);
		S[4] = l5.getX(y);
		S[5] = l6.getX(y);
		Sort(S, y);
		Sleep(10);
		ScanLines(y + 1, l1, l2, l3, l4, l5, l6);
	}
}


int main()
{
	initgraph(640, 480);
	setcolor(BLUE);
	float S[6] = { 0 };
	Line l1(80, 80, 280, 160);
	Line l2(280, 160, 520, 0);
	Line l3(520, 0, 520, 220);
	Line l4(520, 220, 280, 400);
	Line l5(280, 400, 80, 320);
	Line l6(80, 320, 80, 80);
	ScanLines(0, l1, l2, l3, l4, l5, l6);
	PointFill(280, 200,RED);
	_getch();
	closegraph();
	return 0;
}

  • 28
    点赞
  • 118
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
扫描线种子填充算法是一种用于图形填充的算法,其基本思想是从种子点开始,沿着扫描线进行像素填充,直到遇到边界为止。以下是C++实现算法的基本步骤: 1. 定义一个像素点结构体,用于存储像素的坐标信息和颜色信息。 ```cpp struct Pixel { int x; int y; int color; }; ``` 2. 定义一个扫描线结构体,用于存储扫描线的起始和终止位置。 ```cpp struct ScanLine { int y; int left; int right; }; ``` 3. 定义一个函数用于判断像素点是否在边界内部。 ```cpp bool insideBoundary(int x, int y) { // 判断像素点是否在边界内部 // 如果在内部返回 true,否则返回 false } ``` 4. 定义一个函数用于判断像素点是否为种子点。 ```cpp bool isSeedPoint(int x, int y) { // 判断像素点是否为种子点 // 如果是返回 true,否则返回 false } ``` 5. 定义一个函数用于填充扫描线上的像素点。 ```cpp void fillScanLine(int y, int left, int right, int color) { for (int x = left; x <= right; x++) { // 填充像素点 } } ``` 6. 定义一个函数用于进行扫描线种子填充。 ```cpp void scanLineSeedFill(int x, int y, int color) { if (!insideBoundary(x, y) || isSeedPoint(x, y)) { return; } // 初始化扫描线 std::vector<ScanLine> scanLines; scanLines.push_back({y, x, x}); // 循环处理扫描线,直到所有像素点都填充完成 while (!scanLines.empty()) { // 取出当前扫描线 ScanLine scanLine = scanLines.back(); scanLines.pop_back(); // 填充当前扫描线上的像素点 fillScanLine(scanLine.y, scanLine.left, scanLine.right, color); // 处理下一扫描线 for (int i = scanLine.left; i <= scanLine.right; i++) { // 处理当前像素点的上方像素点 if (insideBoundary(i, scanLine.y - 1) && !isSeedPoint(i, scanLine.y - 1)) { int j = i; while (insideBoundary(j, scanLine.y - 1) && !isSeedPoint(j, scanLine.y - 1)) { j--; } scanLines.push_back({scanLine.y - 1, j + 1, i - 1}); } // 处理当前像素点的下方像素点 if (insideBoundary(i, scanLine.y + 1) && !isSeedPoint(i, scanLine.y + 1)) { int j = i; while (insideBoundary(j, scanLine.y + 1) && !isSeedPoint(j, scanLine.y + 1)) { j--; } scanLines.push_back({scanLine.y + 1, j + 1, i - 1}); } } } } ``` 以上是C++实现扫描线种子填充算法的基本步骤,可以根据具体需求进行调整和优化。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值