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

Мы будем благодарны за любые идеи о Spline and Wand.

Спасибо .


person jemiah    schedule 28.02.2018    source источник


Ответы (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)

овал  rect

person emcconville    schedule 28.02.2018
comment
Это работает, и это работает прекрасно. У меня есть длинный список других примеров, чтобы попробовать это, так что я собираюсь попробовать это на всех остальных. Спасибо! Теперь я хочу попробовать тот же метод с решением SciPy, чтобы посмотреть, позволит ли оно мне зафиксировать все измерения, которые мне нужны для проверки границ. Серьезно, мой текущий счет репутации слишком низкий, чтобы отметить, насколько полезным был этот ответ. Я бы отдал 100 баллов, если бы мог. - person jemiah; 28.02.2018
comment
Я пошел и попробовал это решение на нескольких других файлах DXF. Он прекрасно работает над всеми из них. Мне очень любопытно, почему для этой работы понадобились группы из четырех человек. Когда у вас будет время, было бы здорово узнать, почему шлицы нужно обрабатывать группами по четыре штуки. Судя по вашим утверждениям, вы много знаете о файлах DXF и кривых сплайнов. В своем исследовании я не нашел упоминаний о группах из 4 человек. Откуда вы об этом узнали? Спасибо - person jemiah; 01.03.2018