From baee8c3aa58fb88ec25b231ac41c65df122531f1 Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Wed, 1 Jan 2014 22:36:08 +0400 Subject: [PATCH] refactored Mesh, added tests, added failing "twice spin()" test --- modules/viz/include/opencv2/viz/widgets.hpp | 4 +- modules/viz/src/clouds.cpp | 192 +++++++++------------------- modules/viz/src/vtk/vtkCloudMatSource.cpp | 6 +- modules/viz/test/tests_simple.cpp | 34 +++++ 4 files changed, 98 insertions(+), 138 deletions(-) diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index 28a2acb..27f211c 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -65,14 +65,14 @@ namespace cv SHADING }; - enum RenderingRepresentationProperties + enum RepresentationValues { REPRESENTATION_POINTS, REPRESENTATION_WIREFRAME, REPRESENTATION_SURFACE }; - enum ShadingRepresentationProperties + enum ShadingValues { SHADING_FLAT, SHADING_GOURAUD, diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp index 014f799..2247dff 100644 --- a/modules/viz/src/clouds.cpp +++ b/modules/viz/src/clouds.cpp @@ -126,49 +126,47 @@ void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, co transform_filter->SetTransform(transform); transform_filter->Update(); + vtkSmartPointer polydata = transform_filter->GetOutput(); vtkSmartPointer actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Incompatible widget type." && actor); - vtkSmartPointer poly_data = transform_filter->GetOutput(); - vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); - if (!mapper) { // This is the first cloud mapper = vtkSmartPointer::New(); #if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(poly_data); + mapper->SetInput(polydata); #else - mapper->SetInputData(poly_data); + mapper->SetInputData(polydata); #endif mapper->SetScalarRange(0, 255); mapper->SetScalarModeToUsePointData(); mapper->ScalarVisibilityOn(); mapper->ImmediateModeRenderingOff(); - actor->SetNumberOfCloudPoints(std::max(1, poly_data->GetNumberOfPoints()/10)); + actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints()/10)); actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->BackfaceCullingOn(); actor->SetMapper(mapper); return; } - vtkPolyData *data = vtkPolyData::SafeDownCast(mapper->GetInput()); - CV_Assert("Cloud Widget without data" && data); + vtkPolyData *currdata = vtkPolyData::SafeDownCast(mapper->GetInput()); + CV_Assert("Cloud Widget without data" && currdata); vtkSmartPointer appendFilter = vtkSmartPointer::New(); #if VTK_MAJOR_VERSION <= 5 - appendFilter->AddInput(data); - appendFilter->AddInput(poly_data); + appendFilter->AddInput(currdata); + appendFilter->AddInput(polydata); mapper->SetInput(appendFilter->GetOutput()); #else - appendFilter->AddInputData(data); - appendFilter->AddInputData(poly_data); + appendFilter->AddInputData(currdata); + appendFilter->AddInputData(polydata); mapper->SetInputData(appendFilter->GetOutput()); #endif - actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + poly_data->GetNumberOfPoints()/10)); + actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10)); } void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose) @@ -328,150 +326,78 @@ template<> cv::viz::WCloudNormals cv::viz::Widget::cast( /////////////////////////////////////////////////////////////////////////////////////////////// /// Mesh Widget implementation -namespace cv { namespace viz { namespace -{ - struct MeshUtils - { - template - static Vec<_Tp, 3> * copy(const Mat &source, Vec<_Tp, 3> *output, int *look_up, const Mat &nan_mask) - { - CV_Assert(DataDepth<_Tp>::value == source.depth() && source.size() == nan_mask.size()); - CV_Assert(nan_mask.channels() == 3 || nan_mask.channels() == 4); - CV_DbgAssert(DataDepth<_Tp>::value == nan_mask.depth()); - - int s_chs = source.channels(); - int m_chs = nan_mask.channels(); - - int index = 0; - const _Tp* srow = source.ptr<_Tp>(0); - const _Tp* mrow = nan_mask.ptr<_Tp>(0); - - for (int x = 0; x < source.cols; ++x, srow += s_chs, mrow += m_chs) - { - if (!isNan(mrow[0]) && !isNan(mrow[1]) && !isNan(mrow[2])) - { - look_up[x] = index; - *output++ = Vec<_Tp, 3>(srow); - ++index; - } - } - return output; - } - }; -}}} - cv::viz::WMesh::WMesh(const Mesh3d &mesh) { - CV_Assert(mesh.cloud.rows == 1 && (mesh.cloud.type() == CV_32FC3 || mesh.cloud.type() == CV_64FC3 || mesh.cloud.type() == CV_32FC4 || mesh.cloud.type() == CV_64FC4)); - CV_Assert(mesh.colors.empty() || (mesh.colors.depth() == CV_8U && mesh.cloud.size() == mesh.colors.size())); - CV_Assert(!mesh.polygons.empty() && mesh.polygons.type() == CV_32SC1); - - vtkSmartPointer points = vtkSmartPointer::New(); - vtkIdType nr_points = mesh.cloud.total(); - Mat look_up_mat(1, nr_points, CV_32SC1); - int * look_up = look_up_mat.ptr(); - points->SetNumberOfPoints(nr_points); - - // Copy data from cloud to vtkPoints - if (mesh.cloud.depth() == CV_32F) - { - points->SetDataTypeToFloat(); - Vec3f *data_beg = vtkpoints_data(points); - Vec3f *data_end = MeshUtils::copy(mesh.cloud, data_beg, look_up, mesh.cloud); - nr_points = data_end - data_beg; - } - else - { - points->SetDataTypeToDouble(); - Vec3d *data_beg = vtkpoints_data(points); - Vec3d *data_end = MeshUtils::copy(mesh.cloud, data_beg, look_up, mesh.cloud); - nr_points = data_end - data_beg; - } + CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1); - vtkSmartPointer scalars; - - if (!mesh.colors.empty()) - { - Vec3b *colors_data = new Vec3b[nr_points]; - NanFilter::copyColor(mesh.colors, colors_data, mesh.cloud); - - scalars = vtkSmartPointer::New(); - scalars->SetNumberOfComponents(3); - scalars->SetNumberOfTuples(nr_points); - scalars->SetArray(colors_data->val, 3 * nr_points, 0); - } - - points->SetNumberOfPoints(nr_points); - - vtkSmartPointer data; + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloud(mesh.cloud, mesh.colors); + source->Update(); - if (mesh.polygons.size().area() > 1) + Mat lookup_buffer(1, mesh.cloud.total(), CV_32SC1); + int *lookup = lookup_buffer.ptr(); + for(int y = 0, index = 0; y < mesh.cloud.rows; ++y) { - vtkSmartPointer cell_array = vtkSmartPointer::New(); - const int * polygons = mesh.polygons.ptr(); + int s_chs = mesh.cloud.channels(); - int idx = 0; - int poly_size = mesh.polygons.total(); - for (int i = 0; i < poly_size; ++idx) + if (mesh.cloud.depth() == CV_32F) { - int n_points = polygons[i++]; + const float* srow = mesh.cloud.ptr(y); + const float* send = srow + mesh.cloud.cols * s_chs; - cell_array->InsertNextCell(n_points); - for (int j = 0; j < n_points; ++j, ++idx) - cell_array->InsertCellPoint(look_up[polygons[i++]]); + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; } - vtkSmartPointer polydata = vtkSmartPointer::New(); - cell_array->GetData()->SetNumberOfValues(idx); - cell_array->Squeeze(); - polydata->SetStrips(cell_array); - polydata->SetPoints(points); - if (scalars) - polydata->GetPointData()->SetScalars(scalars); + if (mesh.cloud.depth() == CV_64F) + { + const double* srow = mesh.cloud.ptr(y); + const double* send = srow + mesh.cloud.cols * s_chs; - data = polydata; + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; + } } - else - { - // Only one polygon - vtkSmartPointer polygon = vtkSmartPointer::New(); - const int * polygons = mesh.polygons.ptr(); - int n_points = polygons[0]; + lookup = lookup_buffer.ptr(); - polygon->GetPointIds()->SetNumberOfIds(n_points); + vtkSmartPointer polydata = source->GetOutput(); + polydata->SetVerts(0); - for (int j = 1; j < n_points+1; ++j) - polygon->GetPointIds()->SetId(j, look_up[polygons[j]]); + const int * polygons = mesh.polygons.ptr(); + vtkSmartPointer cell_array = vtkSmartPointer::New(); - vtkSmartPointer poly_grid = vtkSmartPointer::New(); - poly_grid->Allocate(1, 1); - poly_grid->InsertNextCell(polygon->GetCellType(), polygon->GetPointIds()); - poly_grid->SetPoints(points); - - if (scalars) - poly_grid->GetPointData()->SetScalars(scalars); + int idx = 0; + int poly_size = mesh.polygons.total(); + for (int i = 0; i < poly_size; ++idx) + { + int n_points = polygons[i++]; - data = poly_grid; + cell_array->InsertNextCell(n_points); + for (int j = 0; j < n_points; ++j, ++idx) + cell_array->InsertCellPoint(lookup[polygons[i++]]); } + cell_array->GetData()->SetNumberOfValues(idx); + cell_array->Squeeze(); + polydata->SetStrips(cell_array); - vtkSmartPointer actor = vtkSmartPointer::New(); + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); +#if VTK_MAJOR_VERSION <= 5 + mapper->SetInput(polydata); +#else + mapper->SetInputData(polydata); +#endif + vtkSmartPointer actor = vtkSmartPointer::New(); + //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10)); actor->GetProperty()->SetRepresentationToSurface(); actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->EdgeVisibilityOff(); actor->GetProperty()->ShadingOff(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(data); -#else - mapper->SetInputData(data); -#endif - mapper->ImmediateModeRenderingOff(); - - vtkIdType numberOfCloudPoints = nr_points * 0.1; - actor->SetNumberOfCloudPoints(int(numberOfCloudPoints > 1 ? numberOfCloudPoints : 1)); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); diff --git a/modules/viz/src/vtk/vtkCloudMatSource.cpp b/modules/viz/src/vtk/vtkCloudMatSource.cpp index 46603a7..cf3d21e 100644 --- a/modules/viz/src/vtk/vtkCloudMatSource.cpp +++ b/modules/viz/src/vtk/vtkCloudMatSource.cpp @@ -163,14 +163,14 @@ int cv::viz::vtkCloudMatSource::filterNanCopy(const Mat& cloud) points->Allocate(cloud.total()); points->SetNumberOfPoints(cloud.total()); - int cn = cloud.channels(); + int s_chs = cloud.channels(); int total = 0; for (int y = 0; y < cloud.rows; ++y) { const _Tp* srow = cloud.ptr<_Tp>(y); - const _Tp* send = srow + cloud.cols * cn; + const _Tp* send = srow + cloud.cols * s_chs; - for (; srow != send; srow += cn) + for (; srow != send; srow += s_chs) if (!isNan(srow)) points->SetPoint(total++, srow); } diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp index 76e448d..ece1370 100644 --- a/modules/viz/test/tests_simple.cpp +++ b/modules/viz/test/tests_simple.cpp @@ -100,3 +100,37 @@ TEST(Viz, DISABLED_show_cloud_collection) viz.showWidget("ccol", ccol); viz.spin(); } + +TEST(Viz, DISABLED_show_mesh) +{ + Mesh3d mesh = Mesh3d::load(get_dragon_ply_file_path()); + + Viz3d viz("show_mesh"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh)); + viz.spin(); +} + +TEST(Viz, DISABLED_show_mesh_random_colors) +{ + Mesh3d mesh = Mesh3d::load(get_dragon_ply_file_path()); + theRNG().fill(mesh.colors, RNG::UNIFORM, 0, 255); + + Viz3d viz("show_mesh_random_color"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh)); + viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG); + viz.spin(); +} + +TEST(Viz, DISABLED_spin_twice_____________________________TODO_UI_BUG) +{ + Mesh3d mesh = Mesh3d::load(get_dragon_ply_file_path()); + + Viz3d viz("spin_twice"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh)); + viz.spin(); + viz.spin(); +} + -- 2.7.4