我在寻找解决方案时偶然发现了这个问题,提供的答案解决得很好。但是,它并不完全适合我的需求,我需要一个“可张量化”的解决方案(即在numpy中实现而不需要显式循环),并且可能带有linewidth选项。最终,我实现了自己的版本,并且由于最终速度比line_aa快得多,所以我想分享一下。
它有两种风味,带和不带linewidth。实际上前者不是后者的泛化,也与line_aa不完全相同,但对于我的目的来说它们就足够好,在图表上看起来也不错。
def naive_line(r0, c0, r1, c1):
if abs(c1-c0) < abs(r1-r0):
xx, yy, val = naive_line(c0, r0, c1, r1)
return (yy, xx, val)
if c0 > c1:
return naive_line(r1, c1, r0, c0)
x = np.arange(c0, c1+1, dtype=float)
y = x * (r1-r0) / (c1-c0) + (c1*r0-c0*r1) / (c1-c0)
valbot = np.floor(y)-y+1
valtop = y-np.floor(y)
return (np.concatenate((np.floor(y), np.floor(y)+1)).astype(int), np.concatenate((x,x)).astype(int),
np.concatenate((valbot, valtop)))
我称之为“幼稚”,因为它与
Wikipedia中的幼稚实现非常相似,但加入了一些抗锯齿,尽管并不完美(例如,会使非常细的对角线)。
加权版本提供更加明显的抗锯齿,可以得到更粗的线条。
def trapez(y,y0,w):
return np.clip(np.minimum(y+1+w/2-y0, -y+1+w/2+y0),0,1)
def weighted_line(r0, c0, r1, c1, w, rmin=0, rmax=np.inf):
if abs(c1-c0) < abs(r1-r0):
xx, yy, val = weighted_line(c0, r0, c1, r1, w, rmin=rmin, rmax=rmax)
return (yy, xx, val)
if c0 > c1:
return weighted_line(r1, c1, r0, c0, w, rmin=rmin, rmax=rmax)
slope = (r1-r0) / (c1-c0)
w *= np.sqrt(1+np.abs(slope)) / 2
x = np.arange(c0, c1+1, dtype=float)
y = x * slope + (c1*r0-c0*r1) / (c1-c0)
thickness = np.ceil(w/2)
yy = (np.floor(y).reshape(-1,1) + np.arange(-thickness-1,thickness+2).reshape(1,-1))
xx = np.repeat(x, yy.shape[1])
vals = trapez(yy, y.reshape(-1,1), w).flatten()
yy = yy.flatten()
mask = np.logical_and.reduce((yy >= rmin, yy < rmax, vals > 0))
return (yy[mask].astype(int), xx[mask].astype(int), vals[mask])
权重调整的确相当任意,因此任何人都可以根据自己的口味进行调整。现在需要rmin和rmax以避免图片外的像素。比较如下:
![A comparison is here](https://istack.dev59.com/jEUys.webp)
如您所见,即使w=1,weighted_line也稍微粗一些,但以某种均匀的方式;同样,naive_line也略微均匀地变细。
有关基准测试的最后说明:在我的机器上,运行%timeit f(1,1,100,240)
来测试各种函数(对于weighted_line,w=1)的结果是,line_aa需要90微秒,weighted_line需要84微秒(当然随着权重的增加时间会增加),而naive_line只需要18微秒。再做比较,将line_aa重新实现为纯Python代码(而不是包中的Cython代码)需要350微秒。
ImageDraw
模块具有与您描述的相似的API。此外,请查看skimage.draw
:http://scikit-image.org/docs/dev/api/skimage.draw.html。就此而言,如果需要抗锯齿和/或更高级的绘图方法,甚至可以使用matplotlib进行绘制。 - Joe Kingtonline_aa
。谢谢!你想要发布答案还是我创建一个社区wiki? - Martin Thoma