Python вызывает библиотеку vtk и numpy для рисования пользовательских поверхностей и выполнения наложения текстур.

Введение

        Библиотека vtk — это библиотека 3D-компьютерной графики, обработки изображений и визуализации с открытым исходным кодом, которую можно использовать для выполнения таких задач, как 3D-реконструкция и наложение текстур. В связи с потребностями проектов в группе в 3D-моделях я начал потихоньку изучать, как использовать эту библиотеку (PS: я никогда не выполнял 3D-задачи для обучения обработке изображений, это сложно)... Колесо vtk (whl файл) можно найти по этой ссылке. Доступно по адресу: Архив: Пакеты расширений Python для Windows — Кристоф Гольке (uci.edu) https://www.lfd.uci.edu/~gohlke/pythonlibs/#vtk

        Я обнаружил, что учебные пособия по vtk в Интернете в основном взяты из книги Чжан Сяодуна «Продвинутая графика VTK и разработка изображений». Содержание очень подробное, но всегда есть точки знаний, которые я хочу найти, но не могу найти. Эта задача заключается в восстановлении внутренней стенки бумажной трубки из ленты , как показано на рисунке ниже:

         Информация о изогнутой поверхности этой бумажной трубки известна, ее диаметр составляет 76 мм. Здесь я поставлю объектив камеры в центр круга, чтобы сделать снимок, размер изображения 2592*1944 (500 пикселей), соотношение 4:3, полученное изображение следующее (texture.jpg ) :

        Теперь задача состоит в том , чтобы с помощью библиотеки vtk реконструировать поверхность, соответствующую полю зрения камеры, и сопоставить приведенное выше изображение в виде текстуры с реконструированной моделью.Как это сделать? 

Две библиотеки numpy и vtk рисуют пользовательские поверхности.

        Проверьте информацию и обнаружите, что vtk предоставляет важную функцию: vtk.vtkSurfaceReconstructionFilter() , эта функция может помочь нам выполнить неявную реконструкцию плоскости данных вершин в формате vtk.vtkPolyData() , а данные вершин vtk.vtkPolyData() могут Используйте numpy для сборки. Таким образом, идея заключается в следующем:

1. numpy создает пользовательские точки выборки поверхности (с использованием linspace и т. д.)

2. Библиотека vtk вызывает vtkSurfaceReconstructionFilter для реконструкции и рисования поверхности.

3. Используйте библиотеку vtk для наложения текстур.

2.1 numpy входные координаты вершины

        После расчета поле зрения захваченной текстуры и jpg соответствует части цилиндрической поверхности, которая пока называется дуговой поверхностью . Угол этой дуговой поверхности составляет около 90° , радиус 76 мм , высота 80 мм . Здесь 1 единица длины используется как 1 мм для рисования. Код для построения координат вершин следующий (с использованием numpy и vtk.vtkPoints () ):

import vtk
import numpy as np

# 半径
r = 76
# 极坐标系下构建顶点数据
theta = np.linspace(0, np.pi / 2, 61)
x = r * np.cos(theta)
y = r * np.sin(theta)

# vtkPoints格式的点
points = vtk.vtkPoints()
vertices = vtk.vtkCellArray()

i = 0
for z in range(80):
    for xi, yi in zip(x, y):
        points.InsertPoint(i, xi, yi, z)
        # vertices.InsertNextCell(1)
        # vertices.InsertCellPoint(i)
        i += 1

        Трехмерное изображение массива вершин можно нарисовать по данным подобных точек выборки (код не приводится, он используется только в качестве примера):

 

        Используя эти данные вершин, следующим шагом будет вызов vtkSurfaceReconstructionFilter для перестроения нашей пользовательской поверхности.

2.2  vtkSurfaceReconstructionРеконструкция поверхности фильтра

        Имея данные вершин в формате numpy.ndarray в версии 2.1, сначала преобразуйте их в формат данных vtk в формате vtk.vtkPolyData(), в основном используя функцию SetPoints:

