【问题标题】:How to "translate" the Midpoint Circle Algorithm into matplotlib?如何将中点圆算法“翻译”成 matplotlib?
【发布时间】:2016-02-21 17:34:59
【问题描述】:

我需要在matplotlib 中实现Midpoint Circle Algorithm,以便在200x200 单元格的方形网格上光栅化一个圆。也请参考我的other question

感谢this answer,我能够找到一些我认为可以完美运行的代码。我唯一的问题是我不知道如何整合和修改它以确保matplotlib 绘制一个实心圆,里面有1,外面有0

这就是我使用matplotlib 实现脚本的方式:

import numpy
import matplotlib.pyplot as plt    
n=200 #Grid size, 4 times my visualized output in order to be able to truncate some circles
empty_lattice=numpy.zeros((n,n)) #The empty 2D grid
radius=int(numpy.random.uniform(30,90)) #Radius
xc=int(numpy.random.uniform(0,n-radius)) #X center
yc=int(numpy.random.uniform(0,n-radius)) #Y center
x=0
y=radius
d=3-2*radius
while (x<=y):
    for hor in range(0,x): #This loop is my unfortunate attempt to fill the circle with 1s
        for ver in range(0,y):
            empty_lattice[xc+x][yc+y]=1 #1st octant
            empty_lattice[xc-x][yc+y]=1 #2nd octant
            empty_lattice[xc+x][yc-y]=1 #3rd octant
            empty_lattice[xc-x][yc-y]=1 #4th octant
            empty_lattice[xc+y][yc+x]=1 #5th octant
            empty_lattice[xc-y][yc+x]=1 #6th octant
            empty_lattice[xc+y][yc-x]=1 #7th octant
            empty_lattice[xc-y][yc-x]=1 #8th octant
    if (d<0):
        d=d+4*x+6
    else:
        d=d+4*(x-y)+10
        y=y-1
    x=x+1           

现在,这是我得到的,但你看到我的圆圈是空的,并且在它底部的水平线上有一个“间隙”。这个间隙出现在每个八分圆交叉点处。 如何修改我的代码以填补圆圈和空白?

编辑

采用the answer provided below后,发现下图中画了两个镜像圆。我认为这个错误来自我的原始脚本,而不是答案。我只想要每个图像中的一个圆圈。 我怎样才能摆脱这个功能?

【问题讨论】:

  • 您可能想查看skimage,它有一套工具可以为您处理这类事情。如果你想自己做,我强烈怀疑用广播做这个会更快(通过让 numpy 在 c 中做循环而不是在 python 中自己做)。

标签: python algorithm matplotlib geometry rasterizing


【解决方案1】:

要消除间隙,您需要将水平范围扩大一倍。在您的代码中,这将是 for hor in range(0,x + 1): 行。我的代码采用了不同的策略。

据我了解,中点圆算法只是绕着圆的周长走。所以我认为它不能轻易修改以填充内部。下面的代码检查第一个八分圆中的每个点,以查看该点与中心的距离是否小于或等于半径。如果在半径范围内,则每个八分圆中的所有 8 个对应点都被填充。

import numpy
import matplotlib.pyplot as plt    
n=200 #Grid size, 4 times my visualized output in order to be able to truncate some circles
empty_lattice=numpy.zeros((n,n)) #The empty 2D grid
radius=int(numpy.random.uniform(30,90)) #Radius
xc=int(numpy.random.uniform(0,n-radius)) #X center
yc=int(numpy.random.uniform(0,n-radius)) #Y center
r2 = radius ** 2
for dx in range(0, radius):
    dx2 = dx ** 2
    for dy in range(0, dx + 1):
        dy2 = dy ** 2
        if (dx2 + dy2 <= r2):
            empty_lattice[xc+dx][yc+dy]=1 #1st octant
            empty_lattice[xc-dx][yc+dy]=1 #2nd octant
            empty_lattice[xc+dx][yc-dy]=1 #3rd octant
            empty_lattice[xc-dx][yc-dy]=1 #4th octant
            empty_lattice[xc+dy][yc+dx]=1 #5th octant
            empty_lattice[xc-dy][yc+dx]=1 #6th octant
            empty_lattice[xc+dy][yc-dx]=1 #7th octant
            empty_lattice[xc-dy][yc-dx]=1 #8th octant

