计算机图形实验三 :种子填充 python(堆栈实现法 和 递归实现法)动画

提供了堆栈实现法的函数、递归实现法的函数,并且还提供了完整的代码,在代码中有具体的代码注释

堆栈实现法:

有在代码中有具体的代码注释

def SeedFill(x, y):
    # 图形空白点入栈
    if point[x][y] == 0:
        stack.append((x, y))
        while len(stack) != 0:
            # 栈顶像素出栈
            seed = stack.pop()
            x, y = seed
            # 从种子点像右边填充
            while point[x][y] == 0:
                # 将已经被填充的点记作1
                point[x][y] = 1
                # 上色
                plt.plot(x, y, 'r.', markersize=1)
                plt.pause(0.01)
                # 向右填充直到遇到边界
                x = x + 1
            # right为检查区间的最右像素
            right = x - 1  # right需要减1,是因为上面的循环需要遇见边界点,但是right表示的是填充点的最右边的点
            # 填充完右边的空白点之后,回到种子点,准备向种子点左右填充
            x, y = seed
            x = x - 1
            # 向种子点左边填充
            while point[x, y] == 0:
                point[x][y] = 1
                plt.plot(x, y, 'r.', markersize=1)
                # 设置暂停,实现动画效果
                plt.pause(0.01)
                # 向种子点的左边填充
                x = x - 1
            # left为检查区间的最左像素
            left = x + 1
            # 将新的种子点入栈
            # 处理上一条扫描线
            x = left
            y = y + 1
            # 为了更好的选取种子点,所以引入flag参数(flag=True 说明是可以入栈的点)
            while x < right:
                # 初始化flag
                flag = False
                while point[x][y] == 0:
                    flag = True
                    x = x + 1
                if flag:
                    stack.append((x - 1, y))
                    # 种子点入栈之后需要重新将flag重置为False,不然在循环里面flag就一直会是true的
                    flag = False
                while point[x][y] != 0 and x < right:
                    # 使用这个语句,是为了防止图形有洞的情况,有洞,但是还是需要遍历到最右边
                    x = x + 1
            # 处理下一条扫描线
            x = left
            y = y - 2  # 因为在前面的是先处理了上一条扫面线,所以需要-2
            while x < right:
                flag = False
                while point[x][y] == 0:
                    flag = True
                    x = x + 1
                if flag:
                    stack.append((x - 1, y))
                    flag = False
                while point[x][y] != 0 and x < right:
                    x = x + 1

 递推式:

# 种子填充算法(递归式)
def seedFill(x, y):
    if point[x][y] == 0:
        point[x][y] = 1
        plt.plot(x, y, 'r.', markersize=1)
        plt.pause(0.1)
        if point[x + 1][y] == 0:
            seedFill(x + 1, y)
        if point[x][y + 1] == 0:
            seedFill(x, y + 1)
        if point[x - 1][y] == 0:
            seedFill(x - 1, y)
        if point[x][y - 1] == 0:
            seedFill(x, y - 1)

使用DDA算法进行直线的绘制(多边形的边缘)

# DDA直线扫描算法,用于绘制多边形的边界
def DDA(x1, y1, x2, y2):
    dx, dy = x2 - x1, y2 - y1
    k = dy / dx
    x, y = x1, y1
    # 绘点
    for i in range(0, int(abs(dx) + 1)):
        # 网格线
        plt.grid()
        # x轴y轴数值取整
        plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
        plt.gca().yaxis.set_major_locator(MaxNLocator(integer=True))
        # 需要四舍五入
        plt.plot(int(round(x)), int(round(y)), 'b.', markersize=1)
        point[int(round(x))][int(round(y))] = 2
        x += 1
        y += float(k)

完整代码

本代码还实现了种子填充的动画效果,如果不需要动画效果的,可以将 plt.pause(0.01) 代码删除,就没有动画效果了

# -*- coding=utf-8 -*-
# Author:lei吼吼
# @Time :2022/10/31 21:49
# @File: 种子填充.py
# @Software:PyCharm

import matplotlib.pyplot as plt
import numpy as np
from matplotlib.ticker import MaxNLocator

np.set_printoptions(threshold=np.inf)
# 在矩阵point中,0表示空白点,1表示填充点,2表示边界点
# 初始化450*450的矩阵为零
point = np.zeros((450, 450))
stack = []
# 网格线
plt.grid(ls='--', which='major')


