///////////////////////////////////////////////////////////////////////////////////////////////
/// Cloud Collection Widget implementation
-namespace cv { namespace viz { namespace
-{
- struct CloudCollectionUtils
- {
- static inline vtkSmartPointer<vtkPolyData> create(const Mat &cloud, vtkIdType &nr_points)
- {
- vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
- vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();
-
- polydata->SetVerts(vertices);
-
- vtkSmartPointer<vtkPoints> points = polydata->GetPoints();
- vtkSmartPointer<vtkIdTypeArray> initcells;
- nr_points = cloud.total();
-
- if (!points)
- {
- points = vtkSmartPointer<vtkPoints>::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<float>(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<double>(points);
- Vec3d *data_end = NanFilter::copy(cloud, data_beg, cloud);
- nr_points = data_end - data_beg;
- }
- points->SetNumberOfPoints(nr_points);
-
- // Update cells
- vtkSmartPointer<vtkIdTypeArray> cells = vertices->GetData();
- // If no init cells and cells has not been initialized...
- if (!cells)
- cells = vtkSmartPointer<vtkIdTypeArray>::New();
-
- // If we have less values then we need to recreate the array
- if (cells->GetNumberOfTuples() < nr_points)
- {
- cells = vtkSmartPointer<vtkIdTypeArray>::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<vtkIdTypeArray>::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<vtkLODActor> actor, vtkSmartPointer<vtkPolyData> poly_data)
- {
- vtkDataSetMapper *mapper = vtkDataSetMapper::SafeDownCast(actor->GetMapper());
- if (!mapper)
- {
- // This is the first cloud
- vtkSmartPointer<vtkPolyDataMapper> mapper_new = vtkSmartPointer<vtkPolyDataMapper>::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<vtkIdType>(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<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::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<vtkIdType>(1, old_cloud_points+poly_data->GetNumberOfPoints() / 10)));
- }
- };
-}}}
-
cv::viz::WCloudCollection::WCloudCollection()
{
// Just create the actor
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<vtkPolyData> polydata = CloudCollectionUtils::create(cloud, nr_points);
-
- // Filter colors
- Vec3b* colors_data = new Vec3b[nr_points];
- NanFilter::copyColor(colors, colors_data, cloud);
+ vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
+ source->SetColorCloud(cloud, colors);
- vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::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<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
- transform->PreMultiply();
- transform->SetMatrix(convertToVtkMatrix(pose.matrix));
+ transform->SetMatrix(pose.matrix.val);
vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::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<vtkLODActor> 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<vtkPolyData> polydata = CloudCollectionUtils::create(cloud, nr_points);
+ vtkSmartPointer<vtkPolyData> poly_data = transform_filter->GetOutput();
- vtkSmartPointer<vtkUnsignedCharArray> scalars = vtkSmartPointer<vtkUnsignedCharArray>::New();
- scalars->SetNumberOfComponents(3);
- scalars->SetNumberOfTuples(nr_points);
- scalars->FillComponent(0, color[2]);
- scalars->FillComponent(1, color[1]);
- scalars->FillComponent(2, color[0]);
+ vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
- // Assign the colors
- polydata->GetPointData()->SetScalars(scalars);
+ if (!mapper)
+ {
+ // This is the first cloud
+ mapper = vtkSmartPointer<vtkPolyDataMapper>::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<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
- transform->PreMultiply();
- transform->SetMatrix(convertToVtkMatrix(pose.matrix));
+ vtkPolyData *data = vtkPolyData::SafeDownCast(mapper->GetInput());
+ CV_Assert("Cloud Widget without data" && data);
- vtkSmartPointer<vtkTransformPolyDataFilter> transform_filter = vtkSmartPointer<vtkTransformPolyDataFilter>::New();
- transform_filter->SetTransform(transform);
+ vtkSmartPointer<vtkAppendPolyData> appendFilter = vtkSmartPointer<vtkAppendPolyData>::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<cv::viz::WCloudCollection>()