Создание сплайн-кривых с помощью Wand и Python

Я пытаюсь нарисовать растровое представление сплайн-кривых, извлеченных из файлов DXF. Я извлек данные из файлов DXF с помощью библиотеки ezdxf, и я использую библиотеку Python Wand (ImageMagick) для рисования изображений. У Wand есть функция сплайна, но то, что она рисует, не всегда соответствует кривым из файлов DXF. Это неудивительно, так как функция сплайна Wand не имеет входов для узлов или степени кривой сплайна DXF. Следующие изображения показывают, как выглядят фигуры DXF. Сплайн-функция Wand хорошо работает с одним примером, но не с другим.

Первый - овальный овальный пример сплайна.

Овальный Пример

Второй пример - Прямоугольник позвоночника.

Пример прямоугольника

Точки данных и узлы из файлов 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 для аппроксимации кривой. Если кому-то интересно, я мог бы также включить этот пример кода, но я не хочу слишком запутывать поток.

Любые идеи о сплайне и палочке будут с благодарностью.

Благодарю.

1 ответ

Решение

Главное, что нужно понять, это то, что Безье является сплайном, но не все сплайны являются безье. Так что для 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)

овальный прямоугольник

Другие вопросы по тегам