diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index ec17f6576f..2c49b9d0e2 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -323,6 +323,19 @@ namespace cv WCloud(InputArray cloud, const Color &color = Color::white()); }; + class CV_EXPORTS WPaintedCloud: public Widget3D + { + public: + //! Paint cloud with default gradient between cloud bounds points + WPaintedCloud(InputArray cloud); + + //! Paint cloud with default gradient between given points + WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2); + + //! Paint cloud with gradient specified by given colors between given points + WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2); + }; + class CV_EXPORTS WCloudCollection : public Widget3D { public: @@ -372,6 +385,7 @@ namespace cv template<> CV_EXPORTS WTrajectoryFrustums Widget::cast(); template<> CV_EXPORTS WTrajectorySpheres Widget::cast(); template<> CV_EXPORTS WCloud Widget::cast(); + template<> CV_EXPORTS WPaintedCloud Widget::cast(); template<> CV_EXPORTS WCloudCollection Widget::cast(); template<> CV_EXPORTS WCloudNormals Widget::cast(); template<> CV_EXPORTS WMesh Widget::cast(); diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp index 9ea1d76fe8..d5283d430b 100644 --- a/modules/viz/src/clouds.cpp +++ b/modules/viz/src/clouds.cpp @@ -72,15 +72,50 @@ cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors) } cv::viz::WCloud::WCloud(InputArray cloud, const Color &color) +{ + WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color)); + *this = cloud_widget; +} + + +template<> cv::viz::WCloud cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Painted Cloud Widget implementation + +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud) { vtkSmartPointer cloud_source = vtkSmartPointer::New(); cloud_source->SetCloud(cloud); cloud_source->Update(); + Vec6d bounds(cloud_source->GetOutput()->GetPoints()->GetBounds()); + + WPaintedCloud cloud_widget(cloud, Vec3d(bounds[0], bounds[2], bounds[4]), Vec3d(bounds[1], bounds[3], bounds[5])); + *this = cloud_widget; +} + +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2) +{ + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetCloud(cloud); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(p1.x, p1.y, p1.z); + elevation->SetHighPoint(p2.x, p2.y, p2.z); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, cloud_source->GetOutput()); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); mapper->ImmediateModeRenderingOff(); - mapper->ScalarVisibilityOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); vtkSmartPointer actor = vtkSmartPointer::New(); actor->GetProperty()->SetInterpolationToFlat(); @@ -88,13 +123,52 @@ cv::viz::WCloud::WCloud(InputArray cloud, const Color &color) actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } -template<> cv::viz::WCloud cv::viz::Widget::cast() +cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2) +{ + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetCloud(cloud); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(p1.x, p1.y, p1.z); + elevation->SetHighPoint(p2.x, p2.y, p2.z); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + + Color vc1 = vtkcolor(c1), vc2 = vtkcolor(c2); + vtkSmartPointer color_transfer = vtkSmartPointer::New(); + color_transfer->SetColorSpaceToRGB(); + color_transfer->AddRGBPoint(0.0, vc1[0], vc1[1], vc1[2]); + color_transfer->AddRGBPoint(1.0, vc2[0], vc2[1], vc2[2]); + color_transfer->SetScaleToLinear(); + color_transfer->Build(); + + //if in future some need to replace color table with real scalars, then this can be done usine next calls: + //vtkDataArray *float_scalars = vtkPolyData::SafeDownCast(elevation->GetOutput())->GetPointData()->GetArray("Elevation"); + //vtkSmartPointer polydata = cloud_source->GetOutput(); + //polydata->GetPointData()->SetScalars(color_transfer->MapScalars(float_scalars, VTK_COLOR_MODE_DEFAULT, 0)); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + mapper->SetLookupTable(color_transfer); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WPaintedCloud cv::viz::Widget::cast() { Widget3D widget = this->cast(); - return static_cast(widget); + return static_cast(widget); } /////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp index 4b963661d4..d5f969a495 100644 --- a/modules/viz/src/precomp.hpp +++ b/modules/viz/src/precomp.hpp @@ -128,6 +128,8 @@ #include #include #include +#include +#include #include #if !defined(_WIN32) || defined(__CYGWIN__) diff --git a/modules/viz/test/test_viz3d.cpp b/modules/viz/test/test_viz3d.cpp index 1fd1d4a338..66ec25db81 100644 --- a/modules/viz/test/test_viz3d.cpp +++ b/modules/viz/test/test_viz3d.cpp @@ -53,7 +53,9 @@ TEST(Viz_viz3d, develop) cv::viz::Viz3d viz("abc"); viz.setBackgroundMeshLab(); viz.showWidget("coo", cv::viz::WCoordinateSystem(1)); - viz.showWidget("cloud", cv::viz::WCloud(cloud)); + //viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0))); + //viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0), cv::viz::Color::green(), cv::viz::Color::red())); + viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud)); //viz.showWidget("h", cv::viz::Widget::fromPlyFile("d:/horse-red.ply")); //viz.showWidget("a", cv::viz::WArrow(cv::Point3f(0,0,0), cv::Point3f(1,1,1))); diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp index 5a685bb592..3e25399b25 100644 --- a/modules/viz/test/tests_simple.cpp +++ b/modules/viz/test/tests_simple.cpp @@ -95,7 +95,7 @@ TEST(Viz, 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::white(), Affine3d().translate(Vec3d(0, 0, 0)).rotate(Vec3d(CV_PI/2, 0, 0))); ccol.addCloud(cloud, Color::blue(), Affine3d().translate(Vec3d(1, 0, 0))); ccol.addCloud(cloud, Color::red(), Affine3d().translate(Vec3d(2, 0, 0))); @@ -105,6 +105,20 @@ TEST(Viz, show_cloud_collection) viz.spin(); } +TEST(Viz, show_painted_clouds) +{ + Mat cloud = readCloud(get_dragon_ply_file_path()); + + Viz3d viz("show_painted_clouds"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("cloud1", WPaintedCloud(cloud), Affine3d(Vec3d(0.0, -CV_PI/2, 0.0), Vec3d(-1.5, 0.0, 0.0))); + viz.showWidget("cloud2", WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(1.5, 0.0, 0.0))); + viz.showWidget("cloud3", WPaintedCloud(cloud, Vec3d(0.0, 0.0, -1.0), Vec3d(0.0, 0.0, 1.0), Color::blue(), Color::red())); + viz.showWidget("arrow", WArrow(Vec3d(0.0, 1.0, -1.0), Vec3d(0.0, 1.0, 1.0), 0.009, Color::raspberry())); + viz.spin(); +} + TEST(Viz, show_mesh) { Mesh mesh = Mesh::load(get_dragon_ply_file_path());