gpt4 book ai didi

python - 使用 matplotlib 创建随机形状/轮廓

转载 作者:太空狗 更新时间:2023-10-29 22:05:21 25 4
gpt4 key购买 nike

我正在尝试使用 python 生成随机轮廓的图像,但找不到简单的方法。

这是我想要的示例:

enter image description here

最初我想用 matplotlib 和高斯函数来做,但我什至无法接近我展示的图像。

有什么简单的方法吗?

感谢任何帮助

最佳答案

问题是问题中显示的那种随机形状并不是真正随机的。它们以某种方式平滑、有序、看似随机的形状。虽然使用计算机可以轻松创建真正随机的形状,但使用笔和纸创建这些伪随机形状要容易得多。

因此,一种选择是以交互方式创建此类形状。这显示在问题 Interactive BSpline fitting in Python 中。

如果您想以编程方式创建随机形状,我们可以使用三次贝塞尔曲线使解决方案适应 How to connect points taking into consideration position and orientation of each of them

想法是通过 get_random_points 创建一组随机点,并用它们调用函数 get_bezier_curve。这将创建一组贝塞尔曲线,这些曲线在输入点处相互平滑连接。我们还确保它们是循环的,即起点和终点之间的过渡也是平滑的。

import numpy as np
from scipy.special import binom
import matplotlib.pyplot as plt


bernstein = lambda n, k, t: binom(n,k)* t**k * (1.-t)**(n-k)

def bezier(points, num=200):
N = len(points)
t = np.linspace(0, 1, num=num)
curve = np.zeros((num, 2))
for i in range(N):
curve += np.outer(bernstein(N - 1, i, t), points[i])
return curve

class Segment():
def __init__(self, p1, p2, angle1, angle2, **kw):
self.p1 = p1; self.p2 = p2
self.angle1 = angle1; self.angle2 = angle2
self.numpoints = kw.get("numpoints", 100)
r = kw.get("r", 0.3)
d = np.sqrt(np.sum((self.p2-self.p1)**2))
self.r = r*d
self.p = np.zeros((4,2))
self.p[0,:] = self.p1[:]
self.p[3,:] = self.p2[:]
self.calc_intermediate_points(self.r)

def calc_intermediate_points(self,r):
self.p[1,:] = self.p1 + np.array([self.r*np.cos(self.angle1),
self.r*np.sin(self.angle1)])
self.p[2,:] = self.p2 + np.array([self.r*np.cos(self.angle2+np.pi),
self.r*np.sin(self.angle2+np.pi)])
self.curve = bezier(self.p,self.numpoints)


def get_curve(points, **kw):
segments = []
for i in range(len(points)-1):
seg = Segment(points[i,:2], points[i+1,:2], points[i,2],points[i+1,2],**kw)
segments.append(seg)
curve = np.concatenate([s.curve for s in segments])
return segments, curve

def ccw_sort(p):
d = p-np.mean(p,axis=0)
s = np.arctan2(d[:,0], d[:,1])
return p[np.argsort(s),:]

def get_bezier_curve(a, rad=0.2, edgy=0):
""" given an array of points *a*, create a curve through
those points.
*rad* is a number between 0 and 1 to steer the distance of
control points.
*edgy* is a parameter which controls how "edgy" the curve is,
edgy=0 is smoothest."""
p = np.arctan(edgy)/np.pi+.5
a = ccw_sort(a)
a = np.append(a, np.atleast_2d(a[0,:]), axis=0)
d = np.diff(a, axis=0)
ang = np.arctan2(d[:,1],d[:,0])
f = lambda ang : (ang>=0)*ang + (ang<0)*(ang+2*np.pi)
ang = f(ang)
ang1 = ang
ang2 = np.roll(ang,1)
ang = p*ang1 + (1-p)*ang2 + (np.abs(ang2-ang1) > np.pi )*np.pi
ang = np.append(ang, [ang[0]])
a = np.append(a, np.atleast_2d(ang).T, axis=1)
s, c = get_curve(a, r=rad, method="var")
x,y = c.T
return x,y, a


def get_random_points(n=5, scale=0.8, mindst=None, rec=0):
""" create n random points in the unit square, which are *mindst*
apart, then scale them."""
mindst = mindst or .7/n
a = np.random.rand(n,2)
d = np.sqrt(np.sum(np.diff(ccw_sort(a), axis=0), axis=1)**2)
if np.all(d >= mindst) or rec>=200:
return a*scale
else:
return get_random_points(n=n, scale=scale, mindst=mindst, rec=rec+1)

您可以使用这些功能,例如作为

fig, ax = plt.subplots()
ax.set_aspect("equal")

rad = 0.2
edgy = 0.05

for c in np.array([[0,0], [0,1], [1,0], [1,1]]):

a = get_random_points(n=7, scale=1) + c
x,y, _ = get_bezier_curve(a,rad=rad, edgy=edgy)
plt.plot(x,y)

plt.show()

enter image description here

我们可以检查参数如何影响结果。这里基本上使用了 3 个参数:

  • rad,贝塞尔曲线控制点所在点周围的半径。该数字与相邻点之间的距离相关,因此应介于 0 和 1 之间。半径越大,曲线的特征越尖锐。
  • edgy,决定曲线平滑度的参数。如果为 0,曲线通过每个点的角度将是相邻点方向之间的平均值。它越大,角度就越多地由一个相邻点决定。曲线因此变得“尖锐”。
  • n 要使用的随机点数。当然最少的点数是3。你使用的点数越多,形状的特征就越丰富;冒着在曲线中产生重叠或环路的风险。

enter image description here enter image description here enter image description here

关于python - 使用 matplotlib 创建随机形状/轮廓,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50731785/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com