Visualisation de données 3D avec des outils open source : un didacticiel utilisant VTK

Publié: 2022-03-11

Dans son récent article sur le blog de Toptal, le spécialiste des données Charles Cook a écrit sur le calcul scientifique avec des outils open source. Son tutoriel fait un point important sur les outils open source et le rôle qu'ils peuvent jouer dans le traitement facile des données et l'acquisition des résultats.

Mais dès que nous avons résolu toutes ces équations différentielles complexes, un autre problème surgit. Comment comprenons-nous et interprétons-nous les énormes quantités de données issues de ces simulations ? Comment visualisons-nous les gigaoctets potentiels de données, telles que les données avec des millions de points de grille dans une grande simulation ?

Une formation en visualisation de données pour les data scientists intéressés par les outils de visualisation de données 3D.

Lors de mon travail sur des problèmes similaires pour mon mémoire de maîtrise, je suis entré en contact avec le Visualization Toolkit, ou VTK - une puissante bibliothèque graphique spécialisée dans la visualisation de données.

Dans ce didacticiel, je vais donner une introduction rapide à VTK et à son architecture de pipeline, puis discuter d'un exemple de visualisation 3D réel utilisant les données d'un fluide simulé dans une pompe à turbine. Enfin je listerai les points forts de la bibliothèque, ainsi que les points faibles que j'ai rencontrés.

Visualisation des données et pipeline VTK

La bibliothèque open source VTK contient un solide pipeline de traitement et de rendu avec de nombreux algorithmes de visualisation sophistiqués. Ses capacités, cependant, ne s'arrêtent pas là, car au fil du temps, des algorithmes de traitement d'image et de maillage ont également été ajoutés. Dans mon projet actuel avec une société de recherche dentaire, j'utilise VTK pour des tâches de traitement basées sur le maillage dans une application de type CAO basée sur Qt. Les études de cas VTK montrent le large éventail d'applications appropriées.

L'architecture de VTK s'articule autour d'un puissant concept de pipeline. Les grandes lignes de ce concept sont présentées ici :

