Swig实现C++的VTK对象到Python的传递
案例需求:
在某些场景下需要使用python脚本的形式将一些符号(markers、glyphs、...)加到图形应用程序中已存在的图元之上,以起到标记的作用。
之所以使用脚本来添加符号而非在原程序代码中开发,一方面是考虑此功能非程序需求定义的功能,另一方面是考虑在原程序代码中开发的时间成本和改动的影响范围。
针对此需求,有两种实现方式:
(1)在C++的应用中创建VTKRenderWindow对象,经过包装之后给到Python脚本,脚本中向VTKRenderWindow增加Renderer和Renderer下的Actor;
(2)在Python的脚本中创建VTKRenderWindow对象并增加Renderer和Renderer下的Actor,经过包装之后传给C++。
下面的案例实现虽然采用的第一种方式,但如果需要使用第二种方式,只需要在mod.i中增加VTK对象作为输入的接口,然后将VTKRenderWindow对象的创建换到Python脚本中。
案例实现:
1.安装Python。用于从VTK源码编译生成Python下的VTK包
我安装的是Python3.10.8
https://www.python.org/ftp/python/3.10.8/python-3.10.8-amd64.exe
2.从GitLab克隆VTK9.2.2
git clone -b v9.2.2 https://gitlab.kitware.com/vtk/vtk.git
3.编译VTK源码
以下是编译的脚本文件configure_and_build_VTK_9_2_2.bat
Windows:
setlocal EnableDelayedExpansion
set BUILD_DIR=D:\code\VTK2023\vtk
set PYTHONHOME=C:\Python\Python310
set PYTHONPATH=C:\Python\Python310\Lib;C:\Python\Python310\DLLs;C:\Python\Python310\libs
:: Create build and install directories
mkdir "D:\code\VTK2023\vtk9.2.2\vtk_build"
mkdir "D:\code\VTK2023\vtk9.2.2\vtk_install"
:: Execute cmake from VS build tools to build VTK
cmake -S"D:\code\VTK2023\vtk" ^
-G"Visual Studio 17 2022" ^
-B"D:\code\VTK2023\vtk9.2.2\vtk_build" ^
-DVTK_VERSIONED_INSTALL:BOOL=ON ^
-DVTK_CUSTOM_LIBRARY_SUFFIX:STRING=9.2 ^
-DVTK_WRAP_PYTHON=ON ^
-DVTK_PYTHON_VERSION=3 ^
-DVTK_WHEEL_BUILD=ON ^
-DVTK_INSTALL_SDK:BOOL=ON ^
-DCMAKE_BUILD_TYPE:STRING=Debug ^
-DVTK_SMP_IMPLEMENTATION_TYPE=TBB ^
-DVTK_SMP_ENABLE_STDTHREAD=ON ^
-DVTK_SMP_ENABLE_SEQUENTIAL=ON ^
-DCMAKE_INSTALL_LIBDIR:PATH=lib ^
-DCMAKE_INSTALL_INCLUDEDIR:PATH=include ^
-DCMAKE_INSTALL_PREFIX:PATH="D:/code/VTK2023/vtk9.2.2/vtk_install"
:: Compile code using msbuild:
cd "D:\code\VTK2023\vtk9.2.2\vtk_build"
:: Create Release DLL's
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Msbuild\Current\Bin\amd64\MSBuild.exe" VTK.sln /p:Configuration="Release"
"C:\Program Files\Microsoft Visual Studio\2022\Professional\Msbuild\Current\Bin\amd64\MSBuild.exe" INSTALL.vcxproj /p:Configuration="Release"
:: Build the wheel
python setup.py bdist_wheel
endlocal
出现以下错误:
D:\code\VTK2023\vtk9.2.2\vtk_build>python setup.py bdist_wheel
usage: setup.py [global_opts] cmd1 [cmd1_opts] [cmd2 [cmd2_opts] ...]
or: setup.py --help [cmd1 cmd2 ...]
or: setup.py --help-commands
or: setup.py cmd --help
error: invalid command 'bdist_wheel'
bdist_wheel
是一个用于构建Python包发布格式的命令,它可以生成.whl格式的二进制分发包。
解决方法:
pip install wheel
pip install --upgrade setuptools
最后在vtk_build目录下再来运行python setup.py bdist_wheel命令,会在dist文件夹中生成一个vtk-9.2.2.dev0-cp310-cp310-win_amd64.whl文件。
Install VTK的python包:
C:\Python\Python310\Scripts>pip install D:/code\VTK2023/vtk9.2.2/vtk_build/dist/vtk-9.2.2.dev0-cp310-cp310-win_amd64.whl
以一个C++的Demo验证编译的C++库文件是否可以正常使用:
头文件的目录为:D:/code/VTK2023/vtk9.2.2/vtk_install/vtk-9.2.2.data/headers/vtk-9.2
库文件的目录为:D:/code/VTK2023/vtk9.2.2/vtk_install/lib
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkFloatArray.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <array>
int main(int, char* [])
{
vtkNew<vtkNamedColors> colors;
std::array<std::array<double, 3>, 8> pts = { {{{0, 0, 0}},
{{1, 0, 0}},
{{1, 1, 0}},
{{0, 1, 0}},
{{0, 0, 1}},
{{1, 0, 1}},
{{1, 1, 1}},
{{0, 1, 1}}} };
// The ordering of the corner points on each face.
std::array<std::array<vtkIdType, 4>, 6> ordering = { {{{0, 3, 2, 1}},
{{4, 5, 6, 7}},
{{0, 1, 5, 4}},
{{1, 2, 6, 5}},
{{2, 3, 7, 6}},
{{3, 0, 4, 7}}} };
// We'll create the building blocks of polydata including data attributes.
vtkNew<vtkPolyData> cube;
vtkNew<vtkPoints> points;
vtkNew<vtkCellArray> polys;
vtkNew<vtkFloatArray> scalars;
// Load the point, cell, and data attributes.
for (auto i = 0ul; i < pts.size(); ++i)
{
points->InsertPoint(i, pts[i].data());
scalars->InsertTuple1(i, i);
}
for (auto&& i : ordering)
{
polys->InsertNextCell(vtkIdType(i.size()), i.data());
}
// We now assign the pieces to the vtkPolyData.
cube->SetPoints(points);
cube->SetPolys(polys);
cube->GetPointData()->SetScalars(scalars);
// Now we'll look at it.
vtkNew<vtkPolyDataMapper> cubeMapper;
cubeMapper->SetInputData(cube);
cubeMapper->SetScalarRange(cube->GetScalarRange());
vtkNew<vtkActor> cubeActor;
cubeActor->SetMapper(cubeMapper);
// The usual rendering stuff.
vtkNew<vtkCamera> camera;
camera->SetPosition(1, 1, 1);
camera->SetFocalPoint(0, 0, 0);
vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> renWin;
renWin->AddRenderer(renderer);
renWin->SetWindowName("Cube");
vtkNew<vtkRenderWindowInteractor> iren;
iren->SetRenderWindow(renWin);
renderer->AddActor(cubeActor);
renderer->SetActiveCamera(camera);
renderer->ResetCamera();
renderer->SetBackground(colors->GetColor3d("Cornsilk").GetData());
renWin->SetSize(600, 600);
// interact with data
renWin->Render();
iren->Start();
getchar();
return EXIT_SUCCESS;
}
以一个Python的Demo验证安装的VTK Python包是否可以正常使用:
# -*- coding: utf-8 -*-
import sys
# noinspection PyUnresolvedReferences
try:
import vtkmodules.vtkInteractionStyle
except ImportError as e:
sys.exit("cannot import vtk module:" + str(e))
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
def main():
colors = vtkNamedColors()
# Create a sphere
sphereSource = vtkSphereSource()
sphereSource.SetCenter(0.0, 0.0, 0.0)
sphereSource.SetRadius(5.0)
# Make the surface smooth.
sphereSource.SetPhiResolution(100)
sphereSource.SetThetaResolution(100)
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(sphereSource.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d("Cornsilk"))
renderer = vtkRenderer()
renderWindow = vtkRenderWindow()
renderWindow.SetWindowName("Sphere")
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
renderer.SetBackground(colors.GetColor3d("DarkGreen"))
renderWindow.Render()
renderWindowInteractor.Start()
if __name__ == '__main__':
main()
会报以下错误:
D:\code\VTK2023\vtk9.2.2\swigtest\vtkwrapper>"C:/Python/Python310/python.exe" vtkPyDemo.py
cannot import vtk module:DLL load failed while importing vtkInteractionStyle: The specified module could not be found.
解决步骤:
(1)在python的根目录下新建一个文件夹ExtraDLLs,从以下链接下载tbb12.dll放到该文件夹中:
tbb12.dll : Free .DLL download. - DLLme.com
(2)在python的根目录下新建一个set_lib_path.pth文件,内容如下:
import os, sys; os.add_dll_directory(sys.prefix+'\\DLLs'); os.add_dll_directory(sys.prefix+'\\ExtraDLLs'); os.add_dll_directory(sys.prefix+'\\Lib\\site-packages\\vtkmodules\\Release')
Python使用.pth文件扩展环境路径,也就是查找vtk的库文件时,会根据这个文件里的路径查找。
再来运行就正常了。
4.下载swigwin-4.0.2。用于包装C++的vtk对象并传递给python。
SWIG download | SourceForge.net
5.Swig包装VTK对象传递给Python的Demo代码
在同一文件夹(vtkwrapper)下新建以下三个文件:mod.h, mod.cpp, mod.i
mod.h
#pragma once
#include <vtkRenderWindow.h>
vtkRenderWindow* getVTKRenderWindow();
mod.cpp
#include "mod.h"
vtkRenderWindow* getVTKRenderWindow()
{
vtkRenderWindow* renderWindow = vtkRenderWindow::New();
renderWindow->SetWindowName("Sphere");
return renderWindow;
}
mod.i
%module mod
%{
#include "mod.h"
#include <vtkPythonUtil.h>
%}
%typemap(out) vtkRenderWindow*
{
$result = vtkPythonUtil::GetObjectFromPointer (static_cast<vtkRenderWindow*>($1));
}
%include "mod.h"
%init
%{
%}
6. 打包接口并生成相应的模块。
将swigwin-4.0.2放在与vtkwrapper文件夹同一层的目录,然后在vtkwrapper文件夹下,打开Windows PowerShell,输入以下命令将接口打包:
"..\swigwin-4.0.2\swig.exe" -c++ -python mod.i
执行完以上命令后,会生成mod.py和mod_wrap.cxx文件。
把接口打包成模块:
首先新增setup.py文件:
from distutils.core import setup, Extension
mod_module = Extension(
'_mod',
sources=['mod_wrap.cxx', 'mod.cpp'],
library_dirs=['D:/code/VTK2023/vtk9.2.2/vtk_install/lib'],
libraries=['vtksys', 'vtkRenderingCore', 'vtkWrappingPythonCore3.10'],
)
setup (name = 'mod',
version = '0.1',
author = "beshar",
description = """Simple swig example from docs""",
include_dirs=['D:/code/VTK2023/vtk9.2.2/vtk_install/vtk-9.2.2.data/headers/vtk-9.2'],
ext_modules = [mod_module],
py_modules = ["mod"],
)
然后执行以下命令:
"C:\Python\Python310\python.exe" setup.py build_ext --inplace
完成之后,会生成build文件夹,文件夹下中有一个python的库文件_mod.cp310-win_amd64.pyd
7.使用dumpbin查生成的pyd文件的依赖项。用于确定运行时的依赖。
::打开"VS2022 开发人员命令提示"
::切换目录到pyd文件所在的目录
D:
cd D:\code\VTK2023\vtk9.2.2\swigtest\vtkwrapper\build\lib.win-amd64-cpython-310
::执行dumpbin命令
dumpbin /dependents _mod.cp310-win_amd64.pyd
依赖性信息如下:
D:\code\VTK2023\vtk9.2.2\swigtest\vtkwrapper\build\lib.win-amd64-cpython-310>dumpbin /dependents _mod.cp310-win_amd64.pyd
Microsoft (R) COFF/PE Dumper Version 14.31.31107.0
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file _mod.cp310-win_amd64.pyd
File Type: DLL
Image has the following dependencies:
vtksys.dll
vtkRenderingCore.dll
vtkWrappingPythonCore3.10.dll
python310.dll
KERNEL32.dll
VCRUNTIME140.dll
api-ms-win-crt-heap-l1-1-0.dll
api-ms-win-crt-stdio-l1-1-0.dll
api-ms-win-crt-string-l1-1-0.dll
api-ms-win-crt-runtime-l1-1-0.dll
Summary
1000 .data
1000 .pdata
2000 .rdata
1000 .reloc
1000 .rsrc
3000 .text
可以看到pyd依赖VTK的C++库文件。
所以,我们将第3步(编译VTK源码)的VTK动态库文件拷贝到_mod.cp310-win_amd64.pyd同一文件夹下。
8.使用打包好的mod模块和getVTKRenderWindow接口
新建一个test.py文件来测试C++打包成python的getVTKRenderWindow接口
# -*- coding: utf-8 -*-
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderWindow,
vtkRenderWindowInteractor,
vtkRenderer
)
import mod
def main():
colors = vtkNamedColors()
# Create a sphere
sphereSource = vtkSphereSource()
sphereSource.SetCenter(0.0, 0.0, 0.0)
sphereSource.SetRadius(5.0)
# Make the surface smooth.
sphereSource.SetPhiResolution(100)
sphereSource.SetThetaResolution(100)
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(sphereSource.GetOutputPort())
actor = vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d("Cornsilk"))
renderer = vtkRenderer()
renderWindow = mod.getVTKRenderWindow()
renderWindow.AddRenderer(renderer)
renderWindowInteractor = vtkRenderWindowInteractor()
renderWindowInteractor.SetRenderWindow(renderWindow)
renderer.AddActor(actor)
renderer.SetBackground(colors.GetColor3d("DarkGreen"))
renderWindow.Render()
renderWindowInteractor.Start()
if __name__ == '__main__':
main()
使用以下命令运行test.py文件:
D:\code\VTK2023\vtk9.2.2\swigtest\vtkwrapper\build\lib.win-amd64-cpython-310>"C:/Python/Python310/python.exe" test.py
运行正常,至此全部流程完成。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!