diff --git a/modules/viz/doc/viz3d.rst b/modules/viz/doc/viz3d.rst index ad1356e587..b57e04118d 100644 --- a/modules/viz/doc/viz3d.rst +++ b/modules/viz/doc/viz3d.rst @@ -482,19 +482,19 @@ This class wraps mesh attributes, and it can load a mesh from a ``ply`` file. :: Mat polygons; //! Loads mesh from a given ply file - static Mesh3d loadMesh(const String& file); + static Mesh3d load(const String& file); private: /* hidden */ }; -viz::Mesh3d::loadMesh +viz::Mesh3d::load --------------------- Loads a mesh from a ``ply`` file. -.. ocv:function:: static Mesh3d loadMesh(const String& file) +.. ocv:function:: static Mesh3d load(const String& file) - :param file: File name. + :param file: File name (for no only PLY is supported) viz::KeyboardEvent diff --git a/modules/viz/include/opencv2/viz/types.hpp b/modules/viz/include/opencv2/viz/types.hpp index ff6bd5a689..0a1fc14699 100644 --- a/modules/viz/include/opencv2/viz/types.hpp +++ b/modules/viz/include/opencv2/viz/types.hpp @@ -112,7 +112,7 @@ namespace cv Mat polygons; //! Loads mesh from a given ply file - static Mesh3d loadMesh(const String& file); + static Mesh3d load(const String& file); }; class CV_EXPORTS Camera diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp index 16f274cf2d..014f79921f 100644 --- a/modules/viz/src/clouds.cpp +++ b/modules/viz/src/clouds.cpp @@ -106,143 +106,6 @@ template<> cv::viz::WCloud cv::viz::Widget::cast() /////////////////////////////////////////////////////////////////////////////////////////////// /// Cloud Collection Widget implementation -namespace cv { namespace viz { namespace -{ - struct CloudCollectionUtils - { - static inline vtkSmartPointer create(const Mat &cloud, vtkIdType &nr_points) - { - vtkSmartPointer polydata = vtkSmartPointer::New(); - vtkSmartPointer vertices = vtkSmartPointer::New(); - - polydata->SetVerts(vertices); - - vtkSmartPointer points = polydata->GetPoints(); - vtkSmartPointer initcells; - nr_points = cloud.total(); - - if (!points) - { - points = vtkSmartPointer::New(); - if (cloud.depth() == CV_32F) - points->SetDataTypeToFloat(); - else if (cloud.depth() == CV_64F) - points->SetDataTypeToDouble(); - polydata->SetPoints(points); - } - points->SetNumberOfPoints(nr_points); - - if (cloud.depth() == CV_32F) - { - // Get a pointer to the beginning of the data array - Vec3f *data_beg = vtkpoints_data(points); - Vec3f *data_end = NanFilter::copy(cloud, data_beg, cloud); - nr_points = data_end - data_beg; - } - else if (cloud.depth() == CV_64F) - { - // Get a pointer to the beginning of the data array - Vec3d *data_beg = vtkpoints_data(points); - Vec3d *data_end = NanFilter::copy(cloud, data_beg, cloud); - nr_points = data_end - data_beg; - } - points->SetNumberOfPoints(nr_points); - - // Update cells - vtkSmartPointer cells = vertices->GetData(); - // If no init cells and cells has not been initialized... - if (!cells) - cells = vtkSmartPointer::New(); - - // If we have less values then we need to recreate the array - if (cells->GetNumberOfTuples() < nr_points) - { - cells = vtkSmartPointer::New(); - - // If init cells is given, and there's enough data in it, use it - if (initcells && initcells->GetNumberOfTuples() >= nr_points) - { - cells->DeepCopy(initcells); - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - else - { - // If the number of tuples is still too small, we need to recreate the array - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - vtkIdType *cell = cells->GetPointer(0); - // Fill it with 1s - std::fill(cell, cell + nr_points * 2, 1); - cell++; - for (vtkIdType i = 0; i < nr_points; ++i, cell += 2) - *cell = i; - // Save the results in initcells - initcells = vtkSmartPointer::New(); - initcells->DeepCopy(cells); - } - } - else - { - // The assumption here is that the current set of cells has more data than needed - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - - // Set the cells and the vertices - vertices->SetCells(nr_points, cells); - return polydata; - } - - static void createMapper(vtkSmartPointer actor, vtkSmartPointer poly_data) - { - vtkDataSetMapper *mapper = vtkDataSetMapper::SafeDownCast(actor->GetMapper()); - if (!mapper) - { - // This is the first cloud - vtkSmartPointer mapper_new = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper_new->SetInputConnection(poly_data->GetProducerPort()); -#else - mapper_new->SetInputData(poly_data); -#endif - - mapper_new->SetScalarRange(0, 255); - mapper_new->SetScalarModeToUsePointData(); - - bool interpolation = (poly_data && poly_data->GetNumberOfCells() != poly_data->GetNumberOfVerts()); - - mapper_new->SetInterpolateScalarsBeforeMapping(interpolation); - mapper_new->ScalarVisibilityOn(); - mapper_new->ImmediateModeRenderingOff(); - - actor->SetNumberOfCloudPoints(int(std::max(1, poly_data->GetNumberOfPoints() / 10))); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper_new); - return ; - } - - vtkPolyData *data = vtkPolyData::SafeDownCast(mapper->GetInput()); - CV_Assert("Cloud Widget without data" && data); - - vtkSmartPointer appendFilter = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - appendFilter->AddInputConnection(mapper->GetInput()->GetProducerPort()); - appendFilter->AddInputConnection(poly_data->GetProducerPort()); -#else - appendFilter->AddInputData(data); - appendFilter->AddInputData(poly_data); -#endif - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - // Update the number of cloud points - vtkIdType old_cloud_points = actor->GetNumberOfCloudPoints(); - actor->SetNumberOfCloudPoints(int(std::max(1, old_cloud_points+poly_data->GetNumberOfPoints() / 10))); - } - }; -}}} - cv::viz::WCloudCollection::WCloudCollection() { // Just create the actor @@ -250,84 +113,67 @@ cv::viz::WCloudCollection::WCloudCollection() WidgetAccessor::setProp(*this, actor); } -void cv::viz::WCloudCollection::addCloud(InputArray _cloud, InputArray _colors, const Affine3d &pose) +void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose) { - Mat cloud = _cloud.getMat(); - Mat colors = _colors.getMat(); - CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); - CV_Assert(colors.depth() == CV_8U && cloud.size() == colors.size()); - - vtkIdType nr_points; - vtkSmartPointer polydata = CloudCollectionUtils::create(cloud, nr_points); - - // Filter colors - Vec3b* colors_data = new Vec3b[nr_points]; - NanFilter::copyColor(colors, colors_data, cloud); + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloud(cloud, colors); - vtkSmartPointer scalars = vtkSmartPointer::New(); - scalars->SetNumberOfComponents(3); - scalars->SetNumberOfTuples(nr_points); - scalars->SetArray(colors_data->val, 3 * nr_points, 0); - - // Assign the colors - polydata->GetPointData()->SetScalars(scalars); - - // Transform the poly data based on the pose vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(convertToVtkMatrix(pose.matrix)); + transform->SetMatrix(pose.matrix.val); vtkSmartPointer transform_filter = vtkSmartPointer::New(); + transform_filter->SetInputConnection(source->GetOutputPort()); transform_filter->SetTransform(transform); -#if VTK_MAJOR_VERSION <= 5 - transform_filter->SetInputConnection(polydata->GetProducerPort()); -#else - transform_filter->SetInputData(polydata); -#endif transform_filter->Update(); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); + vtkSmartPointer actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Incompatible widget type." && actor); - CloudCollectionUtils::createMapper(actor, transform_filter->GetOutput()); -} - -void cv::viz::WCloudCollection::addCloud(InputArray _cloud, const Color &color, const Affine3d &pose) -{ - Mat cloud = _cloud.getMat(); - CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); - - vtkIdType nr_points; - vtkSmartPointer polydata = CloudCollectionUtils::create(cloud, nr_points); + vtkSmartPointer poly_data = transform_filter->GetOutput(); - vtkSmartPointer scalars = vtkSmartPointer::New(); - scalars->SetNumberOfComponents(3); - scalars->SetNumberOfTuples(nr_points); - scalars->FillComponent(0, color[2]); - scalars->FillComponent(1, color[1]); - scalars->FillComponent(2, color[0]); + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); - // Assign the colors - polydata->GetPointData()->SetScalars(scalars); + if (!mapper) + { + // This is the first cloud + mapper = vtkSmartPointer::New(); +#if VTK_MAJOR_VERSION <= 5 + mapper->SetInput(poly_data); +#else + mapper->SetInputData(poly_data); +#endif + mapper->SetScalarRange(0, 255); + mapper->SetScalarModeToUsePointData(); + mapper->ScalarVisibilityOn(); + mapper->ImmediateModeRenderingOff(); + + actor->SetNumberOfCloudPoints(std::max(1, poly_data->GetNumberOfPoints()/10)); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + return; + } - // Transform the poly data based on the pose - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(convertToVtkMatrix(pose.matrix)); + vtkPolyData *data = vtkPolyData::SafeDownCast(mapper->GetInput()); + CV_Assert("Cloud Widget without data" && data); - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); + vtkSmartPointer appendFilter = vtkSmartPointer::New(); #if VTK_MAJOR_VERSION <= 5 - transform_filter->SetInputConnection(polydata->GetProducerPort()); + appendFilter->AddInput(data); + appendFilter->AddInput(poly_data); + mapper->SetInput(appendFilter->GetOutput()); #else - transform_filter->SetInputData(polydata); + appendFilter->AddInputData(data); + appendFilter->AddInputData(poly_data); + mapper->SetInputData(appendFilter->GetOutput()); #endif - transform_filter->Update(); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("Incompatible widget type." && actor); + actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + poly_data->GetNumberOfPoints()/10)); +} - CloudCollectionUtils::createMapper(actor, transform_filter->GetOutput()); +void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose) +{ + addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose); } template<> cv::viz::WCloudCollection cv::viz::Widget::cast() diff --git a/modules/viz/src/types.cpp b/modules/viz/src/types.cpp index 2c7f8e74be..63b9a0214d 100644 --- a/modules/viz/src/types.cpp +++ b/modules/viz/src/types.cpp @@ -128,7 +128,7 @@ namespace cv { namespace viz { namespace }; }}} -cv::viz::Mesh3d cv::viz::Mesh3d::loadMesh(const String& file) +cv::viz::Mesh3d cv::viz::Mesh3d::load(const String& file) { return MeshUtils::loadMesh(file); } diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp index 1a2e9fc94c..76e448da63 100644 --- a/modules/viz/test/tests_simple.cpp +++ b/modules/viz/test/tests_simple.cpp @@ -85,3 +85,18 @@ TEST(Viz, DISABLED_show_cloud_masked) viz.showWidget("dragon", WCloud(dragon_cloud)); viz.spin(); } + +TEST(Viz, DISABLED_show_cloud_collection) +{ + Mat cloud = readCloud(get_dragon_ply_file_path()); + + WCloudCollection ccol; + ccol.addCloud(cloud, Color::white(), Affine3d().translate(Vec3d(0, 0, 0)).rotate(Vec3d(1.57, 0, 0))); + ccol.addCloud(cloud, Color::blue(), Affine3d().translate(Vec3d(1, 0, 0))); + ccol.addCloud(cloud, Color::red(), Affine3d().translate(Vec3d(2, 0, 0))); + + Viz3d viz("show_cloud_collection"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("ccol", ccol); + viz.spin(); +}