Создание сплайн-кривых с помощью Wand и Python
Я пытаюсь нарисовать растровое представление сплайн-кривых, извлеченных из файлов DXF. Я извлек данные из файлов DXF с помощью библиотеки ezdxf, и я использую библиотеку Python Wand (ImageMagick) для рисования изображений. У Wand есть функция сплайна, но то, что она рисует, не всегда соответствует кривым из файлов DXF. Это неудивительно, так как функция сплайна Wand не имеет входов для узлов или степени кривой сплайна DXF. Следующие изображения показывают, как выглядят фигуры DXF. Сплайн-функция Wand хорошо работает с одним примером, но не с другим.
Первый - овальный овальный пример сплайна.
Второй пример - Прямоугольник позвоночника.
Точки данных и узлы из файлов DXF для этих фигур были извлечены и использованы в следующем примере кода, который создает образцы растровых изображений. Несмотря на то, что узлы и степень не приняты во внимание, овал хорошо отображает test_image_oval.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)