From 1a5dfe421dcbc5c2d831fff61ad7d5bc69c2c59c Mon Sep 17 00:00:00 2001 From: Anatoly Baksheev Date: Sat, 15 Feb 2014 17:02:17 +0400 Subject: [PATCH] Added WidgetMerger, Polyline - colors support for each point independently, simple widgets now compute color array instead of setting global color --- modules/viz/doc/widget.rst | 41 +++++++ modules/viz/include/opencv2/viz/widgets.hpp | 15 +++ modules/viz/src/clouds.cpp | 114 ++++++++++++++------ modules/viz/src/precomp.hpp | 5 + modules/viz/src/shapes.cpp | 101 ++++++++--------- modules/viz/test/tests_simple.cpp | 31 +++++- 6 files changed, 222 insertions(+), 85 deletions(-) diff --git a/modules/viz/doc/widget.rst b/modules/viz/doc/widget.rst index 2802edff79..31546ae8e2 100644 --- a/modules/viz/doc/widget.rst +++ b/modules/viz/doc/widget.rst @@ -1025,3 +1025,44 @@ Constructs a WMesh. :param polygons: Points of the mesh object. :param colors: Point colors. :param normals: Point normals. + +viz::WWidgetMerger +--------------------- +.. ocv:class:: WWidgetMerger + +This class allos to merge several widgets to single one. It has quite limited functionality and can't merge widgets with different attributes. For instance, +if widgetA has color array and widgetB has only global color defined, then result of merge won't have color at all. The class is suitable for merging large amount of similar widgets. + + class CV_EXPORTS WWidgetMerger : public Widget3D + { + public: + WWidgetMerger(); + + //! Add widget to merge with optional position change + void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity()); + + //! Repacks internal structure to sinle widget + void finalize(); + }; + + +viz::WWidgetMerger::WWidgetMerger +--------------------------------------- +Constructs a WWidgetMerger. + +.. ocv:WWidgetMerger:: WWidgetMerger() + +viz::WWidgetMerger::addCloud +------------------------------- +Adds a cloud to the collection. + +.. ocv:function:: void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity()) + + :param widget: Widget to merge. + :param pose: Pose of the widget. + +viz::WWidgetMerger::finalize +------------------------------- +Finalizes merger data and constructs final merged widget + +.. ocv:function:: void finalize() \ No newline at end of file diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index 6910196c3d..0c2a4f7050 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -201,6 +201,7 @@ namespace cv class CV_EXPORTS WPolyLine : public Widget3D { public: + WPolyLine(InputArray points, InputArray colors); WPolyLine(InputArray points, const Color &color = Color::white()); }; @@ -362,6 +363,19 @@ namespace cv WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()); }; + + class CV_EXPORTS WWidgetMerger : public Widget3D + { + public: + WWidgetMerger(); + + //! Add widget to merge with optional position change + void addWidget(const Widget3D& widget, const Affine3d &pose = Affine3d::Identity()); + + //! Repacks internal structure to sinle widget + void finalize(); + }; + ///////////////////////////////////////////////////////////////////////////// /// Utility exports @@ -391,6 +405,7 @@ namespace cv template<> CV_EXPORTS WCloudCollection Widget::cast(); template<> CV_EXPORTS WCloudNormals Widget::cast(); template<> CV_EXPORTS WMesh Widget::cast(); + template<> CV_EXPORTS WWidgetMerger Widget::cast(); } /* namespace viz */ } /* namespace cv */ diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp index 349de2f5f2..eec02639e5 100644 --- a/modules/viz/src/clouds.cpp +++ b/modules/viz/src/clouds.cpp @@ -193,8 +193,21 @@ template<> cv::viz::WPaintedCloud cv::viz::Widget::cast( cv::viz::WCloudCollection::WCloudCollection() { - // Just create the actor + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(append_filter->GetOutputPort()); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); + mapper->SetScalarRange(0, 255); + mapper->ScalarVisibilityOn(); + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetNumberOfCloudPoints(1); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); } @@ -206,33 +219,11 @@ void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, co vtkSmartPointer polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose); vtkSmartPointer actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("Incompatible widget type." && actor); - - vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); - if (!mapper) - { - vtkSmartPointer append_filter = vtkSmartPointer::New(); - VtkUtils::AddInputData(append_filter, polydata); - - // This is the first cloud - mapper = vtkSmartPointer::New(); - mapper->SetScalarRange(0, 255); - mapper->SetScalarModeToUsePointData(); - mapper->ScalarVisibilityOn(); - mapper->ImmediateModeRenderingOff(); - mapper->SetInputConnection(append_filter->GetOutputPort()); - - actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints()/10)); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper); - return; - } + CV_Assert("Correctness check." && actor); - vtkSmartPointer producer = mapper->GetInputConnection(0, 0)->GetProducer(); + vtkSmartPointer producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer(); vtkSmartPointer append_filter = vtkAppendPolyData::SafeDownCast(producer); VtkUtils::AddInputData(append_filter, polydata); - append_filter->Modified(); actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10)); } @@ -257,7 +248,6 @@ void cv::viz::WCloudCollection::finalize() vtkSmartPointer polydata = append_filter->GetOutput(); mapper->RemoveInputConnection(0, 0); VtkUtils::SetInputData(mapper, polydata); - mapper->Modified(); } template<> cv::viz::WCloudCollection cv::viz::Widget::cast() @@ -332,20 +322,18 @@ cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, in } } - vtkSmartPointer polyData = vtkSmartPointer::New(); - polyData->SetPoints(points); - polyData->SetLines(lines); + vtkSmartPointer polydata = vtkSmartPointer::New(); + polydata->SetPoints(points); + polydata->SetLines(lines); + VtkUtils::FillScalars(polydata, color); vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetColorModeToMapScalars(); - mapper->SetScalarModeToUsePointData(); - VtkUtils::SetInputData(mapper, polyData); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WCloudNormals cv::viz::Widget::cast() @@ -455,3 +443,63 @@ template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast() Widget3D widget = this->cast(); return static_cast(widget); } + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Widget Merger implementation + +cv::viz::WWidgetMerger::WWidgetMerger() +{ + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(append_filter->GetOutputPort()); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); + mapper->SetScalarRange(0, 255); + mapper->ScalarVisibilityOn(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +void cv::viz::WWidgetMerger::addWidget(const Widget3D& widget, const Affine3d &pose) +{ + vtkActor *widget_actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(widget)); + CV_Assert("Widget is not 3D actor." && widget_actor); + + vtkSmartPointer widget_mapper = vtkPolyDataMapper::SafeDownCast(widget_actor->GetMapper()); + CV_Assert("Widget doesn't have a polydata mapper" && widget_mapper); + widget_mapper->Update(); + + vtkSmartPointer actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + vtkSmartPointer producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer(); + vtkSmartPointer append_filter = vtkAppendPolyData::SafeDownCast(producer); + CV_Assert("Correctness check" && append_filter); + + VtkUtils::AddInputData(append_filter, VtkUtils::TransformPolydata(widget_mapper->GetInput(), pose)); +} + +void cv::viz::WWidgetMerger::finalize() +{ + vtkSmartPointer actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + vtkSmartPointer producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer(); + vtkSmartPointer append_filter = vtkAppendPolyData::SafeDownCast(producer); + CV_Assert("Correctness check" && append_filter); + append_filter->Update(); + + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + mapper->RemoveInputConnection(0, 0); + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + mapper->Modified(); +} + +template<> CV_EXPORTS cv::viz::WWidgetMerger cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp index f77da5a5b0..c594962059 100644 --- a/modules/viz/src/precomp.hpp +++ b/modules/viz/src/precomp.hpp @@ -272,6 +272,11 @@ namespace cv return scalars; } + static vtkSmartPointer FillScalars(vtkSmartPointer polydata, const Color& color) + { + return polydata->GetPointData()->SetScalars(FillScalars(polydata->GetNumberOfPoints(), color)), polydata; + } + static vtkSmartPointer ComputeNormals(vtkSmartPointer polydata) { vtkSmartPointer normals_generator = vtkSmartPointer::New(); diff --git a/modules/viz/src/shapes.cpp b/modules/viz/src/shapes.cpp index 171470d812..4dd77038ec 100644 --- a/modules/viz/src/shapes.cpp +++ b/modules/viz/src/shapes.cpp @@ -54,14 +54,16 @@ cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color line->SetPoint2(pt2.x, pt2.y, pt2.z); line->Update(); + vtkSmartPointer polydata = line->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, line->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WLine cv::viz::Widget::cast() @@ -83,14 +85,16 @@ cv::viz::WSphere::WSphere(const Point3d ¢er, double radius, int sphere_resol sphere->LatLongTessellationOff(); sphere->Update(); + vtkSmartPointer polydata = sphere->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, sphere->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WSphere cv::viz::Widget::cast() @@ -110,15 +114,17 @@ cv::viz::WPlane::WPlane(const Size2d& size, const Color &color) plane->SetPoint2(-0.5 * size.width, 0.5 * size.height, 0.0); plane->Update(); + vtkSmartPointer polydata = plane->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, plane->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); actor->GetProperty()->LightingOff(); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color) @@ -161,6 +167,7 @@ cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness Affine3d transform_with_scale(R * length, start_point); vtkSmartPointer polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale); + VtkUtils::FillScalars(polydata, color); vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, polydata); @@ -169,7 +176,6 @@ cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WArrow cv::viz::Widget::cast() @@ -189,16 +195,17 @@ cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color) disk->SetOuterRadius(radius + thickness); disk->Update(); + vtkSmartPointer polydata = disk->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, disk->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->GetProperty()->LightingOff(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); - } cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color) @@ -231,14 +238,16 @@ cv::viz::WCone::WCone(double length, double radius, int resolution, const Color cone_source->SetResolution(resolution); cone_source->Update(); + vtkSmartPointer polydata = cone_source->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, cone_source->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color) @@ -274,14 +283,16 @@ cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_po tuber->SetRadius(radius); tuber->Update(); + vtkSmartPointer polydata = tuber->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, tuber->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WCylinder cv::viz::Widget::cast() @@ -315,15 +326,16 @@ cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool w vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds); } cube->Update(); + vtkSmartPointer polydata =cube->GetOutput(); + VtkUtils::FillScalars(polydata, color); vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, cube->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WCube cv::viz::Widget::cast() @@ -379,40 +391,21 @@ template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast(); - const double *dpoints = _points.getMat().ptr(); - size_t total = _points.total(); - int s_chs = _points.channels(); - - vtkSmartPointer points = vtkSmartPointer::New(); - points->SetDataType(_points.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE); - points->SetNumberOfPoints((vtkIdType)total); + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetColorCloud(points, colors); + cloud_source->Update(); - if (_points.depth() == CV_32F) - for(size_t i = 0; i < total; ++i, fpoints += s_chs) - points->SetPoint((vtkIdType)i, fpoints); - - if (_points.depth() == CV_64F) - for(size_t i = 0; i < total; ++i, dpoints += s_chs) - points->SetPoint((vtkIdType)i, dpoints); + vtkSmartPointer polydata = cloud_source->GetOutput(); vtkSmartPointer cell_array = vtkSmartPointer::New(); - cell_array->Allocate(cell_array->EstimateSize(1, (int)total)); - cell_array->InsertNextCell((int)total); - for(size_t i = 0; i < total; ++i) - cell_array->InsertCellPoint((vtkIdType)i); - - vtkSmartPointer scalars = VtkUtils::FillScalars(total, color); + cell_array->Allocate(cell_array->EstimateSize(1, polydata->GetNumberOfPoints())); + cell_array->InsertNextCell(polydata->GetNumberOfPoints()); + for(vtkIdType i = 0; i < polydata->GetNumberOfPoints(); ++i) + cell_array->InsertCellPoint(i); - vtkSmartPointer polydata = vtkSmartPointer::New(); - polydata->SetPoints(points); polydata->SetLines(cell_array); - polydata->GetPointData()->SetScalars(scalars); - vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, polydata); mapper->SetScalarRange(0, 255); @@ -423,6 +416,12 @@ cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color) WidgetAccessor::setProp(*this, actor); } +cv::viz::WPolyLine::WPolyLine(InputArray points, const Color &color) +{ + WPolyLine polyline(points, Mat(points.size(), CV_8UC3, color)); + *this = polyline; +} + template<> cv::viz::WPolyLine cv::viz::Widget::cast() { Widget3D widget = this->cast(); @@ -450,14 +449,16 @@ cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Colo VtkUtils::SetInputData(extract_edges, grid_data); extract_edges->Update(); + vtkSmartPointer polydata = extract_edges->GetOutput(); + VtkUtils::FillScalars(polydata, color); + vtkSmartPointer mapper = vtkSmartPointer::New(); - VtkUtils::SetInputData(mapper, extract_edges->GetOutput()); + VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color) @@ -807,6 +808,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const double aspect_ratio = f_y / f_x; vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + VtkUtils::FillScalars(polydata, color); vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, polydata); @@ -815,7 +817,6 @@ cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color) @@ -824,6 +825,7 @@ cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const double fovy = fov[1] * 180 / CV_PI; vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + VtkUtils::FillScalars(polydata, color); vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, polydata); @@ -832,7 +834,6 @@ cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color) @@ -967,6 +968,7 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33 source->SetTrajectory(_path); vtkSmartPointer glyph = getPolyData(WCameraPosition(K, scale)); + VtkUtils::FillScalars(glyph, color); vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); tensor_glyph->SetInputConnection(source->GetOutputPort()); @@ -984,7 +986,6 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33 actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color) @@ -993,6 +994,7 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d source->SetTrajectory(_path); vtkSmartPointer glyph = getPolyData(WCameraPosition(fov, scale)); + VtkUtils::FillScalars(glyph, color); vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); tensor_glyph->SetInputConnection(source->GetOutputPort()); @@ -1010,7 +1012,6 @@ cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); - setColor(color); } template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast() diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp index 10c1d81808..d1b059cf67 100644 --- a/modules/viz/test/tests_simple.cpp +++ b/modules/viz/test/tests_simple.cpp @@ -156,6 +156,27 @@ TEST(Viz, show_mesh_random_colors) viz.spin(); } +TEST(Viz, show_widget_merger) +{ + WWidgetMerger merger; + merger.addWidget(WCube(Vec3d::all(0.0), Vec3d::all(1.0), true, Color::gold())); + + RNG& rng = theRNG(); + for(int i = 0; i < 77; ++i) + { + Vec3b c; + rng.fill(c, RNG::NORMAL, Scalar::all(128), Scalar::all(48), true); + merger.addWidget(WSphere(Vec3d(c)*(1.0/255.0), 7.0/255.0, 10, Color(c[2], c[1], c[0]))); + } + merger.finalize(); + + Viz3d viz("show_mesh_random_color"); + viz.showWidget("coo", WCoordinateSystem()); + viz.showWidget("merger", merger); + viz.showWidget("text2d", WText("Widget merger", Point(20, 20), 20, Color::green())); + viz.spin(); +} + TEST(Viz, show_textured_mesh) { Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); @@ -195,12 +216,18 @@ TEST(Viz, show_textured_mesh) TEST(Viz, show_polyline) { - Mat polyline(1, 32, CV_64FC3); + const Color palette[] = { Color::red(), Color::green(), Color::blue(), Color::gold(), Color::raspberry(), Color::bluberry(), Color::lime() }; + size_t palette_size = sizeof(palette)/sizeof(palette[0]); + + Mat polyline(1, 32, CV_64FC3), colors(1, 32, CV_8UC3); for(int i = 0; i < (int)polyline.total(); ++i) + { polyline.at(i) = Vec3d(i/16.0, cos(i * CV_PI/6), sin(i * CV_PI/6)); + colors.at(i) = palette[i & palette_size]; + } Viz3d viz("show_polyline"); - viz.showWidget("polyline", WPolyLine(Mat(polyline), Color::apricot())); + viz.showWidget("polyline", WPolyLine(polyline, colors)); viz.showWidget("coosys", WCoordinateSystem()); viz.showWidget("text2d", WText("Polyline", Point(20, 20), 20, Color::green())); viz.spin();