polyData = vtk.vtkPolyData()
polyData.SetPoints(points)

        Затем настало время для vtkSurfaceReconstructionFilter и vtkContourFilter. Просто используйте vtkPolyData, преобразованный выше, в качестве входных данных, чтобы получить реконструированный объект поверхности:

polyData = vtk.vtkPolyData()
polyData.SetPoints(points)
# polyData.SetVerts(vertices)

surf = vtk.vtkSurfaceReconstructionFilter()
# 输入polyData数据
surf.SetInputData(polyData)
surf.SetNeighborhoodSize(20)
# 此处SetSampleSpacing数值小精度高但运行时间长,数值大则反之
surf.SetSampleSpacing(1.0)
surf.Update()

# 轮廓信息
contour = vtk.vtkContourFilter()
contour.SetInputConnection(surf.GetOutputPort())
contour.SetValue(0, 0.0)
contour.Update()

         На этом этапе мы фактически создали пользовательскую поверхность и загрузили ее в переменную контура в формате vtk.vtkContourFilter(). На этом этапе мы можем использовать картограф ( mapper ) и актер ( actor ) библиотеки vtk, чтобы нарисовать внешний вид контура. Для этой части существует множество онлайн-уроков, и вы можете проверить наличие пробелов самостоятельно:

texturemap = vtk.vtkTextureMapToPlane()
texturemap.SetInputData(contour.GetOutput())

# 设置纹理映射原点
texturemap.SetOrigin(76, 0, 0)
# 设置两个坐标轴的方向(根据自定义曲面的信息来输入)
texturemap.SetPoint1(0, 76, 0)
texturemap.SetPoint2(76, 0, 80)

# 映射器
mapper = vtk.vtkPolyDataMapper()
# 映射器输入自定义曲面模型信息
mapper.SetInputConnection(texturemap.GetOutputPort())
# 这一句十分关键,不然后面的纹理映射可能会失败
mapper.ScalarVisibilityOff()

# 演员
actor = vtk.vtkActor()
# 演员添加映射器
actor.SetMapper(mapper)

# 绘制
ren = vtk.vtkRenderer()
# 添加演员
ren.AddActor(actor)

#绘制窗口
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
renWin.SetSize(800, 800)

# 交互窗口
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
iren.Initialize()
renWin.Render()
iren.Start()

Пользовательское 3D-изображение поверхности без текстуры выглядит следующим образом:

         Мы прошли больше половины пути! Далее вам нужно всего лишь наложить текстуру на эту чисто белую плоскость, как если бы вы наклеили пленку на изогнутый экран ~

3. Наложение текстур

        Выполнить наложение текстуры на пользовательскую поверхность несложно, здесь для построения модели используется vtk.vtkTextureMapToPlane(), то есть изображение текстурыtexture.jpg раскладывается на пользовательскую поверхность вдоль определенной плоскости. Самое главное — установить три координаты SetOrigin, SetPoint1 и SetPoint2 , которые соответственно представляют начало координат и направления двух координатных осей. Положение начала координат и ориентация оси различны, а направление отображаемой текстуры также может быть инвертировано или зеркально отражено.Закон трехмерных координат нарисован здесь вручную, и вы можете это понять:

        Обратите внимание, что исходная позиция часто не равна (0, 0, 0) в исходной системе координат! , необходимо определять по координатам собственного графика. Затем вы можете напрямую выполнить наложение текстуры. Узор, показанный в файлеtexture.jpg, будет сопоставлен с пользовательской поверхностью дуги в соответствии с направлением плоскости и размером изображения выше . Как упоминалось выше, это похоже на наклеивание защитной пленки на изогнутую поверхность. screen ....Код следующий, и последующие шаги рисования такие же, как и выше , поэтому не буду вдаваться в подробности :

reader = vtk.vtkJPEGReader()
reader.SetFileName(r'texture.jpg')