def SeedFill(x, y):
    # 图形空白点入栈
    if point[x][y] == 0:
        stack.append((x, y))
        while len(stack) != 0:
            # 栈顶像素出栈
            seed = stack.pop()
            x, y = seed
            # 从种子点像右边填充
            while point[x][y] == 0:
                # 将已经被填充的点记作1
                point[x][y] = 1
                # 上色
                plt.plot(x, y, 'r.', markersize=1)
                plt.pause(0.01)
                # 向右填充直到遇到边界
                x = x + 1
            # right为检查区间的最右像素
            right = x - 1  # right需要减1,是因为上面的循环需要遇见边界点,但是right表示的是填充点的最右边的点
            # 填充完右边的空白点之后,回到种子点,准备向种子点左右填充
            x, y = seed
            x = x - 1
            # 向种子点左边填充
            while point[x, y] == 0:
                point[x][y] = 1
                plt.plot(x, y, 'r.', markersize=1)
                # 设置暂停,实现动画效果
                plt.pause(0.01)
                # 向种子点的左边填充
                x = x - 1
            # left为检查区间的最左像素
            left = x + 1
            # 将新的种子点入栈
            # 处理上一条扫描线
            x = left
            y = y + 1
            # 为了更好的选取种子点,所以引入flag参数(flag=True 说明是可以入栈的点)
            while x < right:
                # 初始化flag
                flag = False
                while point[x][y] == 0:
                    flag = True
                    x = x + 1
                if flag:
                    stack.append((x - 1, y))
                    # 种子点入栈之后需要重新将flag重置为False,不然在循环里面flag就一直会是true的
                    flag = False
                while point[x][y] != 0 and x < right:
                    # 使用这个语句,是为了防止图形有洞的情况,有洞,但是还是需要遍历到最右边
                    x = x + 1
            # 处理下一条扫描线
            x = left
            y = y - 2  # 因为在前面的是先处理了上一条扫面线,所以需要-2
            while x < right:
                flag = False
                while point[x][y] == 0:
                    flag = True
                    x = x + 1
                if flag:
                    stack.append((x - 1, y))
                    flag = False
                while point[x][y] != 0 and x < right:
                    x = x + 1


# 种子填充算法(递归式)
def seedFill(x, y):
    if point[x][y] == 0:
        point[x][y] = 1
        plt.plot(x, y, 'r.', markersize=1)
        plt.pause(0.1)
        if point[x + 1][y] == 0:
            seedFill(x + 1, y)
        if point[x][y + 1] == 0:
            seedFill(x, y + 1)
        if point[x - 1][y] == 0:
            seedFill(x - 1, y)
        if point[x][y - 1] == 0:
            seedFill(x, y - 1)


# DDA直线扫描算法,用于绘制多边形的边界
def DDA(x1, y1, x2, y2):
    dx, dy = x2 - x1, y2 - y1
    k = dy / dx
    x, y = x1, y1
    # 绘点
    for i in range(0, int(abs(dx) + 1)):
        # 网格线
        plt.grid()
        # x轴y轴数值取整
        plt.gca().xaxis.set_major_locator(MaxNLocator(integer=True))
        plt.gca().yaxis.set_major_locator(MaxNLocator(integer=True))
        # 需要四舍五入
        plt.plot(int(round(x)), int(round(y)), 'b.', markersize=1)
        point[int(round(x))][int(round(y))] = 2
        x += 1
        y += float(k)


# 绘制多边形的边
def draw(x, y, xEnd, yEnd):
    if xEnd < x:
        x, y, xEnd, yEnd = xEnd, yEnd, x, y
    DDA(x, y, xEnd, yEnd)


# 绘制多边形
def drawLine():
    draw(0, 40, 40, 18)
    draw(40, 18, 80, 40)
    draw(0, 40, 60, 60)
    draw(60, 60, 80, 40)
    draw(20, 40, 40, 48)
    draw(40, 48, 50, 40)
    draw(50, 40, 40, 30)
    draw(40, 30, 20, 40)
    # 网格线
    plt.grid()


if __name__ == '__main__':
    # 画出图形的边界
    drawLine()
    plt.grid()
    # 选取(40,18)作为种子起始点
    SeedFill(40, 28)
    plt.show()

最终结果

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值