plt.imshow(empty_lattice)
plt.show()

如果你真的想坚持中点圆算法,你可以画周长,然后从中心点开始flood fill

编辑 1:

去掉了两个不必要的行。

编辑 2:

上面的代码以模块化的方式将圆圈环绕在图像边缘。如果您不希望这样,则需要一些额外的条件:

            empty_lattice[xc+dx][yc+dy]=1 #1st octant
            if (xc - dx >= 0):
                empty_lattice[xc-dx][yc+dy]=1 #2nd octant
            if (yc - dy >= 0):
                empty_lattice[xc+dx][yc-dy]=1 #3rd octant
            if (xc - dx >= 0 and yc - dy >= 0):
                empty_lattice[xc-dx][yc-dy]=1 #4th octant
            if (yc + dx < n):
                empty_lattice[xc+dy][yc+dx]=1 #5th octant
            if (xc - dy >= 0):
                empty_lattice[xc-dy][yc+dx]=1 #6th octant
            if (yc - dx >= 0):
                empty_lattice[xc+dy][yc-dx]=1 #7th octant
            if (xc - dy >= 0 and yc - dx >= 0):
                empty_lattice[xc-dy][yc-dx]=1 #8th octant

编辑 3:

我意识到您的原始代码有什么问题。您的for 循环涉及一个变量hor,但您忘记使用hor。此代码有效。我将由您来检查指数是否为正。

x=0
y=radius
d=3-2*radius
while (x<=y):
    for hor in range(0,x + 1): #This loop is my unfortunate attempt to fill the circle with 1s
##        for ver in range(0,y):
        empty_lattice[xc+hor][yc+y]=1 #1st octant
        empty_lattice[xc-hor][yc+y]=1 #2nd octant
        empty_lattice[xc+hor][yc-y]=1 #3rd octant
        empty_lattice[xc-hor][yc-y]=1 #4th octant
        empty_lattice[xc+x][yc+hor]=1 #1st octant
        empty_lattice[xc-x][yc+hor]=1 #2nd octant
        empty_lattice[xc+x][yc-hor]=1 #3rd octant
        empty_lattice[xc-x][yc-hor]=1 #4th octant
        empty_lattice[xc+hor][yc+x]=1 #5th octant
        empty_lattice[xc-hor][yc+x]=1 #6th octant
        empty_lattice[xc+hor][yc-x]=1 #7th octant
        empty_lattice[xc-hor][yc-x]=1 #8th octant
        empty_lattice[xc+y][yc+hor]=1 #5th octant
        empty_lattice[xc-y][yc+hor]=1 #6th octant
        empty_lattice[xc+y][yc-hor]=1 #7th octant
        empty_lattice[xc-y][yc-hor]=1 #8th octant
    if (d<0):
        d=d+4*x+6
    else:
        d=d+4*(x-y)+10
        y=y-1
    x=x+1  

【讨论】:

  • 我很想知道这两种方法中的哪一种——洪水填充和这种修改后的中点圆算法——更快。有什么见解吗?
  • 我认为洪水填充会稍微快一些。我不确定您是否注意到,但是如果您注释掉两个 for 循环并取消缩进 empty_lattice 分配,您的原始代码就可以很好地绘制边缘。洪水填充不需要计算距离,但我认为额外的编程工作不值得。
  • 呃,为什么我会得到镜像圈子?请检查我的编辑
  • @FC84 请参阅编辑 2。但是,您的评论表明您的网格大小是可视化输出的 4 倍。因此,您可以只可视化 1:100 季度,而不是使用所有那些笨拙的 if 语句。
  • 我在我的脚本中更进一步地这样做了。但我似乎明白我可以摆脱一些 if 语句,对吧?
猜你喜欢
  • 2018-06-13
  • 1970-01-01
  • 2023-03-06
  • 2021-10-28
  • 2010-12-24
  • 2021-05-25
  • 1970-01-01
  • 1970-01-01
  • 2011-03-09
相关资源
最近更新 更多