diff --git a/modules/viz/include/opencv2/viz/viz3d.hpp b/modules/viz/include/opencv2/viz/viz3d.hpp index 65065bc7f..f16d26d42 100644 --- a/modules/viz/include/opencv2/viz/viz3d.hpp +++ b/modules/viz/include/opencv2/viz/viz3d.hpp @@ -26,16 +26,11 @@ namespace temp_viz void setBackgroundColor(const Color& color = Color::black()); - void showPointCloud(const String& id, InputArray cloud, InputArray colors, const Affine3f& pose = Affine3f::Identity()); - void showPointCloud(const String& id, InputArray cloud, const Color& color, const Affine3f& pose = Affine3f::Identity()); - - bool addPointCloudNormals (const Mat &cloud, const Mat& normals, int level = 100, float scale = 0.02f, const String& id = "cloud"); bool addPolygonMesh (const Mesh3d& mesh, const String& id = "polygon"); bool updatePolygonMesh (const Mesh3d& mesh, const String& id = "polygon"); bool addPolylineFromPolygonMesh (const Mesh3d& mesh, const String& id = "polyline"); - bool addText (const String &text, int xpos, int ypos, const Color& color, int fontsize = 10, const String& id = ""); bool addPolygon(const Mat& cloud, const Color& color, const String& id = "polygon"); void spin (); @@ -47,10 +42,11 @@ namespace temp_viz bool wasStopped() const; void showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()); - bool removeWidget(const String &id); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; - bool setWidgetPose(const String &id, const Affine3f &pose); - bool updateWidgetPose(const String &id, const Affine3f &pose); + void setWidgetPose(const String &id, const Affine3f &pose); + void updateWidgetPose(const String &id, const Affine3f &pose); Affine3f getWidgetPose(const String &id) const; private: Viz3d(const Viz3d&); diff --git a/modules/viz/include/opencv2/viz/widget_accessor.hpp b/modules/viz/include/opencv2/viz/widget_accessor.hpp index 0cc39f7ff..a114c3a26 100644 --- a/modules/viz/include/opencv2/viz/widget_accessor.hpp +++ b/modules/viz/include/opencv2/viz/widget_accessor.hpp @@ -2,7 +2,7 @@ #include #include -#include +#include namespace temp_viz { @@ -12,6 +12,7 @@ namespace temp_viz //It is indended for those users who want to develop own widgets system using VTK library API. struct CV_EXPORTS WidgetAccessor { - static vtkSmartPointer getActor(const Widget &widget); + static vtkSmartPointer getProp(const Widget &widget); + static void setProp(Widget &widget, vtkSmartPointer prop); }; } diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index b5b9b65cd..06750238e 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -13,32 +13,48 @@ namespace temp_viz Widget(); Widget(const Widget &other); Widget& operator =(const Widget &other); - - ~Widget(); - void copyTo(Widget &dst); + ~Widget(); - void setColor(const Color &color); + template _W cast(); + private: + class Impl; + Impl *impl_; + friend struct WidgetAccessor; + + void create(); + void release(); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// The base class for all 3D widgets + class CV_EXPORTS Widget3D : public Widget + { + public: + Widget3D() {} + void setPose(const Affine3f &pose); void updatePose(const Affine3f &pose); Affine3f getPose() const; - protected: - Widget(bool text_widget); + void setColor(const Color &color); private: - class Impl; - Impl* impl_; + struct MatrixConverter; - void create(); - void release(); - void create(bool text_widget); - - friend struct WidgetAccessor; }; - - - class CV_EXPORTS LineWidget : public Widget + + ///////////////////////////////////////////////////////////////////////////// + /// The base class for all 2D widgets + class CV_EXPORTS Widget2D : public Widget + { + public: + Widget2D() {} + + void setColor(const Color &color); + }; + + class CV_EXPORTS LineWidget : public Widget3D { public: LineWidget(const Point3f &pt1, const Point3f &pt2, const Color &color = Color::white()); @@ -46,72 +62,119 @@ namespace temp_viz void setLineWidth(float line_width); float getLineWidth(); }; - - class CV_EXPORTS PlaneWidget : public Widget + + class CV_EXPORTS PlaneWidget : public Widget3D { public: PlaneWidget(const Vec4f& coefs, double size = 1.0, const Color &color = Color::white()); PlaneWidget(const Vec4f& coefs, const Point3f& pt, double size = 1.0, const Color &color = Color::white()); }; - class CV_EXPORTS SphereWidget : public Widget + class CV_EXPORTS SphereWidget : public Widget3D { public: SphereWidget(const cv::Point3f ¢er, float radius, int sphere_resolution = 10, const Color &color = Color::white()); }; - class CV_EXPORTS ArrowWidget : public Widget + class CV_EXPORTS ArrowWidget : public Widget3D { public: ArrowWidget(const Point3f& pt1, const Point3f& pt2, const Color &color = Color::white()); }; - class CV_EXPORTS CircleWidget : public Widget + class CV_EXPORTS CircleWidget : public Widget3D { public: CircleWidget(const Point3f& pt, double radius, double thickness = 0.01, const Color &color = Color::white()); }; - class CV_EXPORTS CylinderWidget : public Widget + class CV_EXPORTS CylinderWidget : public Widget3D { public: CylinderWidget(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()); }; - class CV_EXPORTS CubeWidget : public Widget + class CV_EXPORTS CubeWidget : public Widget3D { public: CubeWidget(const Point3f& pt_min, const Point3f& pt_max, bool wire_frame = true, const Color &color = Color::white()); }; - class CV_EXPORTS CoordinateSystemWidget : public Widget + class CV_EXPORTS CoordinateSystemWidget : public Widget3D { public: CoordinateSystemWidget(double scale, const Affine3f& affine); }; - class CV_EXPORTS TextWidget : public Widget + class CV_EXPORTS PolyLineWidget : public Widget3D + { + public: + PolyLineWidget(InputArray _points, const Color &color = Color::white()); + + private: + struct CopyImpl; + }; + + class CV_EXPORTS GridWidget : public Widget3D + { + public: + GridWidget(Vec2i dimensions, Vec2d spacing, const Color &color = Color::white()); + }; + + class CV_EXPORTS Text3DWidget : public Widget3D + { + public: + Text3DWidget(const String &text, const Point3f &position, double text_scale = 1.0, const Color &color = Color::white()); + + void setText(const String &text); + String getText() const; + }; + + class CV_EXPORTS TextWidget : public Widget2D { public: TextWidget(const String &text, const Point2i &pos, int font_size = 10, const Color &color = Color::white()); - // TODO Overload setColor method, and hide setPose, updatePose, getPose methods + void setText(const String &text); + String getText() const; }; - class CV_EXPORTS CloudWidget : public Widget + class CV_EXPORTS CloudWidget : public Widget3D { public: CloudWidget(InputArray _cloud, InputArray _colors); CloudWidget(InputArray _cloud, const Color &color = Color::white()); + private: struct CreateCloudWidget; }; - class CV_EXPORTS CloudNormalsWidget : public Widget + class CV_EXPORTS CloudNormalsWidget : public Widget3D { public: CloudNormalsWidget(InputArray _cloud, InputArray _normals, int level = 100, float scale = 0.02f, const Color &color = Color::white()); + private: struct ApplyCloudNormals; }; + + template<> CV_EXPORTS Widget2D Widget::cast(); + template<> CV_EXPORTS Widget3D Widget::cast(); + template<> CV_EXPORTS LineWidget Widget::cast(); + template<> CV_EXPORTS PlaneWidget Widget::cast(); + template<> CV_EXPORTS SphereWidget Widget::cast(); + template<> CV_EXPORTS CylinderWidget Widget::cast(); + template<> CV_EXPORTS ArrowWidget Widget::cast(); + template<> CV_EXPORTS CircleWidget Widget::cast(); + template<> CV_EXPORTS CubeWidget Widget::cast(); + template<> CV_EXPORTS CoordinateSystemWidget Widget::cast(); + template<> CV_EXPORTS PolyLineWidget Widget::cast(); + template<> CV_EXPORTS GridWidget Widget::cast(); + template<> CV_EXPORTS Text3DWidget Widget::cast(); + template<> CV_EXPORTS TextWidget Widget::cast(); + template<> CV_EXPORTS CloudWidget Widget::cast(); + template<> CV_EXPORTS CloudNormalsWidget Widget::cast(); } + + + diff --git a/modules/viz/src/q/viz3d_impl.hpp b/modules/viz/src/q/viz3d_impl.hpp index 6595416bb..b028812fb 100644 --- a/modules/viz/src/q/viz3d_impl.hpp +++ b/modules/viz/src/q/viz3d_impl.hpp @@ -52,36 +52,15 @@ public: void setBackgroundColor (const Color& color); - bool addText (const String &text, int xpos, int ypos, const Color& color, int fontsize = 10, const String& id = ""); - bool updateText (const String &text, int xpos, int ypos, const Color& color, int fontsize = 10, const String& id = ""); - - /** \brief Set the pose of an existing shape. Returns false if the shape doesn't exist, true if the pose was succesfully updated. */ - bool updateShapePose (const String& id, const Affine3f& pose); - - bool addText3D (const String &text, const Point3f &position, const Color& color, double textScale = 1.0, const String& id = ""); - - bool addPointCloudNormals (const cv::Mat &cloud, const cv::Mat& normals, int level = 100, float scale = 0.02f, const String& id = "cloud"); - - /** \brief If the id exists, updates the point cloud; otherwise, adds a new point cloud to the scene - * \param[in] id a variable to identify the point cloud - * \param[in] cloud cloud input in x,y,z coordinates - * \param[in] colors color input in the same order of the points or single uniform color - * \param[in] pose transform to be applied on the point cloud - */ - void showPointCloud(const String& id, InputArray cloud, InputArray colors, const Affine3f& pose = Affine3f::Identity()); - void showPointCloud(const String& id, InputArray cloud, const Color& color, const Affine3f& pose = Affine3f::Identity()); - bool addPolygonMesh (const Mesh3d& mesh, const cv::Mat& mask, const String& id = "polygon"); bool updatePolygonMesh (const Mesh3d& mesh, const cv::Mat& mask, const String& id = "polygon"); bool addPolylineFromPolygonMesh (const Mesh3d& mesh, const String& id = "polyline"); - void setPointCloudColor (const Color& color, const String& id = "cloud"); bool setPointCloudRenderingProperties (int property, double value, const String& id = "cloud"); bool getPointCloudRenderingProperties (int property, double &value, const String& id = "cloud"); bool setShapeRenderingProperties (int property, double value, const String& id); - void setShapeColor (const Color& color, const String& id); /** \brief Set whether the point cloud is selected or not * \param[in] selected whether the cloud is selected or not (true = selected) @@ -200,10 +179,11 @@ public: void setSize (int xw, int yw); void showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()); - bool removeWidget(const String &id); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; - bool setWidgetPose(const String &id, const Affine3f &pose); - bool updateWidgetPose(const String &id, const Affine3f &pose); + void setWidgetPose(const String &id, const Affine3f &pose); + void updateWidgetPose(const String &id, const Affine3f &pose); Affine3f getWidgetPose(const String &id) const; void all_data(); diff --git a/modules/viz/src/simple_widgets.cpp b/modules/viz/src/simple_widgets.cpp index 640e85c98..49e9f6811 100644 --- a/modules/viz/src/simple_widgets.cpp +++ b/modules/viz/src/simple_widgets.cpp @@ -8,7 +8,7 @@ namespace temp_viz /////////////////////////////////////////////////////////////////////////////////////////////// /// line widget implementation temp_viz::LineWidget::LineWidget(const Point3f &pt1, const Point3f &pt2, const Color &color) -{ +{ vtkSmartPointer line = vtkSmartPointer::New(); line->SetPoint1 (pt1.x, pt1.y, pt1.z); line->SetPoint2 (pt2.x, pt2.y, pt2.z); @@ -17,29 +17,38 @@ temp_viz::LineWidget::LineWidget(const Point3f &pt1, const Point3f &pt2, const C vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(line->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } void temp_viz::LineWidget::setLineWidth(float line_width) { - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); actor->GetProperty()->SetLineWidth(line_width); } float temp_viz::LineWidget::getLineWidth() { - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); return actor->GetProperty()->GetLineWidth(); } +template<> temp_viz::LineWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// plane widget implementation temp_viz::PlaneWidget::PlaneWidget(const Vec4f& coefs, double size, const Color &color) -{ +{ vtkSmartPointer plane = vtkSmartPointer::New (); plane->SetNormal (coefs[0], coefs[1], coefs[2]); double norm = cv::norm(cv::Vec3f(coefs.val)); @@ -48,10 +57,11 @@ temp_viz::PlaneWidget::PlaneWidget(const Vec4f& coefs, double size, const Color vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(plane->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); actor->SetScale(size); + WidgetAccessor::setProp(*this, actor); setColor(color); } @@ -69,13 +79,20 @@ temp_viz::PlaneWidget::PlaneWidget(const Vec4f& coefs, const Point3f& pt, double vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(plane->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); actor->SetScale(size); - + + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::PlaneWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// sphere widget implementation @@ -92,12 +109,19 @@ temp_viz::SphereWidget::SphereWidget(const cv::Point3f ¢er, float radius, in vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(sphere->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::SphereWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// arrow widget implementation @@ -154,12 +178,19 @@ temp_viz::ArrowWidget::ArrowWidget(const Point3f& pt1, const Point3f& pt2, const vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(transformPD->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::ArrowWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// circle widget implementation @@ -183,17 +214,24 @@ temp_viz::CircleWidget::CircleWidget(const temp_viz::Point3f& pt, double radius, vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(tf->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::CircleWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// cylinder widget implementation temp_viz::CylinderWidget::CylinderWidget(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides, const Color &color) -{ +{ const cv::Point3f pt2 = pt_on_axis + axis_direction; vtkSmartPointer line = vtkSmartPointer::New (); line->SetPoint1 (pt_on_axis.x, pt_on_axis.y, pt_on_axis.z); @@ -207,12 +245,19 @@ temp_viz::CylinderWidget::CylinderWidget(const Point3f& pt_on_axis, const Point3 vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(tuber->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New (); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::CylinderWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// cylinder widget implementation @@ -224,15 +269,22 @@ temp_viz::CubeWidget::CubeWidget(const Point3f& pt_min, const Point3f& pt_max, b vtkSmartPointer mapper = vtkSmartPointer::New (); mapper->SetInput(cube->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); if (wire_frame) actor->GetProperty ()->SetRepresentationToWireframe (); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::CubeWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// coordinate system widget implementation @@ -264,7 +316,7 @@ temp_viz::CoordinateSystemWidget::CoordinateSystemWidget(double scale, const Aff mapper->SetScalarModeToUsePointData (); mapper->SetInput(axes_tubes->GetOutput ()); - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); cv::Vec3d t = affine.translation(); @@ -280,14 +332,183 @@ temp_viz::CoordinateSystemWidget::CoordinateSystemWidget(double scale, const Aff actor->SetOrientation(0,0,0); actor->RotateWXYZ(r_angle*180/CV_PI,rvec[0], rvec[1], rvec[2]); + + WidgetAccessor::setProp(*this, actor); +} + +template<> temp_viz::CoordinateSystemWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// polyline widget implementation + +struct temp_viz::PolyLineWidget::CopyImpl +{ + template + static void copy(const Mat& source, Vec<_Tp, 3> *output, vtkSmartPointer polyLine) + { + int s_chs = source.channels(); + + for(int y = 0, id = 0; y < source.rows; ++y) + { + const _Tp* srow = source.ptr<_Tp>(y); + + for(int x = 0; x < source.cols; ++x, srow += s_chs, ++id) + { + *output++ = Vec<_Tp, 3>(srow); + polyLine->GetPointIds()->SetId(id,id); + } + } + } +}; + +temp_viz::PolyLineWidget::PolyLineWidget(InputArray _pointData, const Color &color) +{ + Mat pointData = _pointData.getMat(); + CV_Assert(pointData.type() == CV_32FC3 || pointData.type() == CV_32FC4 || pointData.type() == CV_64FC3 || pointData.type() == CV_64FC4); + vtkIdType nr_points = pointData.total(); + + vtkSmartPointer points = vtkSmartPointer::New (); + vtkSmartPointer polyData = vtkSmartPointer::New (); + vtkSmartPointer polyLine = vtkSmartPointer::New (); + + if (pointData.depth() == CV_32F) + points->SetDataTypeToFloat(); + else + points->SetDataTypeToDouble(); + + points->SetNumberOfPoints(nr_points); + polyLine->GetPointIds()->SetNumberOfIds(nr_points); + + if (pointData.depth() == CV_32F) + { + // Get a pointer to the beginning of the data array + Vec3f *data_beg = vtkpoints_data(points); + CopyImpl::copy(pointData, data_beg, polyLine); + } + else if (pointData.depth() == CV_64F) + { + // Get a pointer to the beginning of the data array + Vec3d *data_beg = vtkpoints_data(points); + CopyImpl::copy(pointData, data_beg, polyLine); + } + + vtkSmartPointer cells = vtkSmartPointer::New(); + cells->InsertNextCell(polyLine); + + polyData->SetPoints(points); + polyData->SetLines(cells); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInput(polyData); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> temp_viz::PolyLineWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// grid widget implementation + +temp_viz::GridWidget::GridWidget(Vec2i dimensions, Vec2d spacing, const Color &color) +{ + // Create the grid using image data + vtkSmartPointer grid = vtkSmartPointer::New(); + + // Add 1 to dimensions because in ImageData dimensions is the number of lines + // - however here it means number of cells + grid->SetDimensions(dimensions[0]+1, dimensions[1]+1, 1); + grid->SetSpacing(spacing[0], spacing[1], 0.); + + // Set origin of the grid to be the middle of the grid + grid->SetOrigin(dimensions[0] * spacing[0] * (-0.5), dimensions[1] * spacing[1] * (-0.5), 0); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInput(grid); + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + // Show it as wireframe + actor->GetProperty ()->SetRepresentationToWireframe (); + WidgetAccessor::setProp(*this, actor); +} + +template<> temp_viz::GridWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// text3D widget implementation + +temp_viz::Text3DWidget::Text3DWidget(const String &text, const Point3f &position, double text_scale, const Color &color) +{ + vtkSmartPointer textSource = vtkSmartPointer::New (); + textSource->SetText (text.c_str()); + textSource->Update (); + + vtkSmartPointer mapper = vtkSmartPointer::New (); + mapper->SetInputConnection (textSource->GetOutputPort ()); + + vtkSmartPointer actor = vtkSmartPointer::New (); + actor->SetMapper (mapper); + actor->SetPosition (position.x, position.y, position.z); + actor->SetScale (text_scale); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +void temp_viz::Text3DWidget::setText(const String &text) +{ + vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + // Update text source + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert(textSource); + + textSource->SetText(text.c_str()); + textSource->Update(); +} + +temp_viz::String temp_viz::Text3DWidget::getText() const +{ + vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert(textSource); + + return textSource->GetText(); +} + +template<> temp_viz::Text3DWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); } /////////////////////////////////////////////////////////////////////////////////////////////// /// text widget implementation -temp_viz::TextWidget::TextWidget(const String &text, const Point2i &pos, int font_size, const Color &color) : Widget(true) +temp_viz::TextWidget::TextWidget(const String &text, const Point2i &pos, int font_size, const Color &color) { - vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetPosition (pos.x, pos.y); actor->SetInput (text.c_str ()); @@ -299,6 +520,28 @@ temp_viz::TextWidget::TextWidget(const String &text, const Point2i &pos, int fon Color c = vtkcolor(color); tprop->SetColor (c.val); + + WidgetAccessor::setProp(*this, actor); +} + +template<> temp_viz::TextWidget temp_viz::Widget::cast() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +void temp_viz::TextWidget::setText(const String &text) +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + actor->SetInput(text.c_str()); +} + +temp_viz::String temp_viz::TextWidget::getText() const +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + return actor->GetInput(); } /////////////////////////////////////////////////////////////////////////////////////////////// @@ -316,8 +559,6 @@ struct temp_viz::CloudWidget::CreateCloudWidget vtkSmartPointer points = polydata->GetPoints(); vtkSmartPointer initcells; nr_points = cloud.total(); - - points = polydata->GetPoints (); if (!points) { @@ -400,7 +641,7 @@ temp_viz::CloudWidget::CloudWidget(InputArray _cloud, InputArray _colors) CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); CV_Assert(colors.type() == CV_8UC3 && cloud.size() == colors.size()); - vtkLODActor * actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); vtkIdType nr_points; vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); @@ -434,6 +675,8 @@ temp_viz::CloudWidget::CloudWidget(InputArray _cloud, InputArray _colors) actor->GetProperty ()->SetInterpolationToFlat (); actor->GetProperty ()->BackfaceCullingOn (); actor->SetMapper (mapper); + + WidgetAccessor::setProp(*this, actor); } temp_viz::CloudWidget::CloudWidget(InputArray _cloud, const Color &color) @@ -441,7 +684,7 @@ temp_viz::CloudWidget::CloudWidget(InputArray _cloud, const Color &color) Mat cloud = _cloud.getMat(); CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); - vtkLODActor * actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); vtkIdType nr_points; vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); @@ -460,9 +703,16 @@ temp_viz::CloudWidget::CloudWidget(InputArray _cloud, const Color &color) actor->GetProperty ()->BackfaceCullingOn (); actor->SetMapper (mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); } +template<> temp_viz::CloudWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + /////////////////////////////////////////////////////////////////////////////////////////////// /// cloud normals widget implementation @@ -550,7 +800,7 @@ temp_viz::CloudNormalsWidget::CloudNormalsWidget(InputArray _cloud, InputArray _ Mat normals = _normals.getMat(); CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type()); - + vtkSmartPointer points = vtkSmartPointer::New(); vtkSmartPointer lines = vtkSmartPointer::New(); vtkIdType nr_normals = 0; @@ -589,7 +839,14 @@ temp_viz::CloudNormalsWidget::CloudNormalsWidget(InputArray _cloud, InputArray _ mapper->SetColorModeToMapScalars(); mapper->SetScalarModeToUsePointData(); - vtkLODActor * actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(*this)); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); + WidgetAccessor::setProp(*this, actor); setColor(color); -} \ No newline at end of file +} + +template<> temp_viz::CloudNormalsWidget temp_viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/viz3d.cpp b/modules/viz/src/viz3d.cpp index ed9405e91..4b9357391 100644 --- a/modules/viz/src/viz3d.cpp +++ b/modules/viz/src/viz3d.cpp @@ -17,21 +17,6 @@ void temp_viz::Viz3d::setBackgroundColor(const Color& color) impl_->setBackgroundColor(color); } -void temp_viz::Viz3d::showPointCloud(const String& id, InputArray cloud, InputArray colors, const Affine3f& pose) -{ - impl_->showPointCloud(id, cloud, colors, pose); -} - -void temp_viz::Viz3d::showPointCloud(const String& id, InputArray cloud, const Color& color, const Affine3f& pose) -{ - impl_->showPointCloud(id, cloud, color, pose); -} - -bool temp_viz::Viz3d::addPointCloudNormals (const Mat &cloud, const Mat& normals, int level, float scale, const String& id) -{ - return impl_->addPointCloudNormals(cloud, normals, level, scale, id); -} - bool temp_viz::Viz3d::addPolygonMesh (const Mesh3d& mesh, const String& id) { return impl_->addPolygonMesh(mesh, Mat(), id); @@ -47,11 +32,6 @@ bool temp_viz::Viz3d::addPolylineFromPolygonMesh (const Mesh3d& mesh, const Stri return impl_->addPolylineFromPolygonMesh(mesh, id); } -bool temp_viz::Viz3d::addText (const String &text, int xpos, int ypos, const Color& color, int fontsize, const String& id) -{ - return impl_->addText(text, xpos, ypos, color, fontsize, id); -} - bool temp_viz::Viz3d::addPolygon(const Mat& cloud, const Color& color, const String& id) { return impl_->addPolygon(cloud, color, id); @@ -84,19 +64,24 @@ void temp_viz::Viz3d::showWidget(const String &id, const Widget &widget, const A impl_->showWidget(id, widget, pose); } -bool temp_viz::Viz3d::removeWidget(const String &id) +void temp_viz::Viz3d::removeWidget(const String &id) { - return impl_->removeWidget(id); + impl_->removeWidget(id); } -bool temp_viz::Viz3d::setWidgetPose(const String &id, const Affine3f &pose) +temp_viz::Widget temp_viz::Viz3d::getWidget(const String &id) const { - return impl_->setWidgetPose(id, pose); + return impl_->getWidget(id); } -bool temp_viz::Viz3d::updateWidgetPose(const String &id, const Affine3f &pose) +void temp_viz::Viz3d::setWidgetPose(const String &id, const Affine3f &pose) { - return impl_->updateWidgetPose(id, pose); + impl_->setWidgetPose(id, pose); +} + +void temp_viz::Viz3d::updateWidgetPose(const String &id, const Affine3f &pose) +{ + impl_->updateWidgetPose(id, pose); } temp_viz::Affine3f temp_viz::Viz3d::getWidgetPose(const String &id) const diff --git a/modules/viz/src/viz3d_impl.cpp b/modules/viz/src/viz3d_impl.cpp index 11982b574..1a1fca699 100644 --- a/modules/viz/src/viz3d_impl.cpp +++ b/modules/viz/src/viz3d_impl.cpp @@ -36,347 +36,6 @@ void temp_viz::Viz3d::VizImpl::setWindowName (const std::string &name) void temp_viz::Viz3d::VizImpl::setPosition (int x, int y) { window_->SetPosition (x, y); } void temp_viz::Viz3d::VizImpl::setSize (int xw, int yw) { window_->SetSize (xw, yw); } -void temp_viz::Viz3d::VizImpl::showPointCloud(const String& id, InputArray _cloud, InputArray _colors, const Affine3f& 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.type() == CV_8UC3 && cloud.size() == colors.size()); - - vtkSmartPointer polydata; - vtkSmartPointer vertices; - vtkSmartPointer points; - vtkSmartPointer initcells; - vtkIdType nr_points = cloud.total(); - - // If the cloud already exists, update otherwise create new one - CloudActorMap::iterator am_it = cloud_actor_map_->find (id); - bool exist = am_it == cloud_actor_map_->end(); - if (exist) - { - // Add as new cloud - allocVtkPolyData(polydata); - //polydata = vtkSmartPointer::New (); - vertices = vtkSmartPointer::New (); - polydata->SetVerts (vertices); - - points = polydata->GetPoints (); - - 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); - } - else - { - // Update the cloud - // Get the current poly data - polydata = reinterpret_cast(am_it->second.actor->GetMapper ())->GetInput (); - vertices = polydata->GetVerts (); - points = polydata->GetPoints (); - // Update the point data type based on the cloud - if (cloud.depth() == CV_32F) - points->SetDataTypeToFloat (); - else if (cloud.depth() == CV_64F) - points->SetDataTypeToDouble (); - - 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); - std::transform(data_beg, data_end, data_beg, ApplyAffine(pose)); - 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); - std::transform(data_beg, data_end, data_beg, ApplyAffine(pose)); - nr_points = data_end - data_beg; - } - - points->SetNumberOfPoints (nr_points); - - vtkSmartPointer cells = vertices->GetData (); - - if (exist) - updateCells (cells, initcells, nr_points); - else - updateCells (cells, am_it->second.cells, nr_points); - - // Set the cells and the vertices - vertices->SetCells (nr_points, cells); - - // Get a random color - Vec3b* colors_data = new Vec3b[nr_points]; - NanFilter::copy(colors, colors_data, cloud); - - vtkSmartPointer scalars = vtkSmartPointer::New (); - scalars->SetNumberOfComponents (3); - scalars->SetNumberOfTuples (nr_points); - scalars->SetArray (colors_data->val, 3 * nr_points, 0); - - // Assign the colors - Vec2d minmax; - polydata->GetPointData ()->SetScalars (scalars); - scalars->GetRange (minmax.val); - - // If this is the new point cloud, a new actor is created - if (exist) - { - vtkSmartPointer actor; - createActorFromVTKDataSet (polydata, actor); - - actor->GetMapper ()->SetScalarRange (minmax.val); - - // Add it to all renderers - renderer_->AddActor (actor); - - // Save the pointer/ID pair to the global actor map - (*cloud_actor_map_)[id].actor = actor; - (*cloud_actor_map_)[id].cells = initcells; - - const Eigen::Vector4f sensor_origin = Eigen::Vector4f::Zero (); - const Eigen::Quaternionf sensor_orientation = Eigen::Quaternionf::Identity (); - - // Save the viewpoint transformation matrix to the global actor map - vtkSmartPointer transformation = vtkSmartPointer::New(); - convertToVtkMatrix (sensor_origin, sensor_orientation, transformation); - - (*cloud_actor_map_)[id].viewpoint_transformation_ = transformation; - } - else - { - // Update the mapper - reinterpret_cast(am_it->second.actor->GetMapper ())->SetInput (polydata); - am_it->second.actor->GetMapper ()->ScalarVisibilityOn(); - am_it->second.actor->Modified (); - } -} - -void temp_viz::Viz3d::VizImpl::showPointCloud(const String& id, InputArray _cloud, const Color& color, const Affine3f& pose) -{ - Mat cloud = _cloud.getMat(); - CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); - - vtkSmartPointer polydata; - vtkSmartPointer vertices; - vtkSmartPointer points; - vtkSmartPointer initcells; - vtkIdType nr_points = cloud.total(); - - // If the cloud already exists, update otherwise create new one - CloudActorMap::iterator am_it = cloud_actor_map_->find (id); - bool exist = am_it == cloud_actor_map_->end(); - if (exist) - { - // Add as new cloud - allocVtkPolyData(polydata); - //polydata = vtkSmartPointer::New (); - vertices = vtkSmartPointer::New (); - polydata->SetVerts (vertices); - - points = polydata->GetPoints (); - - 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); - } - else - { - // Update the cloud - // Get the current poly data - polydata = reinterpret_cast(am_it->second.actor->GetMapper ())->GetInput (); - vertices = polydata->GetVerts (); - points = polydata->GetPoints (); - // Update the point data type based on the cloud - if (cloud.depth() == CV_32F) - points->SetDataTypeToFloat (); - else if (cloud.depth() == CV_64F) - points->SetDataTypeToDouble (); - - 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); - std::transform(data_beg, data_end, data_beg, ApplyAffine(pose)); - 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); - std::transform(data_beg, data_end, data_beg, ApplyAffine(pose)); - nr_points = data_end - data_beg; - } - - points->SetNumberOfPoints (nr_points); - - vtkSmartPointer cells = vertices->GetData (); - - if (exist) - updateCells (cells, initcells, nr_points); - else - updateCells (cells, am_it->second.cells, nr_points); - - // Set the cells and the vertices - vertices->SetCells (nr_points, cells); - - // Get a random color - Color c = vtkcolor(color); - polydata->GetPointData ()->SetScalars (0); - - // If this is the new point cloud, a new actor is created - if (exist) - { - vtkSmartPointer actor; - createActorFromVTKDataSet (polydata, actor, false); - - actor->GetProperty ()->SetColor(c.val); - - // Add it to all renderers - renderer_->AddActor (actor); - - // Save the pointer/ID pair to the global actor map - (*cloud_actor_map_)[id].actor = actor; - (*cloud_actor_map_)[id].cells = initcells; - - const Eigen::Vector4f sensor_origin = Eigen::Vector4f::Zero (); - const Eigen::Quaternionf sensor_orientation = Eigen::Quaternionf::Identity (); - - // Save the viewpoint transformation matrix to the global actor map - vtkSmartPointer transformation = vtkSmartPointer::New(); - convertToVtkMatrix (sensor_origin, sensor_orientation, transformation); - - (*cloud_actor_map_)[id].viewpoint_transformation_ = transformation; - } - else - { - // Update the mapper - reinterpret_cast(am_it->second.actor->GetMapper ())->SetInput (polydata); - am_it->second.actor->GetProperty ()->SetColor(c.val); - am_it->second.actor->GetMapper ()->ScalarVisibilityOff(); - am_it->second.actor->Modified (); - } -} - -bool temp_viz::Viz3d::VizImpl::addPointCloudNormals (const cv::Mat &cloud, const cv::Mat& normals, int level, float scale, const std::string &id) -{ - CV_Assert(cloud.size() == normals.size() && cloud.type() == CV_32FC3 && normals.type() == CV_32FC3); - - if (cloud_actor_map_->find (id) != cloud_actor_map_->end ()) - return false; - - vtkSmartPointer points = vtkSmartPointer::New(); - vtkSmartPointer lines = vtkSmartPointer::New(); - - points->SetDataTypeToFloat (); - vtkSmartPointer data = vtkSmartPointer::New (); - data->SetNumberOfComponents (3); - - vtkIdType nr_normals = 0; - float* pts = 0; - - // If the cloud is organized, then distribute the normal step in both directions - if (cloud.cols > 1 && cloud.rows > 1) - { - vtkIdType point_step = static_cast (sqrt (double (level))); - nr_normals = (static_cast ((cloud.cols - 1)/ point_step) + 1) * - (static_cast ((cloud.rows - 1) / point_step) + 1); - pts = new float[2 * nr_normals * 3]; - - vtkIdType cell_count = 0; - for (vtkIdType y = 0; y < cloud.rows; y += point_step) - for (vtkIdType x = 0; x < cloud.cols; x += point_step) - { - cv::Point3f p = cloud.at(y, x); - cv::Point3f n = normals.at(y, x) * scale; - - pts[2 * cell_count * 3 + 0] = p.x; - pts[2 * cell_count * 3 + 1] = p.y; - pts[2 * cell_count * 3 + 2] = p.z; - pts[2 * cell_count * 3 + 3] = p.x + n.x; - pts[2 * cell_count * 3 + 4] = p.y + n.y; - pts[2 * cell_count * 3 + 5] = p.z + n.z; - - lines->InsertNextCell (2); - lines->InsertCellPoint (2 * cell_count); - lines->InsertCellPoint (2 * cell_count + 1); - cell_count++; - } - } - else - { - nr_normals = (cloud.size().area() - 1) / level + 1 ; - pts = new float[2 * nr_normals * 3]; - - for (vtkIdType i = 0, j = 0; j < nr_normals; j++, i = j * level) - { - cv::Point3f p = cloud.ptr()[i]; - cv::Point3f n = normals.ptr()[i] * scale; - - pts[2 * j * 3 + 0] = p.x; - pts[2 * j * 3 + 1] = p.y; - pts[2 * j * 3 + 2] = p.z; - pts[2 * j * 3 + 3] = p.x + n.x; - pts[2 * j * 3 + 4] = p.y + n.y; - pts[2 * j * 3 + 5] = p.z + n.z; - - lines->InsertNextCell (2); - lines->InsertCellPoint (2 * j); - lines->InsertCellPoint (2 * j + 1); - } - } - - data->SetArray (&pts[0], 2 * nr_normals * 3, 0); - points->SetData (data); - - vtkSmartPointer polyData = vtkSmartPointer::New(); - polyData->SetPoints (points); - polyData->SetLines (lines); - - vtkSmartPointer mapper = vtkSmartPointer::New (); - mapper->SetInput (polyData); - mapper->SetColorModeToMapScalars(); - mapper->SetScalarModeToUsePointData(); - - // create actor - vtkSmartPointer actor = vtkSmartPointer::New (); - actor->SetMapper (mapper); - - // Add it to all renderers - renderer_->AddActor (actor); - - // Save the pointer/ID pair to the global actor map - (*cloud_actor_map_)[id].actor = actor; - return (true); -} - bool temp_viz::Viz3d::VizImpl::addPolygonMesh (const Mesh3d& mesh, const Mat& mask, const std::string &id) { CV_Assert(mesh.cloud.type() == CV_32FC3 && mesh.cloud.rows == 1 && !mesh.polygons.empty ()); @@ -742,50 +401,6 @@ bool temp_viz::Viz3d::VizImpl::addArrow (const cv::Point3f &p1, const cv::Point3 return (true); } -////////////////////////////////////////////////// -bool temp_viz::Viz3d::VizImpl::addText3D (const std::string &text, const cv::Point3f& position, const Color& color, double textScale, const std::string &id) -{ - std::string tid; - if (id.empty ()) - tid = text; - else - tid = id; - - // Check to see if this ID entry already exists (has it been already added to the visualizer?) - ShapeActorMap::iterator am_it = shape_actor_map_->find (tid); - if (am_it != shape_actor_map_->end ()) - return std::cout << "[addText3d] A text with id <" << tid << "> already exists! Please choose a different id and retry." << std::endl, false; - - vtkSmartPointer textSource = vtkSmartPointer::New (); - textSource->SetText (text.c_str()); - textSource->Update (); - - vtkSmartPointer textMapper = vtkSmartPointer::New (); - textMapper->SetInputConnection (textSource->GetOutputPort ()); - - // Since each follower may follow a different camera, we need different followers - vtkRenderer* renderer = renderer_; - - vtkSmartPointer textActor = vtkSmartPointer::New (); - textActor->SetMapper (textMapper); - textActor->SetPosition (position.x, position.y, position.z); - textActor->SetScale (textScale); - - Color c = vtkcolor(color); - textActor->GetProperty ()->SetColor (c.val); - textActor->SetCamera (renderer->GetActiveCamera ()); - - renderer->AddActor (textActor); - renderer->Render (); - - // Save the pointer/ID pair to the global actor map. If we are saving multiple vtkFollowers - // for multiple viewport - (*shape_actor_map_)[tid] = textActor; - - - return (true); -} - bool temp_viz::Viz3d::VizImpl::addPolygon (const cv::Mat& cloud, const Color& color, const std::string &id) { CV_Assert(cloud.type() == CV_32FC3 && cloud.rows == 1); @@ -874,72 +489,80 @@ void temp_viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget removeActorFromRenderer(wam_itr->second.actor); } // Get the actor and set the user matrix - vtkLODActor *actor; - if (actor = vtkLODActor::SafeDownCast(WidgetAccessor::getActor(widget))) + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(widget)); + if (actor) { + // If the actor is 3D, apply pose vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); actor->SetUserMatrix (matrix); actor->Modified(); } - renderer_->AddActor(WidgetAccessor::getActor(widget)); - (*widget_actor_map_)[id].actor = WidgetAccessor::getActor(widget); + // If the actor is a vtkFollower, then it should always face the camera + vtkFollower *follower = vtkFollower::SafeDownCast(actor); + if (follower) + { + follower->SetCamera(renderer_->GetActiveCamera()); + } + + renderer_->AddActor(WidgetAccessor::getProp(widget)); + (*widget_actor_map_)[id].actor = WidgetAccessor::getProp(widget); } -bool temp_viz::Viz3d::VizImpl::removeWidget(const String &id) +void temp_viz::Viz3d::VizImpl::removeWidget(const String &id) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); CV_Assert(exists); - - if (!removeActorFromRenderer (wam_itr->second.actor)) - return false; - + CV_Assert(removeActorFromRenderer (wam_itr->second.actor)); widget_actor_map_->erase(wam_itr); - return true; } -bool temp_viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3f &pose) +temp_viz::Widget temp_viz::Viz3d::VizImpl::getWidget(const String &id) const +{ + WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id); + bool exists = wam_itr != widget_actor_map_->end(); + CV_Assert(exists); + + Widget widget; + WidgetAccessor::setProp(widget, wam_itr->second.actor); + return widget; +} + +void temp_viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3f &pose) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); CV_Assert(exists); - vtkLODActor *actor; - if ((actor = vtkLODActor::SafeDownCast(wam_itr->second.actor))) - { - vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); - actor->SetUserMatrix (matrix); - actor->Modified (); - return true; - } - return false; + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second.actor); + CV_Assert(actor); + + vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); + actor->SetUserMatrix (matrix); + actor->Modified (); } -bool temp_viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3f &pose) +void temp_viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3f &pose) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); CV_Assert(exists); - vtkLODActor *actor; - if ((actor = vtkLODActor::SafeDownCast(wam_itr->second.actor))) + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second.actor); + CV_Assert(actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + if (!matrix) { - vtkSmartPointer matrix = actor->GetUserMatrix(); - if (!matrix) - { - setWidgetPose(id, pose); - return true; - } - Matx44f matrix_cv = convertToMatx(matrix); - - Affine3f updated_pose = pose * Affine3f(matrix_cv); - matrix = convertToVtkMatrix(updated_pose.matrix); - - actor->SetUserMatrix (matrix); - actor->Modified (); - return true; + setWidgetPose(id, pose); + return ; } - return false; + Matx44f matrix_cv = convertToMatx(matrix); + Affine3f updated_pose = pose * Affine3f(matrix_cv); + matrix = convertToVtkMatrix(updated_pose.matrix); + + actor->SetUserMatrix (matrix); + actor->Modified (); } temp_viz::Affine3f temp_viz::Viz3d::VizImpl::getWidgetPose(const String &id) const @@ -948,12 +571,10 @@ temp_viz::Affine3f temp_viz::Viz3d::VizImpl::getWidgetPose(const String &id) con bool exists = wam_itr != widget_actor_map_->end(); CV_Assert(exists); - vtkLODActor *actor; - if ((actor = vtkLODActor::SafeDownCast(wam_itr->second.actor))) - { - vtkSmartPointer matrix = actor->GetUserMatrix(); - Matx44f matrix_cv = convertToMatx(matrix); - return Affine3f(matrix_cv); - } - return Affine3f(); + vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second.actor); + CV_Assert(actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + Matx44f matrix_cv = convertToMatx(matrix); + return Affine3f(matrix_cv); } \ No newline at end of file diff --git a/modules/viz/src/viz_main.cpp b/modules/viz/src/viz_main.cpp index 0d56fe0a5..442a5ff8e 100644 --- a/modules/viz/src/viz_main.cpp +++ b/modules/viz/src/viz_main.cpp @@ -350,21 +350,6 @@ void temp_viz::Viz3d::VizImpl::setBackgroundColor (const Color& color) renderer_->SetBackground (c.val); } -///////////////////////////////////////////////////////////////////////////////////////////// -void temp_viz::Viz3d::VizImpl::setPointCloudColor (const Color& color, const std::string &id) -{ - CloudActorMap::iterator am_it = cloud_actor_map_->find (id); - if (am_it != cloud_actor_map_->end ()) - { - vtkLODActor* actor = vtkLODActor::SafeDownCast (am_it->second.actor); - - Color c = vtkcolor(color); - actor->GetProperty ()->SetColor (c.val); - actor->GetMapper ()->ScalarVisibilityOff (); - actor->Modified (); - } -} - ///////////////////////////////////////////////////////////////////////////////////////////// bool temp_viz::Viz3d::VizImpl::getPointCloudRenderingProperties (int property, double &value, const std::string &id) { @@ -470,26 +455,6 @@ bool temp_viz::Viz3d::VizImpl::setPointCloudSelected (const bool selected, const return true; } -///////////////////////////////////////////////////////////////////////////////////////////// -void temp_viz::Viz3d::VizImpl::setShapeColor (const Color& color, const std::string &id) -{ - ShapeActorMap::iterator am_it = shape_actor_map_->find (id); - if (am_it != shape_actor_map_->end ()) - { - vtkActor* actor = vtkActor::SafeDownCast (am_it->second); - - Color c = vtkcolor(color); - actor->GetMapper ()->ScalarVisibilityOff (); - actor->GetProperty ()->SetColor (c.val); - actor->GetProperty ()->SetEdgeColor (c.val); - actor->GetProperty ()->SetAmbient (0.8); - actor->GetProperty ()->SetDiffuse (0.8); - actor->GetProperty ()->SetSpecular (0.8); - actor->GetProperty ()->SetLighting (0); - actor->Modified (); - } -} - ///////////////////////////////////////////////////////////////////////////////////////////// bool temp_viz::Viz3d::VizImpl::setShapeRenderingProperties (int property, double value, const std::string &id) { @@ -618,28 +583,6 @@ void temp_viz::Viz3d::VizImpl::updateCamera () renderer_->Render (); } -///////////////////////////////////////////////////////////////////////////////////////////// -bool temp_viz::Viz3d::VizImpl::updateShapePose (const std::string &id, const cv::Affine3f& pose) -{ - ShapeActorMap::iterator am_it = shape_actor_map_->find (id); - - vtkLODActor* actor; - - if (am_it == shape_actor_map_->end ()) - return (false); - else - actor = vtkLODActor::SafeDownCast (am_it->second); - - vtkSmartPointer matrix = vtkSmartPointer::New (); - - convertToVtkMatrix (pose.matrix, matrix); - - actor->SetUserMatrix (matrix); - actor->Modified (); - - return (true); -} - ///////////////////////////////////////////////////////////////////////////////////////////// void temp_viz::Viz3d::VizImpl::getCameras (temp_viz::Camera& camera) { @@ -916,62 +859,6 @@ bool temp_viz::Viz3d::VizImpl::addModelFromPLYFile (const std::string &filename, return (true); } -///////////////////////////////////////////////////////////////////////////////////////////// -bool temp_viz::Viz3d::VizImpl::addText (const std::string &text, int xpos, int ypos, const Color& color, int fontsize, const std::string &id) -{ - std::string tid = id.empty() ? text : id; - - // Check to see if this ID entry already exists (has it been already added to the visualizer?) - ShapeActorMap::iterator am_it = shape_actor_map_->find (tid); - if (am_it != shape_actor_map_->end ()) - return std::cout << "[addText] A text with id <"< already exists! Please choose a different id and retry.\n" << std::endl, false; - - // Create an Actor - vtkSmartPointer actor = vtkSmartPointer::New (); - actor->SetPosition (xpos, ypos); - actor->SetInput (text.c_str ()); - - vtkSmartPointer tprop = actor->GetTextProperty (); - tprop->SetFontSize (fontsize); - tprop->SetFontFamilyToArial (); - tprop->SetJustificationToLeft (); - tprop->BoldOn (); - - Color c = vtkcolor(color); - tprop->SetColor (c.val); - renderer_->AddActor(actor); - - // Save the pointer/ID pair to the global actor map - (*shape_actor_map_)[tid] = actor; - return (true); -} - -////////////////////////////////////////////////////////////////////////////////////////// -bool temp_viz::Viz3d::VizImpl::updateText (const std::string &text, int xpos, int ypos, const Color& color, int fontsize, const std::string &id) -{ - std::string tid = id.empty() ? text : id; - - ShapeActorMap::iterator am_it = shape_actor_map_->find (tid); - if (am_it == shape_actor_map_->end ()) - return false; - - // Retrieve the Actor - vtkTextActor *actor = vtkTextActor::SafeDownCast (am_it->second); - - actor->SetPosition (xpos, ypos); - actor->SetInput (text.c_str ()); - - vtkTextProperty* tprop = actor->GetTextProperty (); - tprop->SetFontSize (fontsize); - - Color c = vtkcolor(color); - tprop->SetColor (c.val); - - actor->Modified (); - - return (true); -} - bool temp_viz::Viz3d::VizImpl::addPolylineFromPolygonMesh (const Mesh3d& mesh, const std::string &id) { CV_Assert(mesh.cloud.rows == 1 && mesh.cloud.type() == CV_32FC3); diff --git a/modules/viz/src/widget.cpp b/modules/viz/src/widget.cpp index f75827f8f..7978d7a5b 100644 --- a/modules/viz/src/widget.cpp +++ b/modules/viz/src/widget.cpp @@ -1,126 +1,34 @@ #include "precomp.hpp" +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget implementation + class temp_viz::Widget::Impl { public: - vtkSmartPointer actor; + vtkSmartPointer prop; int ref_counter; - - Impl() : actor(vtkSmartPointer::New()) {} - Impl(bool text_widget) - { - if (text_widget) - actor = vtkSmartPointer::New(); - else - actor = vtkSmartPointer::New(); - } - - void setColor(const Color& color) - { - vtkLODActor *lod_actor = vtkLODActor::SafeDownCast(actor); - Color c = vtkcolor(color); - lod_actor->GetMapper ()->ScalarVisibilityOff (); - lod_actor->GetProperty ()->SetColor (c.val); - lod_actor->GetProperty ()->SetEdgeColor (c.val); - lod_actor->GetProperty ()->SetAmbient (0.8); - lod_actor->GetProperty ()->SetDiffuse (0.8); - lod_actor->GetProperty ()->SetSpecular (0.8); - lod_actor->GetProperty ()->SetLighting (0); - lod_actor->Modified (); - } - - void setPose(const Affine3f& pose) - { - vtkLODActor *lod_actor = vtkLODActor::SafeDownCast(actor); - vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); - lod_actor->SetUserMatrix (matrix); - lod_actor->Modified (); - } - - void updatePose(const Affine3f& pose) - { - vtkLODActor *lod_actor = vtkLODActor::SafeDownCast(actor); - vtkSmartPointer matrix = lod_actor->GetUserMatrix(); - if (!matrix) - { - setPose(pose); - return ; - } - Matx44f matrix_cv = convertToMatx(matrix); - - Affine3f updated_pose = pose * Affine3f(matrix_cv); - matrix = convertToVtkMatrix(updated_pose.matrix); - - lod_actor->SetUserMatrix (matrix); - lod_actor->Modified (); - } - - Affine3f getPose() const - { - vtkLODActor *lod_actor = vtkLODActor::SafeDownCast(actor); - vtkSmartPointer matrix = lod_actor->GetUserMatrix(); - Matx44f matrix_cv = convertToMatx(matrix); - return Affine3f(matrix_cv); - } - -protected: - - static vtkSmartPointer convertToVtkMatrix (const cv::Matx44f& m) - { - vtkSmartPointer vtk_matrix = vtkSmartPointer::New (); - for (int i = 0; i < 4; i++) - for (int k = 0; k < 4; k++) - vtk_matrix->SetElement(i, k, m(i, k)); - return vtk_matrix; - } - - static cv::Matx44f convertToMatx(const vtkSmartPointer& vtk_matrix) - { - cv::Matx44f m; - for (int i = 0; i < 4; i++) - for (int k = 0; k < 4; k++) - m(i, k) = vtk_matrix->GetElement (i, k); - return m; - } + Impl() : prop(0) {} }; - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// stream accessor implementaion - -vtkSmartPointer temp_viz::WidgetAccessor::getActor(const Widget& widget) -{ - return widget.impl_->actor; -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// widget implementaion - temp_viz::Widget::Widget() : impl_(0) { create(); } -temp_viz::Widget::Widget(bool text_widget) : impl_(0) +temp_viz::Widget::Widget(const Widget &other) : impl_(other.impl_) { - create(text_widget); + if (impl_) CV_XADD(&impl_->ref_counter, 1); } -temp_viz::Widget::Widget(const Widget& other) : impl_(other.impl_) -{ - if (impl_) - CV_XADD(&impl_->ref_counter, 1); -} - -temp_viz::Widget& temp_viz::Widget::operator =(const Widget &other) +temp_viz::Widget& temp_viz::Widget::operator=(const Widget &other) { if (this != &other) { release(); impl_ = other.impl_; - if (impl_) - CV_XADD(&impl_->ref_counter, 1); + if (impl_) CV_XADD(&impl_->ref_counter, 1); } return *this; } @@ -130,20 +38,9 @@ temp_viz::Widget::~Widget() release(); } -void temp_viz::Widget::copyTo(Widget& /*dst*/) -{ - // TODO Deep copy the data if there is any -} - -void temp_viz::Widget::setColor(const Color& color) { impl_->setColor(color); } -void temp_viz::Widget::setPose(const Affine3f& pose) { impl_->setPose(pose); } -void temp_viz::Widget::updatePose(const Affine3f& pose) { impl_->updatePose(pose); } -temp_viz::Affine3f temp_viz::Widget::getPose() const { return impl_->getPose(); } - void temp_viz::Widget::create() { - if (impl_) - release(); + if (impl_) release(); impl_ = new Impl(); impl_->ref_counter = 1; } @@ -157,11 +54,128 @@ void temp_viz::Widget::release() } } -void temp_viz::Widget::create(bool text_widget) +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget accessor implementaion + +vtkSmartPointer temp_viz::WidgetAccessor::getProp(const Widget& widget) { - if (impl_) - release(); - impl_ = new Impl(text_widget); - impl_->ref_counter = 1; + return widget.impl_->prop; } +void temp_viz::WidgetAccessor::setProp(Widget& widget, vtkSmartPointer prop) +{ + widget.impl_->prop = prop; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget3D implementation + +struct temp_viz::Widget3D::MatrixConverter +{ + static cv::Matx44f convertToMatx(const vtkSmartPointer& vtk_matrix) + { + cv::Matx44f m; + for (int i = 0; i < 4; i++) + for (int k = 0; k < 4; k++) + m(i, k) = vtk_matrix->GetElement (i, k); + return m; + } + + static vtkSmartPointer convertToVtkMatrix (const cv::Matx44f& m) + { + vtkSmartPointer vtk_matrix = vtkSmartPointer::New (); + for (int i = 0; i < 4; i++) + for (int k = 0; k < 4; k++) + vtk_matrix->SetElement(i, k, m(i, k)); + return vtk_matrix; + } +}; + +void temp_viz::Widget3D::setPose(const Affine3f &pose) +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); + actor->SetUserMatrix (matrix); + actor->Modified (); +} + +void temp_viz::Widget3D::updatePose(const Affine3f &pose) +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + if (!matrix) + { + setPose(pose); + return ; + } + Matx44f matrix_cv = MatrixConverter::convertToMatx(matrix); + + Affine3f updated_pose = pose * Affine3f(matrix_cv); + matrix = MatrixConverter::convertToVtkMatrix(updated_pose.matrix); + + actor->SetUserMatrix (matrix); + actor->Modified (); +} + +temp_viz::Affine3f temp_viz::Widget3D::getPose() const +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + vtkSmartPointer matrix = actor->GetUserMatrix(); + Matx44f matrix_cv = MatrixConverter::convertToMatx(matrix); + return Affine3f(matrix_cv); +} + +void temp_viz::Widget3D::setColor(const Color &color) +{ + // Cast to actor instead of prop3d since prop3d doesn't provide getproperty + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + Color c = vtkcolor(color); + actor->GetMapper ()->ScalarVisibilityOff (); + actor->GetProperty ()->SetColor (c.val); + actor->GetProperty ()->SetEdgeColor (c.val); + actor->GetProperty ()->SetAmbient (0.8); + actor->GetProperty ()->SetDiffuse (0.8); + actor->GetProperty ()->SetSpecular (0.8); + actor->GetProperty ()->SetLighting (0); + actor->Modified (); +} + +template<> temp_viz::Widget3D temp_viz::Widget::cast() +{ + vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + Widget3D widget; + WidgetAccessor::setProp(widget, actor); + return widget; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// widget2D implementation + +void temp_viz::Widget2D::setColor(const Color &color) +{ + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + Color c = vtkcolor(color); + actor->GetProperty ()->SetColor (c.val); + actor->Modified (); +} + +template<> temp_viz::Widget2D temp_viz::Widget::cast() +{ + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert(actor); + + Widget2D widget; + WidgetAccessor::setProp(widget, actor); + return widget; +} diff --git a/modules/viz/test/test_viz3d.cpp b/modules/viz/test/test_viz3d.cpp index 76993d160..090501eb5 100644 --- a/modules/viz/test/test_viz3d.cpp +++ b/modules/viz/test/test_viz3d.cpp @@ -112,16 +112,40 @@ TEST(Viz_viz3d, accuracy) v.showWidget("coordinateSystem", csw); // v.showWidget("text",tw); // v.showWidget("pcw",pcw); - v.showWidget("pcw2",pcw2); +// v.showWidget("pcw2",pcw2); - temp_viz::LineWidget lw2 = lw; +// temp_viz::LineWidget lw2 = lw; // v.showPointCloud("cld",cloud, colors); cv::Mat normals(cloud.size(), cloud.type(), cv::Scalar(0, 10, 0)); // v.addPointCloudNormals(cloud, normals, 100, 0.02, "n"); temp_viz::CloudNormalsWidget cnw(cloud, normals); - v.showWidget("n", cnw); +// v.showWidget("n", cnw); + +// lw = v.getWidget("n").cast(); +// pw = v.getWidget("n").cast(); + + cv::Mat points(1, 4, CV_64FC4); + + cv::Vec4d* data = points.ptr(); + data[0] = cv::Vec4d(0.0,0.0,0.0,0.0); + data[1] = cv::Vec4d(1.0,1.0,1.0,1.0); + data[2] = cv::Vec4d(0.0,2.0,0.0,0.0); + data[3] = cv::Vec4d(3.0,4.0,1.0,1.0); + points = points.reshape(0, 2); + + temp_viz::PolyLineWidget plw(points); +// v.showWidget("polyline",plw); +// lw = v.getWidget("polyline").cast(); + + temp_viz::GridWidget gw(temp_viz::Vec2i(10,10), temp_viz::Vec2d(0.1,0.1)); + v.showWidget("grid", gw); + lw = v.getWidget("grid").cast(); + + temp_viz::Text3DWidget t3w("OpenCV", cv::Point3f(0.0, 2.0, 0.0), 1.0, temp_viz::Color(255,255,0)); + v.showWidget("txt3d", t3w); +// float grid_x_angle = 0.0; while(!v.wasStopped()) { @@ -129,28 +153,30 @@ TEST(Viz_viz3d, accuracy) cv::Affine3f cloudPosition(angle_x, angle_y, angle_z, cv::Vec3f(pos_x, pos_y, pos_z)); cv::Affine3f cloudPosition2(angle_x, angle_y, angle_z, cv::Vec3f(pos_x+0.2, pos_y+0.2, pos_z+0.2)); - lw2.setColor(temp_viz::Color(col_blue, col_green, col_red)); - lw.setLineWidth(lw.getLineWidth()+pos_x * 10); + lw.setColor(temp_viz::Color(col_blue, col_green, col_red)); +// lw.setLineWidth(pos_x * 10); - pw.setColor(temp_viz::Color(col_blue, col_green, col_red)); + plw.setColor(temp_viz::Color(col_blue, col_green, col_red)); sw.setPose(cloudPosition); // pw.setPose(cloudPosition); aw.setPose(cloudPosition); cw.setPose(cloudPosition); cyw.setPose(cloudPosition); - lw.setPose(cloudPosition); +// lw.setPose(cloudPosition); cuw.setPose(cloudPosition); // cnw.setPose(cloudPosition); // v.showWidget("pcw",pcw, cloudPosition); // v.showWidget("pcw2",pcw2, cloudPosition2); // v.showWidget("plane", pw, cloudPosition); - v.setWidgetPose("n",cloudPosition); - v.setWidgetPose("pcw2", cloudPosition); +// v.setWidgetPose("n",cloudPosition); +// v.setWidgetPose("pcw2", cloudPosition); cnw.setColor(temp_viz::Color(col_blue, col_green, col_red)); pcw2.setColor(temp_viz::Color(col_blue, col_green, col_red)); + gw.updatePose(temp_viz::Affine3f(0.0, 0.1, 0.0, cv::Vec3f(0.0,0.0,0.0))); + angle_x += 0.1f; angle_y -= 0.1f; angle_z += 0.1f;