Voici à quoi ressemble le pipeline de visualisation de données VTK.

  • Les sources sont au tout début du pipeline et créent « quelque chose à partir de rien ». Par exemple, un vtkConeSource crée un cône 3D et un vtkSTLReader lit les fichiers de géométrie 3D *.stl .
  • Les filtres transforment la sortie des sources ou d'autres filtres en quelque chose de nouveau. Par exemple, un vtkCutter coupe la sortie de l'objet précédent dans les algorithmes en utilisant une fonction implicite, par exemple un plan. Tous les algorithmes de traitement fournis avec VTK sont implémentés sous forme de filtres et peuvent être librement chaînés.
  • Les mappeurs transforment les données en primitives graphiques. Par exemple, ils peuvent être utilisés pour spécifier une table de correspondance pour colorer les données scientifiques. Ils sont une manière abstraite de spécifier ce qu'il faut afficher.
  • Les acteurs représentent un objet (géométrie plus propriétés d'affichage) dans la scène. Des éléments tels que la couleur, l'opacité, l'ombrage ou l'orientation sont spécifiés ici.
  • Les moteurs de rendu et les fenêtres décrivent enfin le rendu sur l'écran d'une manière indépendante de la plate-forme.

Un pipeline de rendu VTK typique commence avec une ou plusieurs sources, les traite à l'aide de divers filtres en plusieurs objets de sortie, qui sont ensuite rendus séparément à l'aide de mappeurs et d'acteurs. La puissance derrière ce concept est le mécanisme de mise à jour. Si les paramètres des filtres ou des sources sont modifiés, tous les filtres, mappeurs, acteurs et fenêtres de rendu dépendants sont automatiquement mis à jour. Si, en revanche, un objet plus bas dans le pipeline a besoin d'informations pour effectuer ses tâches, il peut facilement les obtenir.

De plus, il n'est pas nécessaire de traiter directement avec des systèmes de rendu comme OpenGL. VTK encapsule toutes les tâches de bas niveau d'une manière indépendante de la plate-forme et (partiellement) du système de rendu ; le développeur travaille à un niveau beaucoup plus élevé.

Exemple de code avec un ensemble de données de pompe à rotor

Examinons un exemple de visualisation de données utilisant un ensemble de données d'écoulement de fluide dans une pompe à turbine rotative du concours de visualisation IEEE 2011. Les données elles-mêmes sont le résultat d'une simulation numérique de dynamique des fluides, un peu comme celle décrite dans l'article de Charles Cook.

Les données de simulation compressées de la pompe en vedette font plus de 30 Go. Il contient plusieurs parties et plusieurs pas de temps, d'où sa grande taille. Dans ce guide, nous allons jouer avec la partie rotor de l'un de ces pas de temps, qui a une taille compressée d'environ 150 Mo.

Mon langage de prédilection pour utiliser VTK est C++, mais il existe des mappages pour plusieurs autres langages comme Tcl/Tk, Java et Python. Si la cible n'est que la visualisation d'un seul ensemble de données, il n'est pas du tout nécessaire d'écrire du code et peut utiliser Paraview, une interface graphique pour la plupart des fonctionnalités de VTK.

L'ensemble de données et pourquoi 64 bits est nécessaire

J'ai extrait le jeu de données du rotor du jeu de données de 30 Go fourni ci-dessus, en ouvrant un pas de temps dans Paraview et en extrayant la partie rotor dans un fichier séparé. Il s'agit d'un fichier de grille non structuré, c'est-à-dire un volume 3D composé de points et de cellules 3D, comme des hexaèdres, des tétraèdres, etc. Chacun des points 3D a des valeurs associées. Parfois, les cellules ont également des valeurs associées, mais pas dans ce cas. Cette formation se concentrera sur la pression et la vitesse aux points et tentera de les visualiser dans leur contexte 3D.

La taille du fichier compressé est d'environ 150 Mo et la taille en mémoire est d'environ 280 Mo lorsqu'il est chargé avec VTK. Cependant, en le traitant dans VTK, le jeu de données est mis en cache plusieurs fois dans le pipeline VTK et nous atteignons rapidement la limite de mémoire de 2 Go pour les programmes 32 bits. Il existe des moyens d'économiser de la mémoire lors de l'utilisation de VTK, mais pour rester simple, nous allons simplement compiler et exécuter l'exemple en 64 bits.

Remerciements : L'ensemble de données est mis à disposition avec l'aimable autorisation de l'Institut de mécanique appliquée, Université Clausthal, Allemagne (Dipl. Wirtsch.-Ing. Andreas Lucius).

La cible

Ce que nous allons réaliser en utilisant VTK comme outil est la visualisation présentée dans l'image ci-dessous. En tant que contexte 3D, le contour de l'ensemble de données est affiché à l'aide d'un rendu filaire partiellement transparent. La partie gauche du jeu de données est ensuite utilisée pour afficher la pression en utilisant un simple codage couleur des surfaces. (Nous allons ignorer le rendu de volume plus complexe pour cet exemple). Afin de visualiser le champ de vitesse, la partie droite de l'ensemble de données est remplie de lignes de courant, qui sont codées par couleur en fonction de l'amplitude de leur vitesse. Ce choix de visualisation n'est techniquement pas idéal, mais je voulais garder le code VTK aussi simple que possible. De plus, il y a une raison pour que cet exemple fasse partie d'un défi de visualisation, c'est-à-dire beaucoup de turbulences dans le flux.

Il s'agit de la visualisation de données 3D résultante de notre exemple de didacticiel VTK.

Pas à pas

Je vais discuter du code VTK étape par étape, en montrant à quoi ressemblerait la sortie de rendu à chaque étape. Le code source complet peut être téléchargé à la fin de la formation.

Commençons par inclure tout ce dont nous avons besoin de VTK et ouvrons la fonction principale.

 #include <vtkActor.h> #include <vtkArrayCalculator.h> #include <vtkCamera.h> #include <vtkClipDataSet.h> #include <vtkCutter.h> #include <vtkDataSetMapper.h> #include <vtkInteractorStyleTrackballCamera.h> #include <vtkLookupTable.h> #include <vtkNew.h> #include <vtkPlane.h> #include <vtkPointData.h> #include <vtkPointSource.h> #include <vtkPolyDataMapper.h> #include <vtkProperty.h> #include <vtkRenderer.h> #include <vtkRenderWindow.h> #include <vtkRenderWindowInteractor.h> #include <vtkRibbonFilter.h> #include <vtkStreamTracer.h> #include <vtkSmartPointer.h> #include <vtkUnstructuredGrid.h> #include <vtkXMLUnstructuredGridReader.h> int main(int argc, char** argv) {

Ensuite, nous configurons le moteur de rendu et la fenêtre de rendu afin d'afficher nos résultats. Nous définissons la couleur d'arrière-plan et la taille de la fenêtre de rendu.

 // Setup the renderer vtkNew<vtkRenderer> renderer; renderer->SetBackground(0.9, 0.9, 0.9); // Setup the render window vtkNew<vtkRenderWindow> renWin; renWin->AddRenderer(renderer.Get()); renWin->SetSize(500, 500);

Avec ce code, nous pourrions déjà afficher une fenêtre de rendu statique. Au lieu de cela, nous choisissons d'ajouter un vtkRenderWindowInteractor afin de faire pivoter, zoomer et déplacer la scène de manière interactive.

 // Setup the render window interactor vtkNew<vtkRenderWindowInteractor> interact; vtkNew<vtkInteractorStyleTrackballCamera> style; interact->SetRenderWindow(renWin.Get()); interact->SetInteractorStyle(style.Get());

Nous avons maintenant un exemple en cours d'exécution montrant une fenêtre de rendu grise et vide.

Ensuite, nous chargeons l'ensemble de données à l'aide de l'un des nombreux lecteurs fournis avec VTK.

 // Read the file vtkSmartPointer<vtkXMLUnstructuredGridReader> pumpReader = vtkSmartPointer<vtkXMLUnstructuredGridReader>::New(); pumpReader->SetFileName("rotor.vtu");

Petite excursion dans la gestion de la mémoire VTK : VTK utilise un concept pratique de gestion automatique de la mémoire qui s'articule autour du comptage de références. Cependant, à la différence de la plupart des autres implémentations, le nombre de références est conservé dans les objets VTK eux-mêmes, au lieu de la classe de pointeur intelligent. Cela présente l'avantage que le nombre de références peut être augmenté, même si l'objet VTK est transmis sous forme de pointeur brut. Il existe deux manières principales de créer des objets VTK gérés. vtkNew<T> et vtkSmartPointer<T>::New() , la principale différence étant qu'un vtkSmartPointer<T> est implicitement castable en pointeur brut T* et peut être renvoyé à partir d'une fonction. Pour les instances de vtkNew<T> , nous devrons appeler .Get() pour obtenir un pointeur brut et nous ne pouvons le renvoyer qu'en l'enveloppant dans un vtkSmartPointer . Dans notre exemple, nous ne revenons jamais des fonctions et tous les objets vivent tout le temps, nous utiliserons donc le court vtkNew , avec seulement l'exception ci-dessus à des fins de démonstration.

À ce stade, rien n'a encore été lu dans le fichier. Nous ou un filtre plus bas dans la chaîne devrions appeler Update() pour que la lecture du fichier se produise réellement. Il est généralement préférable de laisser les classes VTK gérer elles-mêmes les mises à jour. Cependant, on souhaite parfois accéder directement au résultat d'un filtre, par exemple pour obtenir la plage de pressions dans ce jeu de données. Ensuite, nous devons appeler Update() manuellement. (Nous ne perdons pas de performances en appelant Update() plusieurs fois, car les résultats sont mis en cache.)

 // Get the pressure range pumpReader->Update(); double pressureRange[2]; pumpReader->GetOutput()->GetPointData()->GetArray("Pressure")->GetRange(pressureRange);

Ensuite, nous devons extraire la moitié gauche du jeu de données, en utilisant vtkClipDataSet . Pour ce faire, nous définissons d'abord un vtkPlane qui définit le fractionnement. Ensuite, nous verrons pour la première fois comment le pipeline VTK est connecté : successor->SetInputConnection(predecessor->GetOutputPort()) . Chaque fois que nous demandons une mise à jour à clipperLeft cette connexion garantit désormais que tous les filtres précédents sont également à jour.

 // Clip the left part from the input vtkNew<vtkPlane> planeLeft; planeLeft->SetOrigin(0.0, 0.0, 0.0); planeLeft->SetNormal(-1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperLeft; clipperLeft->SetInputConnection(pumpReader->GetOutputPort()); clipperLeft->SetClipFunction(planeLeft.Get());

Enfin, nous créons nos premiers acteurs et mappeurs pour afficher le rendu filaire de la moitié gauche. Notez que le mappeur est connecté à son filtre exactement de la même manière que les filtres entre eux. La plupart du temps, le moteur de rendu lui-même déclenche les mises à jour de tous les acteurs, mappeurs et chaînes de filtres sous-jacentes !

La seule ligne qui n'est pas explicite est probablement leftWireMapper->ScalarVisibilityOff(); - il interdit la coloration du filaire par des valeurs de pression, qui sont définies comme le tableau actuellement actif.

 // Create the wireframe representation for the left part vtkNew<vtkDataSetMapper> leftWireMapper; leftWireMapper->SetInputConnection(clipperLeft->GetOutputPort()); leftWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> leftWireActor; leftWireActor->SetMapper(leftWireMapper.Get()); leftWireActor->GetProperty()->SetRepresentationToWireframe(); leftWireActor->GetProperty()->SetColor(0.8, 0.8, 0.8); leftWireActor->GetProperty()->SetLineWidth(0.5); leftWireActor->GetProperty()->SetOpacity(0.8); renderer->AddActor(leftWireActor.Get());

À ce stade, la fenêtre de rendu affiche enfin quelque chose, c'est-à-dire le fil de fer de la partie gauche.

Il s'agit également d'un exemple résultant d'une visualisation de données 3D à partir de l'outil VTK.

Le rendu filaire pour la partie droite est créé de la même manière, en basculant la normale du plan d'un vtkClipDataSet (nouvellement créé) dans la direction opposée et en modifiant légèrement la couleur et l'opacité du mappeur et de l'acteur (nouvellement créés). Notez qu'ici, notre pipeline VTK se divise en deux directions (droite et gauche) à partir du même jeu de données d'entrée.

 // Clip the right part from the input vtkNew<vtkPlane> planeRight; planeRight->SetOrigin(0.0, 0.0, 0.0); planeRight->SetNormal(1.0, 0.0, 0.0); vtkNew<vtkClipDataSet> clipperRight; clipperRight->SetInputConnection(pumpReader->GetOutputPort()); clipperRight->SetClipFunction(planeRight.Get()); // Create the wireframe representation for the right part vtkNew<vtkDataSetMapper> rightWireMapper; rightWireMapper->SetInputConnection(clipperRight->GetOutputPort()); rightWireMapper->ScalarVisibilityOff(); vtkNew<vtkActor> rightWireActor; rightWireActor->SetMapper(rightWireMapper.Get()); rightWireActor->GetProperty()->SetRepresentationToWireframe(); rightWireActor->GetProperty()->SetColor(0.2, 0.2, 0.2); rightWireActor->GetProperty()->SetLineWidth(0.5); rightWireActor->GetProperty()->SetOpacity(0.1); renderer->AddActor(rightWireActor.Get());

La fenêtre de sortie affiche maintenant les deux pièces filaires, comme prévu.

La fenêtre de sortie de visualisation des données affiche maintenant les deux parties filaires, selon l'exemple VTK.

Nous sommes maintenant prêts à visualiser quelques données utiles ! Pour ajouter la visualisation de la pression à la partie gauche, nous n'avons pas besoin de faire grand-chose. Nous créons un nouveau mappeur et le connectons également à clipperLeft , mais cette fois nous colorons par le tableau de pression. C'est également ici que nous utilisons enfin la plage de pressureRange que nous avons dérivée ci-dessus.

 // Create the pressure representation for the left part vtkNew<vtkDataSetMapper> pressureColorMapper; pressureColorMapper->SetInputConnection(clipperLeft->GetOutputPort()); pressureColorMapper->SelectColorArray("Pressure"); pressureColorMapper->SetScalarRange(pressureRange); vtkNew<vtkActor> pressureColorActor; pressureColorActor->SetMapper(pressureColorMapper.Get()); pressureColorActor->GetProperty()->SetOpacity(0.5); renderer->AddActor(pressureColorActor.Get());

La sortie ressemble maintenant à l'image ci-dessous. La pression au milieu est très faible, aspirant le matériau dans la pompe. Ensuite, ce matériau est transporté vers l'extérieur, gagnant rapidement en pression. (Bien sûr, il devrait y avoir une légende de la carte des couleurs avec les valeurs réelles, mais je l'ai laissée de côté pour que l'exemple soit plus court.)

Lorsque la couleur est ajoutée à l'exemple de visualisation de données, nous commençons vraiment à voir comment fonctionne la pompe.

Maintenant, la partie la plus délicate commence. Nous voulons tracer des lignes de courant de vitesse dans la partie droite. Les lignes de courant sont générées par intégration dans un champ vectoriel à partir de points sources. Le champ vectoriel fait déjà partie de l'ensemble de données sous la forme du tableau vectoriel "Velocities". Nous n'avons donc qu'à générer les points source. vtkPointSource génère une sphère de points aléatoires. Nous allons générer 1500 points source, car la plupart d'entre eux ne se trouveront de toute façon pas dans l'ensemble de données et seront ignorés par le traceur de flux.

 // Create the source points for the streamlines vtkNew<vtkPointSource> pointSource; pointSource->SetCenter(0.0, 0.0, 0.015); pointSource->SetRadius(0.2); pointSource->SetDistributionToUniform(); pointSource->SetNumberOfPoints(1500);

Ensuite, nous créons le traceur de flux et définissons ses connexions d'entrée. "Attendez, plusieurs connexions ?", pourriez-vous dire. Oui - c'est le premier filtre VTK avec plusieurs entrées que nous rencontrons. La connexion d'entrée normale est utilisée pour le champ vectoriel et la connexion source est utilisée pour les points de départ. Puisque "Velocities" est le tableau vectoriel "actif" dans clipperRight , nous n'avons pas besoin de le spécifier ici explicitement. Enfin, nous spécifions que l'intégration doit être effectuée dans les deux sens à partir des points de départ et définissons la méthode d'intégration sur Runge-Kutta-4.5.

 vtkNew<vtkStreamTracer> tracer; tracer->SetInputConnection(clipperRight->GetOutputPort()); tracer->SetSourceConnection(pointSource->GetOutputPort()); tracer->SetIntegrationDirectionToBoth(); tracer->SetIntegratorTypeToRungeKutta45();

Notre prochain problème consiste à colorer les lignes de courant par l'amplitude de la vitesse. Puisqu'il n'y a pas de tableau pour les magnitudes des vecteurs, nous allons simplement calculer les magnitudes dans un nouveau tableau scalaire. Comme vous l'avez deviné, il existe également un filtre VTK pour cette tâche : vtkArrayCalculator . Il prend un ensemble de données et le sort tel quel, mais ajoute exactement un tableau qui est calculé à partir d'un ou plusieurs de ceux existants. Nous configurons ce calculateur de tableau pour prendre la magnitude du vecteur "Velocity" et le sortir comme "MagVelocity". Enfin, nous appelons à nouveau manuellement Update() , afin de dériver la plage du nouveau tableau.

 // Compute the velocity magnitudes and create the ribbons vtkNew<vtkArrayCalculator> magCalc; magCalc->SetInputConnection(tracer->GetOutputPort()); magCalc->AddVectorArrayName("Velocity"); magCalc->SetResultArrayName("MagVelocity"); magCalc->SetFunction("mag(Velocity)"); magCalc->Update(); double magVelocityRange[2]; magCalc->GetOutput()->GetPointData()->GetArray("MagVelocity")->GetRange(magVelocityRange);

vtkStreamTracer directement des polylignes et vtkArrayCalculator les transmet sans changement. Par conséquent, nous pourrions simplement afficher la sortie de magCalc directement en utilisant un nouveau mappeur et un nouvel acteur.

Au lieu de cela, dans cette formation, nous choisissons de rendre la sortie un peu plus agréable, en affichant des rubans à la place. vtkRibbonFilter génère des cellules 2D pour afficher des rubans pour toutes les polylignes de son entrée.

 // Create and render the ribbons vtkNew<vtkRibbonFilter> ribbonFilter; ribbonFilter->SetInputConnection(magCalc->GetOutputPort()); ribbonFilter->SetWidth(0.0005); vtkNew<vtkPolyDataMapper> streamlineMapper; streamlineMapper->SetInputConnection(ribbonFilter->GetOutputPort()); streamlineMapper->SelectColorArray("MagVelocity"); streamlineMapper->SetScalarRange(magVelocityRange); vtkNew<vtkActor> streamlineActor; streamlineActor->SetMapper(streamlineMapper.Get()); renderer->AddActor(streamlineActor.Get());

Ce qui manque encore maintenant, et qui est en fait nécessaire pour produire également les rendus intermédiaires, ce sont les cinq dernières lignes pour réellement rendre la scène et initialiser l'interacteur.

 // Render and show interactive window renWin->Render(); interact->Initialize(); interact->Start(); return 0; }

Enfin, nous arrivons à la visualisation finie, que je vais présenter une fois de plus ici :

L'exercice d'entraînement VTK donne cet exemple de visualisation complet.

Le code source complet de la visualisation ci-dessus peut être trouvé ici.

Le bon le mauvais et le laid

Je terminerai cet article avec une liste de mes avantages et inconvénients personnels du framework VTK.

  • Pour : Développement actif : VTK est en cours de développement actif par plusieurs contributeurs, principalement issus de la communauté de la recherche. Cela signifie que certains algorithmes de pointe sont disponibles, de nombreux formats 3D peuvent être importés et exportés, les bogues sont activement corrigés et les problèmes ont généralement une solution toute faite dans les forums de discussion.

  • Inconvénients : Fiabilité : Le couplage de nombreux algorithmes de différents contributeurs avec la conception de pipeline ouvert de VTK peut cependant entraîner des problèmes avec des combinaisons de filtres inhabituelles. J'ai dû aller plusieurs fois dans le code source de VTK afin de comprendre pourquoi ma chaîne de filtres complexe ne produit pas les résultats souhaités. Je recommanderais fortement de configurer VTK de manière à permettre le débogage.

  • Pour : Architecture logicielle : La conception du pipeline et l'architecture générale de VTK semblent bien pensées et c'est un plaisir de travailler avec. Quelques lignes de code peuvent produire des résultats étonnants. Les structures de données intégrées sont faciles à comprendre et à utiliser.

  • Con : Micro Architecture : Certaines décisions de conception micro-architecturales échappent à mon entendement. La const-exactitude est presque inexistante, les tableaux sont transmis en tant qu'entrées et sorties sans distinction claire. J'ai atténué cela pour mes propres algorithmes en abandonnant certaines performances et en utilisant mon propre wrapper pour vtkMath qui utilise des types 3D personnalisés comme typedef std::array<double, 3> Pnt3d; .

  • Pro : Micro Documentation : La documentation Doxygen de toutes les classes et filtres est complète et utilisable, les exemples et cas de test sur le wiki sont également d'une grande aide pour comprendre comment les filtres sont utilisés.

  • Con : Macro Documentation : Il existe plusieurs bons tutoriels et introductions à VTK sur le Web. Cependant, pour autant que je sache, il n'y a pas de grande documentation de référence qui explique comment des choses spécifiques sont faites. Si vous voulez faire quelque chose de nouveau, attendez-vous à chercher comment le faire pendant un certain temps. De plus, il est difficile de trouver le filtre spécifique pour une tâche. Cependant, une fois que vous l'avez trouvé, la documentation Doxygen suffira généralement. Un bon moyen d'explorer le framework VTK est de télécharger et d'expérimenter Paraview.

  • Pour : Prise en charge de la parallélisation implicite : Si vos sources peuvent être divisées en plusieurs parties pouvant être traitées indépendamment, la parallélisation est aussi simple que de créer une chaîne de filtres distincte dans chaque thread qui traite une seule partie. La plupart des grands problèmes de visualisation entrent généralement dans cette catégorie.

  • Inconvénient : Pas de prise en charge de la parallélisation explicite : Si vous n'êtes pas confronté à de gros problèmes divisibles, mais que vous souhaitez utiliser plusieurs cœurs, vous êtes seul. Vous devrez déterminer quelles classes sont thread-safe, ou même ré-entrantes par essais et erreurs ou en lisant la source. Une fois, j'ai retrouvé un problème de parallélisation avec un filtre VTK qui utilisait une variable globale statique pour appeler une bibliothèque C.

  • Pro : Buildsystem CMake : Le méta-système de construction multi-plateforme CMake est également développé par Kitware (les fabricants de VTK) et utilisé dans de nombreux projets en dehors de Kitware. Il s'intègre très bien avec VTK et rend la mise en place d'un système de construction pour plusieurs plates-formes beaucoup moins pénible.

  • Pour : Indépendance de la plate-forme, licence et longévité : VTK est indépendant de la plate-forme et est sous licence très permissive de type BSD. De plus, un soutien professionnel est disponible pour les projets importants qui en ont besoin. Kitware est soutenu par de nombreuses entités de recherche et d'autres sociétés et existera pendant un certain temps.

Dernier mot

Dans l'ensemble, VTK est le meilleur outil de visualisation de données pour les types de problèmes que j'aime. Si jamais vous rencontrez un projet qui nécessite une visualisation, un traitement de maillage, un traitement d'image ou des tâches similaires, essayez de lancer Paraview avec un exemple d'entrée et évaluez si VTK pourrait être l'outil pour vous.