texture = vtk.vtkTexture()  # 定义一个纹理类
texture.SetInputConnection(reader.GetOutputPort())
texture.InterpolateOn()

texturemap = vtk.vtkTextureMapToPlane()
texturemap.SetInputData(contour.GetOutput())
texturemap.SetOrigin(76, 0, 0)
texturemap.SetPoint1(0, 76, 0)
texturemap.SetPoint2(76, 0, 80)

# 映射器
mapper = vtk.vtkPolyDataMapper()
# 映射器输入自定义曲面模型信息
mapper.SetInputConnection(texturemap.GetOutputPort())
# 这一句十分关键,不然后面的纹理映射可能会失败
mapper.ScalarVisibilityOff()

# 演员
actor = vtk.vtkActor()
# 演员添加映射器
actor.SetMapper(mapper)
#演员添加纹理
actor.SetTexture(texture)

        Пока все готово, 3D-эффект выглядит следующим образом:

3D-эффекты наложения текстур

4. Резюме

        Сначала поместите код всего процесса для справки:

import vtk
import numpy as np

# 半径
r = 76
# 极坐标系下构建顶点数据
theta = np.linspace(0, np.pi / 2, 61)
x = r * np.cos(theta)
y = r * np.sin(theta)
# vtkPoints格式的点
points = vtk.vtkPoints()
vertices = vtk.vtkCellArray()
i = 0
for z in range(80):
    for xi, yi in zip(x, y):
        points.InsertPoint(i, xi, yi, z)
        # vertices.InsertNextCell(1)
        # vertices.InsertCellPoint(i)
        i += 1

polyData = vtk.vtkPolyData()
polyData.SetPoints(points)
# polyData.SetVerts(vertices)
surf = vtk.vtkSurfaceReconstructionFilter()
# 输入polyData数据
surf.SetInputData(polyData)
surf.SetNeighborhoodSize(20)
# 此处SetSampleSpacing数值小精度高但运行时间长,数值大则反之
surf.SetSampleSpacing(1.0)
surf.Update()
# 轮廓信息
contour = vtk.vtkContourFilter()
contour.SetInputConnection(surf.GetOutputPort())
contour.SetValue(0, 0.0)
contour.Update()

reader = vtk.vtkJPEGReader()
reader.SetFileName(r'texture.jpg')
texture = vtk.vtkTexture()  # 定义一个纹理类
texture.SetInputConnection(reader.GetOutputPort())
texture.InterpolateOn()
texturemap = vtk.vtkTextureMapToPlane()
texturemap.SetInputData(contour.GetOutput())
texturemap.SetOrigin(76, 0, 0)
texturemap.SetPoint1(0, 76, 0)
texturemap.SetPoint2(76, 0, 80)

# 映射器
mapper = vtk.vtkPolyDataMapper()
# 映射器输入自定义曲面模型信息
mapper.SetInputConnection(texturemap.GetOutputPort())
# 这一句十分关键,不然后面的纹理映射可能会失败
mapper.ScalarVisibilityOff()

# 演员
actor = vtk.vtkActor()
# 演员添加映射器
actor.SetMapper(mapper)
actor.SetTexture(texture)

# 绘制
ren = vtk.vtkRenderer()
# 添加演员
ren.AddActor(actor)

#绘制窗口
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(ren)
renWin.SetSize(800, 800)

# 交互窗口
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)
iren.Initialize()
renWin.Render()
iren.Start()

        Здесь вы можете изменить пользовательскую плоскость в соответствии со своей собственной моделью, например топографической картой и другими данными. Я только что познакомился с 3D-знаниями, включая наложение текстур, координатные соотношения и т. д. Я просто поделюсь ими, и метод не идеален. Добро пожаловать для обсуждения и обучения вместе !

Supongo que te gusta

Origin blog.csdn.net/m0_57315535/article/details/128155049
Recomendado
Clasificación