首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何在numpy数组中绘制线条?

如何在numpy数组中绘制线条?
EN

Stack Overflow用户
提问于 2015-07-26 23:21:06
回答 3查看 21.2K关注 0票数 21

我希望能够将线条绘制到numpy数组中,以获得用于在线手写识别的离线特征。这意味着我根本不需要图像,但我需要在一个numpy数组中找到一些位置,该位置是给定大小的图像的外观。

我希望能够指定图像大小,然后像这样绘制笔划:

代码语言:javascript
复制
import module
im = module.new_image(width=800, height=200)
im.add_stroke(from={'x': 123, 'y': 2}, to={'x': 42, 'y': 3})
im.add_stroke(from={'x': 4, 'y': 3}, to={'x': 2, 'y': 1})
features = im.get(x_min=12, x_max=15, y_min=0, y_max=111)

这样简单的事情是可能的吗(最好直接使用numpy / scipy)?

(请注意,我想要灰度插值。因此,features应该是一个0,255中的值矩阵。)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-07-28 16:42:21

感谢Joe Kington的回答!我在找skimage.draw.line_aa

代码语言:javascript
复制
import scipy.misc
import numpy as np
from skimage.draw import line_aa
img = np.zeros((10, 10), dtype=np.uint8)
rr, cc, val = line_aa(1, 1, 8, 4)
img[rr, cc] = val * 255
scipy.misc.imsave("out.png", img)
票数 25
EN

Stack Overflow用户

发布于 2017-11-20 03:25:51

我在寻找解决方案时偶然发现了这个问题,提供的答案很好地解决了它。然而,它并不真正适合我的目的,为此我需要一个“可伸缩的”解决方案(即在numpy中实现,没有显式循环),并且可能还需要一个行宽选项。我最终实现了我自己的版本,因为最终它也比line_aa快得多,我想我可以分享它。

它有两种风格,有线宽和没有线宽。实际上,前者并不是后者的泛化,两者都不完全符合line_aa,但就我的目的而言,它们很好,在绘图中它们看起来也不错。

代码语言:javascript
复制
def naive_line(r0, c0, r1, c1):
    # The algorithm below works fine if c1 >= c0 and c1-c0 >= abs(r1-r0).
    # If either of these cases are violated, do some switches.
    if abs(c1-c0) < abs(r1-r0):
        # Switch x and y, and switch again when returning.
        xx, yy, val = naive_line(c0, r0, c1, r1)
        return (yy, xx, val)

    # At this point we know that the distance in columns (x) is greater
    # than that in rows (y). Possibly one more switch if c0 > c1.
    if c0 > c1:
        return naive_line(r1, c1, r0, c0)

    # We write y as a function of x, because the slope is always <= 1
    # (in absolute value)
    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)))

我称其为" naive“,因为它非常类似于Wikipedia中的naive实现,但有一些抗锯齿,尽管不可否认不是完美的(例如,制作非常细的对角线)。

加权版本提供更粗的线条,更明显的抗锯齿效果。

代码语言:javascript
复制
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):
    # The algorithm below works fine if c1 >= c0 and c1-c0 >= abs(r1-r0).
    # If either of these cases are violated, do some switches.
    if abs(c1-c0) < abs(r1-r0):
        # Switch x and y, and switch again when returning.
        xx, yy, val = weighted_line(c0, r0, c1, r1, w, rmin=rmin, rmax=rmax)
        return (yy, xx, val)

    # At this point we know that the distance in columns (x) is greater
    # than that in rows (y). Possibly one more switch if c0 > c1.
    if c0 > c1:
        return weighted_line(r1, c1, r0, c0, w, rmin=rmin, rmax=rmax)

    # The following is now always < 1 in abs
    slope = (r1-r0) / (c1-c0)

    # Adjust weight by the slope
    w *= np.sqrt(1+np.abs(slope)) / 2

    # We write y as a function of x, because the slope is always <= 1
    # (in absolute value)
    x = np.arange(c0, c1+1, dtype=float)
    y = x * slope + (c1*r0-c0*r1) / (c1-c0)

    # Now instead of 2 values for y, we have 2*np.ceil(w/2).
    # All values are 1 except the upmost and bottommost.
    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()

    # Exclude useless parts and those outside of the interval
    # to avoid parts outside of the picture
    mask = np.logical_and.reduce((yy >= rmin, yy < rmax, vals > 0))

    return (yy[mask].astype(int), xx[mask].astype(int), vals[mask])

不可否认,权重的调整是相当随意的,所以任何人都可以根据自己的喜好进行调整。现在需要rmin和rmax来避免图像之外的像素。比较:

正如您所看到的,即使使用w=1,weighted_line也稍微厚一些,但以一种同质的方式;类似地,naive_line的同质稍微薄一些。

关于基准测试的最后一点注意事项:在我的机器上,针对各种功能(针对weighted_line的w=1)运行%timeit f(1,1,100,240)时,line_aa的运行时间为90µs,weighted_line的运行时间为84µs (当然,时间会随着重量的增加而增加),而naive_line的运行时间为18µs。同样为了进行比较,用纯Python (而不是包中的Cython )重新实现line_aa需要350微秒。

票数 21
EN

Stack Overflow用户

发布于 2019-08-01 23:32:52

我想绘制抗锯齿的线条,我想绘制数千条这样的线条,而不需要安装另一个包。我最终劫持了Matplotlib的内部结构,它以10us/line的速度在100x100数组上执行1000行代码,至少在我的机器上是这样。

代码语言:javascript
复制
def rasterize(lines, shape, **kwargs):
    """Rasterizes an array of lines onto an array of a specific shape using
    Matplotlib. The output lines are antialiased.

    Be wary that the line coordinates are in terms of (i, j), _not_ (x, y).

    Args: 
        lines: (line x end x coords)-shaped array of floats
        shape: (rows, columns) tuple-like

    Returns:
        arr: (rows x columns)-shaped array of floats, with line centres being
        1. and empty space being 0.
    """
    lines, shape = np.array(lines), np.array(shape)

    # Flip from (i, j) to (x, y), as Matplotlib expects
    lines = lines[:, :, ::-1]

    # Create our canvas
    fig = plt.figure()
    fig.set_size_inches(shape[::-1]/fig.get_dpi())

    # Here we're creating axes that cover the entire figure
    ax = fig.add_axes([0, 0, 1, 1])
    ax.axis('off')

    # And now we're setting the boundaries of the axes to match the shape
    ax.set_xlim(0, shape[1])
    ax.set_ylim(0, shape[0])
    ax.invert_yaxis()

    # Add the lines
    lines = mpl.collections.LineCollection(lines, color='k', **kwargs)
    ax.add_collection(lines)

    # Then draw and grab the buffer
    fig.canvas.draw_idle()
    arr = (np.frombuffer(fig.canvas.get_renderer().buffer_rgba(), np.uint8)
                        .reshape((*shape, 4))
                        [:, :, :3]
                        .mean(-1))

    # And close the figure for all the IPython folk out there
    plt.close()

    # Finally, flip and reverse the array so empty space is 0.
    return 1 - arr/255.

下面是输出的样子:

代码语言:javascript
复制
plt.imshow(rasterize([[[5, 10], [15, 20]]], [25, 25]), cmap='Greys')
plt.grid()

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31638651

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档