使用Wand和Python生成样条曲线

时间:2018-02-28 07:10:54

标签: python scipy wand dxf bspline

我正在尝试绘制从DXF文件中提取的样条曲线的栅格表示。我使用ezdxf库从DXF文件中提取数据,并且我使用Python Wand库(ImageMagick)来绘制图像。 Wand具有样条函数,但它绘制的内容并不总是与DXF文件中的曲线匹配。这并不奇怪,因为魔杖样条函数没有结节的输入或DXF样条曲线的程度。以下图像显示了DXF形状的外观。 Wand样条函数适用于一个示例,但不适用于另一个示例。

第一个是样条椭圆Oval Example

Oval Example

第二个是脊柱矩形Rectangle Example

Rectangle Example

这些形状的DXF文件中的数据点和节点已被提取并用于以下示例代码中,该代码创建了样本位图。即使不考虑结和度数,椭圆也很好地呈现test_image_oval.bmp

test_image_oval.bmp

矩形在所有边和角test_image_rect.bmp处都是畸形的。

test_image_rect.bmp

控制点以红色绘制。包括但未使用的结。

from wand.image import Image
from wand.color import Color
from wand.drawing import Drawing

############################################
point_list_oval =   [   (5.0,              1.5,              0),
                        (5.0,              0.6715728753,     0),
                        (3.8807118745,     0.0,              0),
                        (2.5,              0.0,              0),
                        (1.1192881255,     0.0,              0),
                        (0.0,              0.6715728753,     0),
                        (0.0,              1.5,              0),
                        (0.0,              2.3284271247,     0),
                        (1.1192881255,     3.0,              0),
                        (2.5,              3.0,              0),
                        (3.8807118745,     3.0,              0),
                        (5.0,              2.3284271247,     0),
                        (5.0,              1.5,              0)]

knots_oval       = [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0]

############################################
point_list_rect =   [(3.75, 0.0, 0),
                     (3.75,             0.0,              0),
                     (0.25,             0.0,              0),
                     (0.25,             0.0,              0),
                     (0.1125,           0.0,              0),
                     (0.0,              0.1125,           0),
                     (0.0,              0.25,             0),
                     (0.0,              0.25,             0),
                     (0.0,              5.75,             0),
                     (0.0,              5.75,             0),
                     (0.0,              5.8875,           0),
                     (0.1125,           6.0,              0),
                     (0.25,             6.0,              0),
                     (0.25,             6.0,              0),
                     (3.75,             6.0,              0),
                     (3.75,             6.0,              0),
                     (3.8875,           6.0,              0),
                     (4.0,              5.8875,           0),
                     (4.0,              5.75,             0),
                     (4.0,              5.75,             0),
                     (4.0,              0.25,             0),
                     (4.0,              0.25,             0),
                     (4.0,              0.1125,           0),
                     (3.8875,           0.0,              0),
                     (3.75,             0.0,              0)]

knots_rect =  [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0]


############################################
def draw_spline(img_width, img_height, DPI, point_list, filename):
    POINT_SIZE = 1
    STROKE_WIDTH = 0.5

    img = Image(width=img_width, height=img_height, background=Color('white'))

    # Convert the points to a 96dpi image space, remove the z axis
    converstion_list = []
    for point in point_list:
        point = (int(round(point[0] * DPI)), int(round(point[1] * DPI)))
        converstion_list.append(point)
    point_list = converstion_list

    # Draw the control points
    with Drawing() as draw:
        draw.stroke_width = STROKE_WIDTH
        draw.stroke_color = Color('red')
        draw.fill_color = Color('red')

        print '---------------------'
        print 'image points'
        for point in point_list:
            perim = (point[0] + POINT_SIZE, point[1])
            draw.circle(point, perim)
            print point
        draw(img)

    # draw the bezier path
    with Drawing() as draw:
        draw.stroke_width = STROKE_WIDTH
        draw.stroke_color = Color('green')
        draw.fill_color = Color('transparent')

        draw.bezier(point_list)

        draw(img)

    img.save(filename=filename)

############################################
DPI = 96
draw_spline(577,385, DPI, point_list_oval,'test_image_oval.bmp')
draw_spline(577, 700, DPI, point_list_rect, 'test_image_rect.bmp')

有没有人了解如何使用Wand库生成样条曲线并考虑结点和度数以及数据点?

我也尝试过使用SciPy库样条函数(interpolate.splprep),但成效有限。这是解决方案的另一种可能性。遵循该路径将意味着使用SciPy库来插入一大组点,并使用Wand中的折线函数来近似曲线。如果有人感兴趣我也可以包含该示例代码,但我不想过多地混淆线程。

对Spline和Wand的任何见解都将不胜感激。

由于 。

1 个答案:

答案 0 :(得分:2)

要理解的关键是贝塞尔曲线是一个样条曲线,但并非所有样条曲线都是贝塞尔曲线。因此对于DXF,只需绘制四个坐标的块,并使用最后一个使用的点作为下一次迭代的第一个。

# draw the bezier path
with Drawing() as draw:
    draw.stroke_width = STROKE_WIDTH
    draw.stroke_color = Color('green')
    draw.fill_color = Color('transparent')
    chunk = []                   # Prototype a temporary list.
    for points in point_list:    # Iterate over all points.
        chunk.append(points)     # Append to temporary list.
        if len(chunk) == 4:      # Ready to draw?
            draw.bezier(chunk)   # Draw spline segment.
            del chunk[0:3]       # Clear first three items, and reuse last point.
    draw(img)

oval rect