diff --git a/CMakeLists.txt b/CMakeLists.txt index 171046774..7f9b1de9e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -116,7 +116,7 @@ endif() OCV_OPTION(WITH_1394 "Include IEEE1394 support" ON IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_AVFOUNDATION "Use AVFoundation for Video I/O" ON IF IOS) OCV_OPTION(WITH_CARBON "Use Carbon for UI instead of Cocoa" OFF IF APPLE ) -OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" OFF IF (NOT ANDROID AND NOT IOS) ) +OCV_OPTION(WITH_VTK "Include VTK library support (and build opencv_viz module eiher)" ON IF (NOT ANDROID AND NOT IOS) ) OCV_OPTION(WITH_CUDA "Include NVidia Cuda Runtime support" ON IF (NOT IOS) ) OCV_OPTION(WITH_CUFFT "Include NVidia Cuda Fast Fourier Transform (FFT) library support" ON IF (NOT IOS) ) OCV_OPTION(WITH_CUBLAS "Include NVidia Cuda Basic Linear Algebra Subprograms (BLAS) library support" OFF IF (NOT IOS) ) diff --git a/cmake/OpenCVDetectVTK.cmake b/cmake/OpenCVDetectVTK.cmake index f0d28d552..ef9aa8043 100644 --- a/cmake/OpenCVDetectVTK.cmake +++ b/cmake/OpenCVDetectVTK.cmake @@ -2,7 +2,7 @@ if(NOT WITH_VTK OR ANDROID OR IOS) return() endif() -find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture NO_MODULE) +find_package(VTK 6.0 QUIET COMPONENTS vtkRenderingCore vtkInteractionWidgets vtkInteractionStyle vtkIOLegacy vtkIOPLY vtkRenderingFreeType vtkRenderingLOD vtkFiltersTexture vtkIOExport NO_MODULE) if(NOT DEFINED VTK_FOUND OR NOT VTK_FOUND) find_package(VTK 5.10 QUIET COMPONENTS vtkCommon vtkFiltering vtkRendering vtkWidgets vtkImaging NO_MODULE) @@ -18,4 +18,4 @@ if(VTK_FOUND) else() set(HAVE_VTK OFF) message(STATUS "VTK is not found. Please set -DVTK_DIR in CMake to VTK build directory, or set $VTK_DIR enviroment variable to VTK install subdirectory with VTKConfig.cmake file (for windows)") -endif() \ No newline at end of file +endif() diff --git a/doc/tutorials/viz/launching_viz/launching_viz.rst b/doc/tutorials/viz/launching_viz/launching_viz.rst index 0bf31977d..a507a7f27 100644 --- a/doc/tutorials/viz/launching_viz/launching_viz.rst +++ b/doc/tutorials/viz/launching_viz/launching_viz.rst @@ -43,7 +43,7 @@ You can download the code from :download:`here <../../../../samples/cpp/tutorial cout << "First event loop is over" << endl; /// Access window via its name - viz::Viz3d sameWindow = viz::get("Viz Demo"); + viz::Viz3d sameWindow = viz::getWindowByName("Viz Demo"); /// Start event loop sameWindow.spin(); diff --git a/modules/core/include/opencv2/core/affine.hpp b/modules/core/include/opencv2/core/affine.hpp index fefcef8f1..8a5476292 100644 --- a/modules/core/include/opencv2/core/affine.hpp +++ b/modules/core/include/opencv2/core/affine.hpp @@ -55,9 +55,9 @@ namespace cv { public: typedef T float_type; - typedef cv::Matx Mat3; - typedef cv::Matx Mat4; - typedef cv::Vec Vec3; + typedef Matx Mat3; + typedef Matx Mat4; + typedef Vec Vec3; Affine3(); @@ -70,11 +70,11 @@ namespace cv //Rodrigues vector Affine3(const Vec3& rvec, const Vec3& t = Vec3::all(0)); - //Combines all contructors above. Supports 4x4, 3x3, 1x3, 3x1 sizes of data matrix - explicit Affine3(const cv::Mat& data, const Vec3& t = Vec3::all(0)); + //Combines all contructors above. Supports 4x4, 3x4, 3x3, 1x3, 3x1 sizes of data matrix + explicit Affine3(const Mat& data, const Vec3& t = Vec3::all(0)); - //Euler angles - Affine3(float_type alpha, float_type beta, float_type gamma, const Vec3& t = Vec3::all(0)); + //From 16th element array + explicit Affine3(const float_type* vals); static Affine3 Identity(); @@ -87,9 +87,6 @@ namespace cv //Combines rotation methods above. Suports 3x3, 1x3, 3x1 sizes of data matrix; void rotation(const Mat& data); - //Euler angles - void rotation(float_type alpha, float_type beta, float_type gamma); - void linear(const Mat3& L); void translation(const Vec3& t); @@ -105,6 +102,9 @@ namespace cv // a.rotate(R) is equivalent to Affine(R, 0) * a; Affine3 rotate(const Mat3& R) const; + // a.rotate(R) is equivalent to Affine(rvec, 0) * a; + Affine3 rotate(const Vec3& rvec) const; + // a.translate(t) is equivalent to Affine(E, t) * a; Affine3 translate(const Vec3& t) const; @@ -113,6 +113,8 @@ namespace cv template operator Affine3() const; + template Affine3 cast() const; + Mat4 matrix; #if defined EIGEN_WORLD_VERSION && defined EIGEN_GEOMETRY_MODULE_H @@ -132,10 +134,26 @@ namespace cv typedef Affine3 Affine3f; typedef Affine3 Affine3d; - static cv::Vec3f operator*(const cv::Affine3f& affine, const cv::Vec3f& vector); - static cv::Vec3d operator*(const cv::Affine3d& affine, const cv::Vec3d& vector); -} + static Vec3f operator*(const Affine3f& affine, const Vec3f& vector); + static Vec3d operator*(const Affine3d& affine, const Vec3d& vector); + template class DataType< Affine3<_Tp> > + { + public: + typedef Affine3<_Tp> value_type; + typedef Affine3::work_type> work_type; + typedef _Tp channel_type; + + enum { generic_type = 0, + depth = DataType::depth, + channels = 16, + fmt = DataType::fmt + ((channels - 1) << 8), + type = CV_MAKETYPE(depth, channels) + }; + + typedef Vec vec_type; + }; +} /////////////////////////////////////////////////////////////////////////////////// @@ -179,6 +197,12 @@ cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) data.copyTo(matrix); return; } + else if (data.cols == 4 && data.rows == 3) + { + rotation(data(Rect(0, 0, 3, 3))); + translation(data(Rect(3, 0, 1, 3))); + return; + } rotation(data); translation(t); @@ -187,13 +211,8 @@ cv::Affine3::Affine3(const cv::Mat& data, const Vec3& t) } template inline -cv::Affine3::Affine3(float_type alpha, float_type beta, float_type gamma, const Vec3& t) -{ - rotation(alpha, beta, gamma); - translation(t); - matrix.val[12] = matrix.val[13] = matrix.val[14] = 0; - matrix.val[15] = 1; -} +cv::Affine3::Affine3(const float_type* vals) : matrix(vals) +{} template inline cv::Affine3 cv::Affine3::Identity() @@ -261,12 +280,6 @@ void cv::Affine3::rotation(const cv::Mat& data) CV_Assert(!"Input marix can be 3x3, 1x3 or 3x1"); } -template inline -void cv::Affine3::rotation(float_type alpha, float_type beta, float_type gamma) -{ - rotation(Vec3(alpha, beta, gamma)); -} - template inline void cv::Affine3::linear(const Mat3& L) { @@ -382,6 +395,12 @@ cv::Affine3 cv::Affine3::rotate(const Mat3& R) const return result; } +template inline +cv::Affine3 cv::Affine3::rotate(const Vec3& _rvec) const +{ + return rotate(Affine3f(_rvec).rotation()); +} + template inline cv::Affine3 cv::Affine3::translate(const Vec3& t) const { @@ -404,6 +423,12 @@ cv::Affine3::operator Affine3() const return Affine3(matrix); } +template template inline +cv::Affine3 cv::Affine3::cast() const +{ + return Affine3(matrix); +} + template inline cv::Affine3 cv::operator*(const cv::Affine3& affine1, const cv::Affine3& affine2) { diff --git a/modules/viz/doc/viz3d.rst b/modules/viz/doc/viz3d.rst index 2f8dfcd9d..d0e24ae8e 100644 --- a/modules/viz/doc/viz3d.rst +++ b/modules/viz/doc/viz3d.rst @@ -13,7 +13,7 @@ viz::makeTransformToGlobal -------------------------- Takes coordinate frame data and builds transform to global coordinate frame. -.. ocv:function:: Affine3f viz::makeTransformToGlobal(const Vec3f& axis_x, const Vec3f& axis_y, const Vec3f& axis_z, const Vec3f& origin = Vec3f::all(0)) +.. ocv:function:: Affine3d viz::makeTransformToGlobal(const Vec3f& axis_x, const Vec3f& axis_y, const Vec3f& axis_z, const Vec3f& origin = Vec3f::all(0)) :param axis_x: X axis vector in global coordinate frame. :param axis_y: Y axis vector in global coordinate frame. @@ -26,7 +26,7 @@ viz::makeCameraPose ------------------- Constructs camera pose from position, focal_point and up_vector (see gluLookAt() for more infromation). -.. ocv:function:: Affine3f makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir) +.. ocv:function:: Affine3d makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir) :param position: Position of the camera in global coordinate frame. :param focal_point: Focal point of the camera in global coordinate frame. @@ -34,11 +34,11 @@ Constructs camera pose from position, focal_point and up_vector (see gluLookAt() This function returns pose of the camera in global coordinate frame. -viz::get --------- +viz::getWindowByName +-------------------- Retrieves a window by its name. -.. ocv:function:: Viz3d get(const String &window_name) +.. ocv:function:: Viz3d getWindowByName(const String &window_name) :param window_name: Name of the window that is to be retrieved. @@ -51,8 +51,8 @@ This function returns a :ocv:class:`Viz3d` object with the given name. .. code-block:: cpp /// window and window_2 are the same windows. - viz::Viz3d window = viz::get("myWindow"); - viz::Viz3d window_2 = viz::get("Viz - myWindow"); + viz::Viz3d window = viz::getWindowByName("myWindow"); + viz::Viz3d window_2 = viz::getWindowByName("Viz - myWindow"); viz::isNan ---------- @@ -94,19 +94,21 @@ The Viz3d class represents a 3D visualizer window. This class is implicitly shar Viz3d& operator=(const Viz3d&); ~Viz3d(); - void showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()); + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); void removeWidget(const String &id); Widget getWidget(const String &id) const; void removeAllWidgets(); - void setWidgetPose(const String &id, const Affine3f &pose); - void updateWidgetPose(const String &id, const Affine3f &pose); - Affine3f getWidgetPose(const String &id) const; + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; + + void showImage(InputArray image, const Size& window_size = Size(-1, -1)); void setCamera(const Camera &camera); Camera getCamera() const; - Affine3f getViewerPose(); - void setViewerPose(const Affine3f &pose); + Affine3d getViewerPose(); + void setViewerPose(const Affine3d &pose); void resetCameraViewpoint (const String &id); void resetCamera(); @@ -132,8 +134,6 @@ The Viz3d class represents a 3D visualizer window. This class is implicitly shar void setRenderingProperty(const String &id, int property, double value); double getRenderingProperty(const String &id, int property); - void setDesiredUpdateRate(double rate); - double getDesiredUpdateRate(); void setRepresentation(int representation); private: @@ -152,7 +152,7 @@ viz::Viz3d::showWidget ---------------------- Shows a widget in the window. -.. ocv:function:: void Viz3d::showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()) +.. ocv:function:: void Viz3d::showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()) :param id: A unique id for the widget. :param widget: The widget to be displayed in the window. @@ -182,11 +182,20 @@ Removes all widgets from the window. .. ocv:function:: void removeAllWidgets() +viz::Viz3d::showImage +--------------------- +Removed all widgets and displays image scaled to whole window area. + +.. ocv:function:: void showImage(InputArray image, const Size& window_size = Size(-1, -1)) + + :param image: Image to be displayed. + :param size: Size of Viz3d window. Default value means no change. + viz::Viz3d::setWidgetPose ------------------------- Sets pose of a widget in the window. -.. ocv:function:: void setWidgetPose(const String &id, const Affine3f &pose) +.. ocv:function:: void setWidgetPose(const String &id, const Affine3d &pose) :param id: The id of the widget whose pose will be set. :param pose: The new pose of the widget. @@ -195,7 +204,7 @@ viz::Viz3d::updateWidgetPose ---------------------------- Updates pose of a widget in the window by pre-multiplying its current pose. -.. ocv:function:: void updateWidgetPose(const String &id, const Affine3f &pose) +.. ocv:function:: void updateWidgetPose(const String &id, const Affine3d &pose) :param id: The id of the widget whose pose will be updated. :param pose: The pose that the current pose of the widget will be pre-multiplied by. @@ -204,7 +213,7 @@ viz::Viz3d::getWidgetPose ------------------------- Returns the current pose of a widget in the window. -.. ocv:function:: Affine3f getWidgetPose(const String &id) const +.. ocv:function:: Affine3d getWidgetPose(const String &id) const :param id: The id of the widget whose pose will be returned. @@ -226,13 +235,13 @@ viz::Viz3d::getViewerPose ------------------------- Returns the current pose of the viewer. -..ocv:function:: Affine3f getViewerPose() +..ocv:function:: Affine3d getViewerPose() viz::Viz3d::setViewerPose ------------------------- Sets pose of the viewer. -.. ocv:function:: void setViewerPose(const Affine3f &pose) +.. ocv:function:: void setViewerPose(const Affine3d &pose) :param pose: The new pose of the viewer. @@ -414,20 +423,6 @@ Returns rendering property of a widget. * **SHADING_GOURAUD** * **SHADING_PHONG** -viz::Viz3d::setDesiredUpdateRate --------------------------------- -Sets desired update rate of the window. - -.. ocv:function:: void setDesiredUpdateRate(double rate) - - :param rate: Desired update rate. The default is 30. - -viz::Viz3d::getDesiredUpdateRate --------------------------------- -Returns desired update rate of the window. - -.. ocv:function:: double getDesiredUpdateRate() - viz::Viz3d::setRepresentation ----------------------------- Sets geometry representation of the widgets to surface, wireframe or points. @@ -468,33 +463,33 @@ This class a represents BGR color. :: static Color gray(); }; -viz::Mesh3d +viz::Mesh ----------- -.. ocv:class:: Mesh3d +.. ocv:class:: Mesh This class wraps mesh attributes, and it can load a mesh from a ``ply`` file. :: - class CV_EXPORTS Mesh3d + class CV_EXPORTS Mesh { public: - Mat cloud, colors; + Mat cloud, colors, normals; + + //! Raw integer list of the form: (n,id1,id2,...,idn, n,id1,id2,...,idn, ...) + //! where n is the number of points in the poligon, and id is a zero-offset index into an associated cloud. Mat polygons; //! Loads mesh from a given ply file - static Mesh3d loadMesh(const String& file); - - private: - /* hidden */ + static Mesh load(const String& file); }; -viz::Mesh3d::loadMesh +viz::Mesh::load --------------------- Loads a mesh from a ``ply`` file. -.. ocv:function:: static Mesh3d loadMesh(const String& file) +.. ocv:function:: static Mesh load(const String& file) - :param file: File name. + :param file: File name (for no only PLY is supported) viz::KeyboardEvent @@ -506,40 +501,28 @@ This class represents a keyboard event. :: class CV_EXPORTS KeyboardEvent { public: - static const unsigned int Alt = 1; - static const unsigned int Ctrl = 2; - static const unsigned int Shift = 4; + enum { ALT = 1, CTRL = 2, SHIFT = 4 }; + enum Action { KEY_UP = 0, KEY_DOWN = 1 }; - //! Create a keyboard event - //! - Note that action is true if key is pressed, false if released - KeyboardEvent (bool action, const std::string& key_sym, unsigned char key, bool alt, bool ctrl, bool shift); + KeyboardEvent(Action action, const String& symbol, unsigned char code, int modifiers); - bool isAltPressed () const; - bool isCtrlPressed () const; - bool isShiftPressed () const; - - unsigned char getKeyCode () const; - - const String& getKeySym () const; - bool keyDown () const; - bool keyUp () const; - - protected: - /* hidden */ + Action action; + String symbol; + unsigned char code; + int modifiers; }; viz::KeyboardEvent::KeyboardEvent --------------------------------- Constructs a KeyboardEvent. -.. ocv:function:: KeyboardEvent (bool action, const std::string& key_sym, unsigned char key, bool alt, bool ctrl, bool shift) +.. ocv:function:: KeyboardEvent (Action action, const String& symbol, unsigned char code, Modifiers modifiers) + + :param action: Signals if key is pressed or released. + :param symbol: Name of the key. + :param code: Code of the key. + :param modifiers: Signals if ``alt``, ``ctrl`` or ``shift`` are pressed or their combination. - :param action: If true, key is pressed. If false, key is released. - :param key_sym: Name of the key. - :param key: Code of the key. - :param alt: If true, ``alt`` is pressed. - :param ctrl: If true, ``ctrl`` is pressed. - :param shift: If true, ``shift`` is pressed. viz::MouseEvent --------------- @@ -553,26 +536,24 @@ This class represents a mouse event. :: enum Type { MouseMove = 1, MouseButtonPress, MouseButtonRelease, MouseScrollDown, MouseScrollUp, MouseDblClick } ; enum MouseButton { NoButton = 0, LeftButton, MiddleButton, RightButton, VScroll } ; - MouseEvent (const Type& type, const MouseButton& button, const Point& p, bool alt, bool ctrl, bool shift); + MouseEvent(const Type& type, const MouseButton& button, const Point& pointer, int modifiers); Type type; MouseButton button; Point pointer; - unsigned int key_state; + int modifiers; }; viz::MouseEvent::MouseEvent --------------------------- Constructs a MouseEvent. -.. ocv:function:: MouseEvent (const Type& type, const MouseButton& button, const Point& p, bool alt, bool ctrl, bool shift) +.. ocv:function:: MouseEvent (const Type& type, const MouseButton& button, const Point& p, Modifiers modifiers) :param type: Type of the event. This can be **MouseMove**, **MouseButtonPress**, **MouseButtonRelease**, **MouseScrollDown**, **MouseScrollUp**, **MouseDblClick**. :param button: Mouse button. This can be **NoButton**, **LeftButton**, **MiddleButton**, **RightButton**, **VScroll**. :param p: Position of the event. - :param alt: If true, ``alt`` is pressed. - :param ctrl: If true, ``ctrl`` is pressed. - :param shift: If true, ``shift`` is pressed. + :param modifiers: Signals if ``alt``, ``ctrl`` or ``shift`` are pressed or their combination. viz::Camera ----------- @@ -585,24 +566,24 @@ that can extract the intrinsic parameters from ``field of view``, ``intrinsic ma class CV_EXPORTS Camera { public: - Camera(float f_x, float f_y, float c_x, float c_y, const Size &window_size); - Camera(const Vec2f &fov, const Size &window_size); - Camera(const cv::Matx33f &K, const Size &window_size); - Camera(const cv::Matx44f &proj, const Size &window_size); + Camera(double f_x, double f_y, double c_x, double c_y, const Size &window_size); + Camera(const Vec2d &fov, const Size &window_size); + Camera(const Matx33d &K, const Size &window_size); + Camera(const Matx44d &proj, const Size &window_size); - inline const Vec2d & getClip() const { return clip_; } - inline void setClip(const Vec2d &clip) { clip_ = clip; } + inline const Vec2d & getClip() const; + inline void setClip(const Vec2d &clip); - inline const Size & getWindowSize() const { return window_size_; } + inline const Size & getWindowSize() const; void setWindowSize(const Size &window_size); - inline const Vec2f & getFov() const { return fov_; } - inline void setFov(const Vec2f & fov) { fov_ = fov; } + inline const Vec2d & getFov() const; + inline void setFov(const Vec2d & fov); - inline const Vec2f & getPrincipalPoint() const { return principal_point_; } - inline const Vec2f & getFocalLength() const { return focal_; } + inline const Vec2d & getPrincipalPoint() const; + inline const Vec2d & getFocalLength() const; - void computeProjectionMatrix(Matx44f &proj) const; + void computeProjectionMatrix(Matx44d &proj) const; static Camera KinectCamera(const Size &window_size); @@ -614,7 +595,7 @@ viz::Camera::Camera ------------------- Constructs a Camera. -.. ocv:function:: Camera(float f_x, float f_y, float c_x, float c_y, const Size &window_size) +.. ocv:function:: Camera(double f_x, double f_y, double c_x, double c_y, const Size &window_size) :param f_x: Horizontal focal length. :param f_y: Vertical focal length. @@ -622,19 +603,19 @@ Constructs a Camera. :param c_y: y coordinate of the principal point. :param window_size: Size of the window. This together with focal length and principal point determines the field of view. -.. ocv:function:: Camera(const Vec2f &fov, const Size &window_size) +.. ocv:function:: Camera(const Vec2d &fov, const Size &window_size) :param fov: Field of view (horizontal, vertical) :param window_size: Size of the window. Principal point is at the center of the window by default. -.. ocv:function:: Camera(const cv::Matx33f &K, const Size &window_size) +.. ocv:function:: Camera(const Matx33d &K, const Size &window_size) :param K: Intrinsic matrix of the camera. :param window_size: Size of the window. This together with intrinsic matrix determines the field of view. -.. ocv:function:: Camera(const cv::Matx44f &proj, const Size &window_size) +.. ocv:function:: Camera(const Matx44d &proj, const Size &window_size) :param proj: Projection matrix of the camera. :param window_size: Size of the window. This together with projection matrix determines the field of view. @@ -643,7 +624,7 @@ viz::Camera::computeProjectionMatrix ------------------------------------ Computes projection matrix using intrinsic parameters of the camera. -.. ocv:function:: void computeProjectionMatrix(Matx44f &proj) const +.. ocv:function:: void computeProjectionMatrix(Matx44d &proj) const :param proj: Output projection matrix. diff --git a/modules/viz/doc/widget.rst b/modules/viz/doc/widget.rst index bbbfef63a..9ed28a775 100644 --- a/modules/viz/doc/widget.rst +++ b/modules/viz/doc/widget.rst @@ -170,20 +170,23 @@ Base class of all 3D widgets. :: public: Widget3D() {} - void setPose(const Affine3f &pose); - void updatePose(const Affine3f &pose); - Affine3f getPose() const; + //! widget position manipulation, i.e. place where it is rendered. + void setPose(const Affine3d &pose); + void updatePose(const Affine3d &pose); + Affine3d getPose() const; + + //! updates internal widget data, i.e. points, normals, etc. + void applyTransform(const Affine3d &transform); void setColor(const Color &color); - private: - /* hidden */ + }; viz::Widget3D::setPose ---------------------- Sets pose of the widget. -.. ocv:function:: void setPose(const Affine3f &pose) +.. ocv:function:: void setPose(const Affine3d &pose) :param pose: The new pose of the widget. @@ -191,7 +194,7 @@ viz::Widget3D::updateWidgetPose ------------------------------- Updates pose of the widget by pre-multiplying its current pose. -.. ocv:function:: void updateWidgetPose(const Affine3f &pose) +.. ocv:function:: void updateWidgetPose(const Affine3d &pose) :param pose: The pose that the current pose of the widget will be pre-multiplied by. @@ -199,7 +202,16 @@ viz::Widget3D::getPose ---------------------- Returns the current pose of the widget. -.. ocv:function:: Affine3f getWidgetPose() const +.. ocv:function:: Affine3d getWidgetPose() const + + +viz::Widget3D::applyTransform +------------------------------- +Transforms internal widget data (i.e. points, normals) using the given transform. + +.. ocv:function:: void applyTransform(const Affine3d &transform) + + :param transform: Specified transformation to apply. viz::Widget3D::setColor ----------------------- @@ -262,27 +274,31 @@ This 3D Widget defines a finite plane. :: class CV_EXPORTS WPlane : public Widget3D { public: - WPlane(const Vec4f& coefs, float size = 1.0, const Color &color = Color::white()); - WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.0, const Color &color = Color::white()); - private: - /* hidden */ + //! created default plane with center point at origin and normal oriented along z-axis + WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + + //! repositioned plane + WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_plane_yaxis,const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); }; viz::WPlane::WPlane ------------------- -Constructs a WPlane. +Constructs a default plane with center point at origin and normal oriented along z-axis. -.. ocv:function:: WPlane(const Vec4f& coefs, float size = 1.0, const Color &color = Color::white()) +.. ocv:function:: WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()) - :param coefs: Plane coefficients as in (A,B,C,D) where Ax + By + Cz + D = 0. - :param size: Size of the plane. + :param size: Size of the plane :param color: :ocv:class:`Color` of the plane. -.. ocv:function:: WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.0, const Color &color = Color::white()) +viz::WPlane::WPlane +------------------- +Constructs a repositioned plane - :param coefs: Plane coefficients as in (A,B,C,D) where Ax + By + Cz + D = 0. - :param pt: Position of the plane. - :param size: Size of the plane. +.. ocv:function:: WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis,const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()) + + :param center: Center of the plane + :param normal: Plane normal orientation + :param new_yaxis: Up-vector. New orientation of plane y-axis. :param color: :ocv:class:`Color` of the plane. viz::WSphere @@ -294,14 +310,14 @@ This 3D Widget defines a sphere. :: class CV_EXPORTS WSphere : public Widget3D { public: - WSphere(const cv::Point3f ¢er, float radius, int sphere_resolution = 10, const Color &color = Color::white()) + WSphere(const cv::Point3f ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()) }; viz::WSphere::WSphere --------------------- Constructs a WSphere. -.. ocv:function:: WSphere(const cv::Point3f ¢er, float radius, int sphere_resolution = 10, const Color &color = Color::white()) +.. ocv:function:: WSphere(const cv::Point3f ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()) :param center: Center of the sphere. :param radius: Radius of the sphere. @@ -317,14 +333,14 @@ This 3D Widget defines an arrow. :: class CV_EXPORTS WArrow : public Widget3D { public: - WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03, const Color &color = Color::white()); + WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()); }; viz::WArrow::WArrow ----------------------------- Constructs an WArrow. -.. ocv:function:: WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03, const Color &color = Color::white()) +.. ocv:function:: WArrow(const Point3f& pt1, const Point3f& pt2, double thickness = 0.03, const Color &color = Color::white()) :param pt1: Start point of the arrow. :param pt2: End point of the arrow. @@ -342,20 +358,75 @@ This 3D Widget defines a circle. :: class CV_EXPORTS WCircle : public Widget3D { public: - WCircle(const Point3f& pt, float radius, float thickness = 0.01, const Color &color = Color::white()); + //! creates default planar circle centred at origin with plane normal along z-axis + WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()); + + //! creates repositioned circle + WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()); }; viz::WCircle::WCircle ------------------------------- -Constructs a WCircle. +Constructs default planar circle centred at origin with plane normal along z-axis -.. ocv:function:: WCircle(const Point3f& pt, float radius, float thickness = 0.01, const Color &color = Color::white()) +.. ocv:function:: WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()) - :param pt: Center of the circle. :param radius: Radius of the circle. :param thickness: Thickness of the circle. :param color: :ocv:class:`Color` of the circle. +viz::WCircle::WCircle +------------------------------- +Constructs repositioned planar circle. + +.. ocv:function:: WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()) + + :param radius: Radius of the circle. + :param center: Center of the circle. + :param normal: Normal of the plane in which the circle lies. + :param thickness: Thickness of the circle. + :param color: :ocv:class:`Color` of the circle. + + +viz::WCone +------------------------------- +.. ocv:class:: WCone + +This 3D Widget defines a cone. :: + + class CV_EXPORTS WCone : public Widget3D + { + public: + //! create default cone, oriented along x-axis with center of its base located at origin + WCone(double lenght, double radius, int resolution = 6.0, const Color &color = Color::white()); + + //! creates repositioned cone + WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()); + }; + +viz::WCone::WCone +------------------------------- +Constructs default cone oriented along x-axis with center of its base located at origin + +.. ocv:function:: WCone(double length, double radius, int resolution = 6.0, const Color &color = Color::white()) + + :param length: Length of the cone. + :param radius: Radius of the cone. + :param resolution: Resolution of the cone. + :param color: :ocv:class:`Color` of the cone. + +viz::WCone::WCone +------------------------------- +Constructs repositioned planar cone. + +.. ocv:function:: WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()) + + :param radius: Radius of the cone. + :param center: Center of the cone base. + :param tip: Tip of the cone. + :param resolution: Resolution of the cone. + :param color: :ocv:class:`Color` of the cone. + viz::WCylinder -------------- .. ocv:class:: WCylinder @@ -365,17 +436,17 @@ This 3D Widget defines a cylinder. :: class CV_EXPORTS WCylinder : public Widget3D { public: - WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()); + WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides = 30, const Color &color = Color::white()); }; viz::WCylinder::WCylinder ----------------------------------- Constructs a WCylinder. -.. ocv:function:: WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()) +.. ocv:function:: WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, double radius, int numsides = 30, const Color &color = Color::white()) - :param pt_on_axis: A point on the axis of the cylinder. - :param axis_direction: Direction of the axis of the cylinder. + :param axis_point1: A point1 on the axis of the cylinder. + :param axis_point2: A point2 on the axis of the cylinder. :param radius: Radius of the cylinder. :param numsides: Resolution of the cylinder. :param color: :ocv:class:`Color` of the cylinder. @@ -416,14 +487,14 @@ This 3D Widget represents a coordinate system. :: class CV_EXPORTS WCoordinateSystem : public Widget3D { public: - WCoordinateSystem(float scale = 1.0); + WCoordinateSystem(double scale = 1.0); }; viz::WCoordinateSystem::WCoordinateSystem --------------------------------------------------- Constructs a WCoordinateSystem. -.. ocv:function:: WCoordinateSystem(float scale = 1.0) +.. ocv:function:: WCoordinateSystem(double scale = 1.0) :param scale: Determines the size of the axes. @@ -437,9 +508,6 @@ This 3D Widget defines a poly line. :: { public: WPolyLine(InputArray points, const Color &color = Color::white()); - - private: - /* hidden */ }; viz::WPolyLine::WPolyLine @@ -460,30 +528,32 @@ This 3D Widget defines a grid. :: class CV_EXPORTS WGrid : public Widget3D { public: - //! Creates grid at the origin - WGrid(const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()); - //! Creates grid based on the plane equation - WGrid(const Vec4f &coeffs, const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()); - private: - /* hidden */ + //! Creates grid at the origin and normal oriented along z-axis + WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + + //! Creates repositioned grid + WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); }; viz::WGrid::WGrid --------------------------- Constructs a WGrid. -.. ocv:function:: WGrid(const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()) +.. ocv:function:: WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()) - :param dimensions: Number of columns and rows, respectively. - :param spacing: Size of each column and row, respectively. + :param cells: Number of cell columns and rows, respectively. + :param cells_spacing: Size of each cell, respectively. :param color: :ocv:class:`Color` of the grid. -.. ocv:function: WGrid(const Vec4f &coeffs, const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()) +.. ocv:function: WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, Vec2i &cells, const Vec2d &cells_spacing, const Color &color; - :param coeffs: Plane coefficients as in (A,B,C,D) where Ax + By + Cz + D = 0. - :param dimensions: Number of columns and rows, respectively. - :param spacing: Size of each column and row, respectively. - :param color: :ocv:class:`Color` of the grid. + :param center: Center of the grid + :param normal: Grid normal orientation + :param new_yaxis: Up-vector. New orientation of grid y-axis. + :param cells: Number of cell columns and rows, respectively. + :param cells_spacing: Size of each cell, respectively. + :param color: :ocv:class:`Color` of the grid.. viz::WText3D ------------ @@ -494,7 +564,7 @@ This 3D Widget represents 3D text. The text always faces the camera. :: class CV_EXPORTS WText3D : public Widget3D { public: - WText3D(const String &text, const Point3f &position, float text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()); + WText3D(const String &text, const Point3f &position, double text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()); void setText(const String &text); String getText() const; @@ -504,7 +574,7 @@ viz::WText3D::WText3D ------------------------------- Constructs a WText3D. -.. ocv:function:: WText3D(const String &text, const Point3f &position, float text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()) +.. ocv:function:: WText3D(const String &text, const Point3f &position, double text_scale = 1.0, bool face_camera = true, const Color &color = Color::white()) :param text: Text content of the widget. :param position: Position of the text. @@ -575,16 +645,16 @@ This 2D Widget represents an image overlay. :: class CV_EXPORTS WImageOverlay : public Widget2D { public: - WImageOverlay(const Mat &image, const Rect &rect); + WImageOverlay(InputArray image, const Rect &rect); - void setImage(const Mat &image); + void setImage(InputArray image); }; viz::WImageOverlay::WImageOverlay --------------------------------- Constructs an WImageOverlay. -.. ocv:function:: WImageOverlay(const Mat &image, const Rect &rect) +.. ocv:function:: WImageOverlay(InputArray image, const Rect &rect) :param image: BGR or Gray-Scale image. :param rect: Image is scaled and positioned based on rect. @@ -593,7 +663,7 @@ viz::WImageOverlay::setImage ---------------------------- Sets the image content of the widget. -.. ocv:function:: void setImage(const Mat &image) +.. ocv:function:: void setImage(InputArray image) :param image: BGR or Gray-Scale image. @@ -607,23 +677,23 @@ This 3D Widget represents an image in 3D space. :: { public: //! Creates 3D image at the origin - WImage3D(const Mat &image, const Size &size); + WImage3D(InputArray image, const Size2d &size); //! Creates 3D image at a given position, pointing in the direction of the normal, and having the up_vector orientation - WImage3D(const Vec3f &position, const Vec3f &normal, const Vec3f &up_vector, const Mat &image, const Size &size); + WImage3D(InputArray image, const Size2d &size, const Vec3d &position, const Vec3d &normal, const Vec3d &up_vector); - void setImage(const Mat &image); + void setImage(InputArray image); }; viz::WImage3D::WImage3D ----------------------- Constructs an WImage3D. -.. ocv:function:: WImage3D(const Mat &image, const Size &size) +.. ocv:function:: WImage3D(InputArray image, const Size2d &size) :param image: BGR or Gray-Scale image. :param size: Size of the image. -.. ocv:function:: WImage3D(const Vec3f &position, const Vec3f &normal, const Vec3f &up_vector, const Mat &image, const Size &size) +.. ocv:function:: WImage3D(InputArray image, const Size2d &size, const Vec3d &position, const Vec3d &normal, const Vec3d &up_vector) :param position: Position of the image. :param normal: Normal of the plane that represents the image. @@ -635,7 +705,7 @@ viz::WImage3D::setImage ----------------------- Sets the image content of the widget. -.. ocv:function:: void setImage(const Mat &image) +.. ocv:function:: void setImage(InputArray image) :param image: BGR or Gray-Scale image. @@ -649,15 +719,15 @@ This 3D Widget represents camera position in a scene by its axes or viewing frus { public: //! Creates camera coordinate frame (axes) at the origin - WCameraPosition(float scale = 1.0); + WCameraPosition(double scale = 1.0); //! Creates frustum based on the intrinsic marix K at the origin - WCameraPosition(const Matx33f &K, float scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum based on the field of view at the origin - WCameraPosition(const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.0, const Color &color = Color::white()); + WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()); }; viz::WCameraPosition::WCameraPosition @@ -666,7 +736,7 @@ Constructs a WCameraPosition. - **Display camera coordinate frame.** - .. ocv:function:: WCameraPosition(float scale = 1.0) + .. ocv:function:: WCameraPosition(double scale = 1.0) Creates camera coordinate frame at the origin. @@ -676,7 +746,7 @@ Constructs a WCameraPosition. - **Display the viewing frustum.** - .. ocv:function:: WCameraPosition(const Matx33f &K, float scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()) :param K: Intrinsic matrix of the camera. :param scale: Scale of the frustum. @@ -684,7 +754,7 @@ Constructs a WCameraPosition. Creates viewing frustum of the camera based on its intrinsic matrix K. - .. ocv:function:: WCameraPosition(const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()) :param fov: Field of view of the camera (horizontal, vertical). :param scale: Scale of the frustum. @@ -698,7 +768,7 @@ Constructs a WCameraPosition. - **Display image on the far plane of the viewing frustum.** - .. ocv:function:: WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()) :param K: Intrinsic matrix of the camera. :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. @@ -707,7 +777,7 @@ Constructs a WCameraPosition. Creates viewing frustum of the camera based on its intrinsic matrix K, and displays image on the far end plane. - .. ocv:function:: WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.0, const Color &color = Color::white()) + .. ocv:function:: WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()) :param fov: Field of view of the camera (horizontal, vertical). :param img: BGR or Gray-Scale image that is going to be displayed on the far plane of the frustum. @@ -729,81 +799,91 @@ This 3D Widget represents a trajectory. :: class CV_EXPORTS WTrajectory : public Widget3D { public: - enum {DISPLAY_FRAMES = 1, DISPLAY_PATH = 2}; + enum {FRAMES = 1, PATH = 2, BOTH = FRAMES + PATH}; //! Displays trajectory of the given path either by coordinate frames or polyline - WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.0); - //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.0, const Color &color = Color::white()); - //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()); - - private: - /* hidden */ + WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white(),; }; viz::WTrajectory::WTrajectory ----------------------------- Constructs a WTrajectory. -.. ocv:function:: WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.0) +.. ocv:function:: WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white()) - :param path: List of poses on a trajectory. - :param display_mode: Display mode. This can be DISPLAY_PATH, DISPLAY_FRAMES, DISPLAY_PATH & DISPLAY_FRAMES. - :param color: :ocv:class:`Color` of the polyline that represents path. Frames are not affected. + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param display_mode: Display mode. This can be PATH, FRAMES, and BOTH. :param scale: Scale of the frames. Polyline is not affected. + :param color: :ocv:class:`Color` of the polyline that represents path. Frames are not affected. Displays trajectory of the given path as follows: - * DISPLAY_PATH : Displays a poly line that represents the path. - * DISPLAY_FRAMES : Displays coordinate frames at each pose. - * DISPLAY_PATH & DISPLAY_FRAMES : Displays both poly line and coordinate frames. + * PATH : Displays a poly line that represents the path. + * FRAMES : Displays coordinate frames at each pose. + * PATH & FRAMES : Displays both poly line and coordinate frames. -.. ocv:function:: WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.0, const Color &color = Color::white()) +viz::WTrajectoryFrustums +------------------------ +.. ocv:class:: WTrajectoryFrustums - :param path: List of poses on a trajectory. +This 3D Widget represents a trajectory. :: + + class CV_EXPORTS WTrajectoryFrustums : public Widget3D + { + public: + //! Displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); + //! Displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); + }; + +viz::WTrajectoryFrustums::WTrajectoryFrustums +--------------------------------------------- +Constructs a WTrajectoryFrustums. + +.. ocv:function:: WTrajectoryFrustums(const std::vector &path, const Matx33d &K, double scale = 1.0, const Color &color = Color::white()) + + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] :param K: Intrinsic matrix of the camera. :param scale: Scale of the frustums. :param color: :ocv:class:`Color` of the frustums. Displays frustums at each pose of the trajectory. -.. ocv:function:: WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.0, const Color &color = Color::white()) +.. ocv:function:: WTrajectoryFrustums(const std::vector &path, const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()) - :param path: List of poses on a trajectory. + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] :param fov: Field of view of the camera (horizontal, vertical). :param scale: Scale of the frustums. :param color: :ocv:class:`Color` of the frustums. Displays frustums at each pose of the trajectory. -viz::WSpheresTrajectory +viz::WTrajectorySpheres ----------------------- -.. ocv:class:: WSpheresTrajectory +.. ocv:class:: WTrajectorySpheres This 3D Widget represents a trajectory using spheres and lines, where spheres represent the positions of the camera, and lines represent the direction from previous position to the current. :: - class CV_EXPORTS WSpheresTrajectory : public Widget3D + class CV_EXPORTS WTrajectorySpheres : public Widget3D { public: - WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, - float init_sphere_radius = 0.021, sphere_radius = 0.007, - Color &line_color = Color::white(), const Color &sphere_color = Color::white()); + WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, + const Color &from = Color::red(), const Color &to = Color::white()); }; -viz::WSpheresTrajectory::WSpheresTrajectory +viz::WTrajectorySpheres::WTrajectorySpheres ------------------------------------------- -Constructs a WSpheresTrajectory. +Constructs a WTrajectorySpheres. -.. ocv:function:: WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, float init_sphere_radius = 0.021, float sphere_radius = 0.007, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()) +.. ocv:function:: WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, const Color &from = Color::red(), const Color &to = Color::white()) - :param path: List of poses on a trajectory. - :param line_length: Length of the lines. - :param init_sphere_radius: Radius of the first sphere which represents the initial position of the camera. - :param sphere_radius: Radius of the rest of the spheres. - :param line_color: :ocv:class:`Color` of the lines. - :param sphere_color: :ocv:class:`Color` of the spheres. + :param path: List of poses on a trajectory. Takes std::vector> with T == [float | double] + :param line_length: Max length of the lines which point to previous position + :param sphere_radius: Radius of the spheres. + :param from: :ocv:class:`Color` for first sphere. + :param to: :ocv:class:`Color` for last sphere. Intermediate spheres will have interpolated color. viz::WCloud ----------- @@ -818,9 +898,6 @@ This 3D Widget defines a point cloud. :: WCloud(InputArray cloud, InputArray colors); //! All points in cloud have the same color WCloud(InputArray cloud, const Color &color = Color::white()); - - private: - /* hidden */ }; viz::WCloud::WCloud @@ -855,12 +932,9 @@ This 3D Widget defines a collection of clouds. :: WCloudCollection(); //! Each point in cloud is mapped to a color in colors - void addCloud(InputArray cloud, InputArray colors, const Affine3f &pose = Affine3f::Identity()); + void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()); //! All points in cloud have the same color - void addCloud(InputArray cloud, const Color &color = Color::white(), Affine3f &pose = Affine3f::Identity()); - - private: - /* hidden */ + void addCloud(InputArray cloud, const Color &color = Color::white(), Affine3d &pose = Affine3d::Identity()); }; viz::WCloudCollection::WCloudCollection @@ -873,7 +947,7 @@ viz::WCloudCollection::addCloud ------------------------------- Adds a cloud to the collection. -.. ocv:function:: void addCloud(InputArray cloud, InputArray colors, const Affine3f &pose = Affine3f::Identity()) +.. ocv:function:: void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()) :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. :param colors: Set of colors. It has to be of the same size with cloud. @@ -881,7 +955,7 @@ Adds a cloud to the collection. Points in the cloud belong to mask when they are set to (NaN, NaN, NaN). -.. ocv:function:: void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3f &pose = Affine3f::Identity()) +.. ocv:function:: void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3d &pose = Affine3d::Identity()) :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. :param colors: A single :ocv:class:`Color` for the whole cloud. @@ -900,17 +974,14 @@ This 3D Widget represents normals of a point cloud. :: class CV_EXPORTS WCloudNormals : public Widget3D { public: - WCloudNormals(InputArray cloud, InputArray normals, int level = 100, float scale = 0.02f, const Color &color = Color::white()); - - private: - /* hidden */ + WCloudNormals(InputArray cloud, InputArray normals, int level = 100, double scale = 0.02f, const Color &color = Color::white()); }; viz::WCloudNormals::WCloudNormals --------------------------------- Constructs a WCloudNormals. -.. ocv:function:: WCloudNormals(InputArray cloud, InputArray normals, int level = 100, float scale = 0.02f, const Color &color = Color::white()) +.. ocv:function:: WCloudNormals(InputArray cloud, InputArray normals, int level = 100, double scale = 0.02f, const Color &color = Color::white()) :param cloud: Point set which can be of type: ``CV_32FC3``, ``CV_32FC4``, ``CV_64FC3``, ``CV_64FC4``. :param normals: A set of normals that has to be of same type with cloud. @@ -929,16 +1000,21 @@ This 3D Widget defines a mesh. :: class CV_EXPORTS WMesh : public Widget3D { public: - WMesh(const Mesh3d &mesh); - - private: - /* hidden */ + WMesh(const Mesh &mesh); + WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()); }; viz::WMesh::WMesh ----------------- Constructs a WMesh. -.. ocv:function:: WMesh(const Mesh3d &mesh) +.. ocv:function:: WMesh(const Mesh &mesh) - :param mesh: :ocv:class:`Mesh3d` object that will be displayed. + :param mesh: :ocv:class:`Mesh` object that will be displayed. + +.. ocv:function:: WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()) + + :param cloud: Points of the mesh object. + :param polygons: Points of the mesh object. + :param colors: Point colors. + :param normals: Point normals. diff --git a/modules/viz/include/opencv2/viz.hpp b/modules/viz/include/opencv2/viz.hpp index d4f08af72..bf44a2c03 100644 --- a/modules/viz/include/opencv2/viz.hpp +++ b/modules/viz/include/opencv2/viz.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_HPP__ @@ -58,17 +55,20 @@ namespace cv namespace viz { //! takes coordiante frame data and builds transfrom to global coordinate frame - CV_EXPORTS Affine3f makeTransformToGlobal(const Vec3f& axis_x, const Vec3f& axis_y, const Vec3f& axis_z, const Vec3f& origin = Vec3f::all(0)); + CV_EXPORTS Affine3d makeTransformToGlobal(const Vec3d& axis_x, const Vec3d& axis_y, const Vec3d& axis_z, const Vec3d& origin = Vec3d::all(0)); //! constructs camera pose from position, focal_point and up_vector (see gluLookAt() for more infromation) - CV_EXPORTS Affine3f makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir); + CV_EXPORTS Affine3d makeCameraPose(const Vec3d& position, const Vec3d& focal_point, const Vec3d& y_dir); //! retrieves a window by its name. If no window with such name, then it creates new. - CV_EXPORTS Viz3d get(const String &window_name); + CV_EXPORTS Viz3d getWindowByName(const String &window_name); - //! Unregisters all Viz windows from internal database. After it 'get()' will create new windows instead getting existing from the database. + //! Unregisters all Viz windows from internal database. After it 'getWindowByName()' will create new windows instead getting existing from the database. CV_EXPORTS void unregisterAllWindows(); + //! Displays image in specified window + CV_EXPORTS Viz3d imshow(const String& window_name, InputArray image, const Size& window_size = Size(-1, -1)); + //! checks float value for Nan inline bool isNan(float x) { @@ -91,6 +91,36 @@ namespace cv template inline bool isNan(const Point3_<_Tp>& p) { return isNan(p.x) || isNan(p.y) || isNan(p.z); } + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Read/write clouds. Supported formats: ply, xyz, obj and stl (readonly) + + CV_EXPORTS void writeCloud(const String& file, InputArray cloud, InputArray colors = noArray(), InputArray normals = noArray(), bool binary = false); + CV_EXPORTS Mat readCloud (const String& file, OutputArray colors = noArray(), OutputArray normals = noArray()); + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Reads mesh. Only ply format is supported now and no texture load support + + CV_EXPORTS Mesh readMesh(const String& file); + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Read/write poses and trajectories + + CV_EXPORTS bool readPose(const String& file, Affine3d& pose, const String& tag = "pose"); + CV_EXPORTS void writePose(const String& file, const Affine3d& pose, const String& tag = "pose"); + + //! takes vector> with T = float/dobule and writes to a sequence of files with given filename format + CV_EXPORTS void writeTrajectory(InputArray traj, const String& files_format = "pose%05d.xml", int start = 0, const String& tag = "pose"); + + //! takes vector> with T = float/dobule and loads poses from sequence of files + CV_EXPORTS void readTrajectory(OutputArray traj, const String& files_format = "pose%05d.xml", int start = 0, int end = INT_MAX, const String& tag = "pose"); + + + /////////////////////////////////////////////////////////////////////////////////////////////// + /// Computing normals for mesh + + CV_EXPORTS void computeNormals(const Mesh& mesh, OutputArray normals); + } /* namespace viz */ } /* namespace cv */ diff --git a/modules/viz/include/opencv2/viz/types.hpp b/modules/viz/include/opencv2/viz/types.hpp index 682006f95..3c3571b83 100644 --- a/modules/viz/include/opencv2/viz/types.hpp +++ b/modules/viz/include/opencv2/viz/types.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_TYPES_HPP__ @@ -77,49 +74,99 @@ namespace cv static Color white(); static Color gray(); + + static Color mlab(); + + static Color navy(); + static Color olive(); + static Color maroon(); + static Color teal(); + static Color rose(); + static Color azure(); + static Color lime(); + static Color gold(); + static Color brown(); + static Color orange(); + static Color chartreuse(); + static Color orange_red(); + static Color purple(); + static Color indigo(); + + static Color pink(); + static Color cherry(); + static Color bluberry(); + static Color raspberry(); + static Color silver(); + static Color violet(); + static Color apricot(); + static Color turquoise(); + static Color celestial_blue(); + static Color amethyst(); + + static Color not_set(); }; - class CV_EXPORTS Mesh3d + class CV_EXPORTS Mesh { public: + Mat cloud, colors, normals; - Mat cloud, colors; + //! Raw integer list of the form: (n,id1,id2,...,idn, n,id1,id2,...,idn, ...) + //! where n is the number of points in the poligon, and id is a zero-offset index into an associated cloud. Mat polygons; - //! Loads mesh from a given ply file - static cv::viz::Mesh3d loadMesh(const String& file); + Mat texture, tcoords; + + //! Loads mesh from a given ply file (no texture load support for now) + static Mesh load(const String& file); + }; + + class CV_EXPORTS Camera + { + public: + Camera(double fx, double fy, double cx, double cy, const Size &window_size); + explicit Camera(const Vec2d &fov, const Size &window_size); + explicit Camera(const Matx33d &K, const Size &window_size); + explicit Camera(const Matx44d &proj, const Size &window_size); + + const Vec2d & getClip() const { return clip_; } + void setClip(const Vec2d &clip) { clip_ = clip; } + + const Size & getWindowSize() const { return window_size_; } + void setWindowSize(const Size &window_size); + + const Vec2d& getFov() const { return fov_; } + void setFov(const Vec2d& fov) { fov_ = fov; } + + const Vec2d& getPrincipalPoint() const { return principal_point_; } + const Vec2d& getFocalLength() const { return focal_; } + + void computeProjectionMatrix(Matx44d &proj) const; + + static Camera KinectCamera(const Size &window_size); private: - struct loadMeshImpl; + void init(double fx, double fy, double cx, double cy, const Size &window_size); + + Vec2d clip_; + Vec2d fov_; + Size window_size_; + Vec2d principal_point_; + Vec2d focal_; }; class CV_EXPORTS KeyboardEvent { public: - static const unsigned int Alt = 1; - static const unsigned int Ctrl = 2; - static const unsigned int Shift = 4; + enum { NONE = 0, ALT = 1, CTRL = 2, SHIFT = 4 }; + enum Action { KEY_UP = 0, KEY_DOWN = 1 }; - //! Create a keyboard event - //! - Note that action is true if key is pressed, false if released - KeyboardEvent(bool action, const String& key_sym, unsigned char key, bool alt, bool ctrl, bool shift); + KeyboardEvent(Action action, const String& symbol, unsigned char code, int modifiers); - bool isAltPressed() const; - bool isCtrlPressed() const; - bool isShiftPressed() const; - - unsigned char getKeyCode() const; - - const String& getKeySym() const; - bool keyDown() const; - bool keyUp() const; - - protected: - - bool action_; - unsigned int modifiers_; - unsigned char key_code_; - String key_sym_; + Action action; + String symbol; + unsigned char code; + int modifiers; }; class CV_EXPORTS MouseEvent @@ -128,46 +175,12 @@ namespace cv enum Type { MouseMove = 1, MouseButtonPress, MouseButtonRelease, MouseScrollDown, MouseScrollUp, MouseDblClick } ; enum MouseButton { NoButton = 0, LeftButton, MiddleButton, RightButton, VScroll } ; - MouseEvent(const Type& type, const MouseButton& button, const Point& p, bool alt, bool ctrl, bool shift); + MouseEvent(const Type& type, const MouseButton& button, const Point& pointer, int modifiers); Type type; MouseButton button; Point pointer; - unsigned int key_state; - }; - - class CV_EXPORTS Camera - { - public: - Camera(float f_x, float f_y, float c_x, float c_y, const Size &window_size); - Camera(const Vec2f &fov, const Size &window_size); - Camera(const cv::Matx33f &K, const Size &window_size); - Camera(const cv::Matx44f &proj, const Size &window_size); - - inline const Vec2d & getClip() const { return clip_; } - inline void setClip(const Vec2d &clip) { clip_ = clip; } - - inline const Size & getWindowSize() const { return window_size_; } - void setWindowSize(const Size &window_size); - - inline const Vec2f & getFov() const { return fov_; } - inline void setFov(const Vec2f & fov) { fov_ = fov; } - - inline const Vec2f & getPrincipalPoint() const { return principal_point_; } - inline const Vec2f & getFocalLength() const { return focal_; } - - void computeProjectionMatrix(Matx44f &proj) const; - - static Camera KinectCamera(const Size &window_size); - - private: - void init(float f_x, float f_y, float c_x, float c_y, const Size &window_size); - - Vec2d clip_; - Vec2f fov_; - Size window_size_; - Vec2f principal_point_; - Vec2f focal_; + int modifiers; }; } /* namespace viz */ } /* namespace cv */ @@ -180,15 +193,44 @@ inline cv::viz::Color::Color(double _gray) : Scalar(_gray, _gray, _gray) {} inline cv::viz::Color::Color(double _blue, double _green, double _red) : Scalar(_blue, _green, _red) {} inline cv::viz::Color::Color(const Scalar& color) : Scalar(color) {} -inline cv::viz::Color cv::viz::Color::black() { return Color( 0, 0, 0); } -inline cv::viz::Color cv::viz::Color::green() { return Color( 0, 255, 0); } -inline cv::viz::Color cv::viz::Color::blue() { return Color(255, 0, 0); } -inline cv::viz::Color cv::viz::Color::cyan() { return Color(255, 255, 0); } +inline cv::viz::Color cv::viz::Color::black() { return Color( 0, 0, 0); } +inline cv::viz::Color cv::viz::Color::green() { return Color( 0, 255, 0); } +inline cv::viz::Color cv::viz::Color::blue() { return Color(255, 0, 0); } +inline cv::viz::Color cv::viz::Color::cyan() { return Color(255, 255, 0); } inline cv::viz::Color cv::viz::Color::red() { return Color( 0, 0, 255); } inline cv::viz::Color cv::viz::Color::yellow() { return Color( 0, 255, 255); } inline cv::viz::Color cv::viz::Color::magenta() { return Color(255, 0, 255); } inline cv::viz::Color cv::viz::Color::white() { return Color(255, 255, 255); } inline cv::viz::Color cv::viz::Color::gray() { return Color(128, 128, 128); } +inline cv::viz::Color cv::viz::Color::mlab() { return Color(255, 128, 128); } + +inline cv::viz::Color cv::viz::Color::navy() { return Color(0, 0, 128); } +inline cv::viz::Color cv::viz::Color::olive() { return Color(0, 128, 128); } +inline cv::viz::Color cv::viz::Color::maroon() { return Color(0, 0, 128); } +inline cv::viz::Color cv::viz::Color::teal() { return Color(128, 128, 0); } +inline cv::viz::Color cv::viz::Color::rose() { return Color(128, 0, 255); } +inline cv::viz::Color cv::viz::Color::azure() { return Color(255, 128, 0); } +inline cv::viz::Color cv::viz::Color::lime() { return Color(0, 255, 191); } +inline cv::viz::Color cv::viz::Color::gold() { return Color(0, 215, 255); } +inline cv::viz::Color cv::viz::Color::brown() { return Color(0, 75, 150); } +inline cv::viz::Color cv::viz::Color::orange() { return Color(0, 165, 255); } +inline cv::viz::Color cv::viz::Color::chartreuse() { return Color(0, 255, 128); } +inline cv::viz::Color cv::viz::Color::orange_red() { return Color(0, 69, 255); } +inline cv::viz::Color cv::viz::Color::purple() { return Color(128, 0, 128); } +inline cv::viz::Color cv::viz::Color::indigo() { return Color(130, 0, 75); } + +inline cv::viz::Color cv::viz::Color::pink() { return Color(203, 192, 255); } +inline cv::viz::Color cv::viz::Color::cherry() { return Color( 99, 29, 222); } +inline cv::viz::Color cv::viz::Color::bluberry() { return Color(247, 134, 79); } +inline cv::viz::Color cv::viz::Color::raspberry() { return Color( 92, 11, 227); } +inline cv::viz::Color cv::viz::Color::silver() { return Color(192, 192, 192); } +inline cv::viz::Color cv::viz::Color::violet() { return Color(226, 43, 138); } +inline cv::viz::Color cv::viz::Color::apricot() { return Color(177, 206, 251); } +inline cv::viz::Color cv::viz::Color::turquoise() { return Color(208, 224, 64); } +inline cv::viz::Color cv::viz::Color::celestial_blue() { return Color(208, 151, 73); } +inline cv::viz::Color cv::viz::Color::amethyst() { return Color(204, 102, 153); } + +inline cv::viz::Color cv::viz::Color::not_set() { return Color(-1, -1, -1); } #endif diff --git a/modules/viz/include/opencv2/viz/viz3d.hpp b/modules/viz/include/opencv2/viz/viz3d.hpp index f19709eb5..7cb7d0cea 100644 --- a/modules/viz/include/opencv2/viz/viz3d.hpp +++ b/modules/viz/include/opencv2/viz/viz3d.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_VIZ3D_HPP__ @@ -64,6 +61,7 @@ namespace cv class CV_EXPORTS Viz3d { public: + typedef cv::viz::Color Color; typedef void (*KeyboardCallback)(const KeyboardEvent&, void*); typedef void (*MouseCallback)(const MouseEvent&, void*); @@ -72,19 +70,21 @@ namespace cv Viz3d& operator=(const Viz3d&); ~Viz3d(); - void showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()); + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); void removeWidget(const String &id); Widget getWidget(const String &id) const; void removeAllWidgets(); - void setWidgetPose(const String &id, const Affine3f &pose); - void updateWidgetPose(const String &id, const Affine3f &pose); - Affine3f getWidgetPose(const String &id) const; + void showImage(InputArray image, const Size& window_size = Size(-1, -1)); + + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; void setCamera(const Camera &camera); Camera getCamera() const; - Affine3f getViewerPose(); - void setViewerPose(const Affine3f &pose); + Affine3d getViewerPose(); + void setViewerPose(const Affine3d &pose); void resetCameraViewpoint(const String &id); void resetCamera(); @@ -96,13 +96,16 @@ namespace cv void setWindowSize(const Size &window_size); String getWindowName() const; void saveScreenshot(const String &file); - void setWindowPosition(int x, int y); - void setFullScreen(bool mode); - void setBackgroundColor(const Color& color = Color::black()); + void setWindowPosition(const Point& window_position); + void setFullScreen(bool mode = true); + void setBackgroundColor(const Color& color = Color::black(), const Color& color2 = Color::not_set()); + void setBackgroundTexture(InputArray image = noArray()); + void setBackgroundMeshLab(); void spin(); void spinOnce(int time = 1, bool force_redraw = false); bool wasStopped() const; + void close(); void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); void registerMouseCallback(MouseCallback callback, void* cookie = 0); @@ -110,9 +113,6 @@ namespace cv void setRenderingProperty(const String &id, int property, double value); double getRenderingProperty(const String &id, int property); - void setDesiredUpdateRate(double rate); - double getDesiredUpdateRate(); - void setRepresentation(int representation); private: diff --git a/modules/viz/include/opencv2/viz/widget_accessor.hpp b/modules/viz/include/opencv2/viz/widget_accessor.hpp index 394cfa858..29352a214 100644 --- a/modules/viz/include/opencv2/viz/widget_accessor.hpp +++ b/modules/viz/include/opencv2/viz/widget_accessor.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_WIDGET_ACCESSOR_HPP__ @@ -69,4 +66,4 @@ namespace cv } } -#endif \ No newline at end of file +#endif diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index 07b335899..2c49b9d0e 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_WIDGETS_HPP__ @@ -68,14 +65,14 @@ namespace cv SHADING }; - enum RenderingRepresentationProperties + enum RepresentationValues { REPRESENTATION_POINTS, REPRESENTATION_WIREFRAME, REPRESENTATION_SURFACE }; - enum ShadingRepresentationProperties + enum ShadingValues { SHADING_FLAT, SHADING_GOURAUD, @@ -114,13 +111,15 @@ namespace cv public: Widget3D() {} - void setPose(const Affine3f &pose); - void updatePose(const Affine3f &pose); - Affine3f getPose() const; + //! widget position manipulation, i.e. place where it is rendered + void setPose(const Affine3d &pose); + void updatePose(const Affine3d &pose); + Affine3d getPose() const; + + //! update internal widget data, i.e. points, normals, etc. + void applyTransform(const Affine3d &transform); void setColor(const Color &color); - private: - struct MatrixConverter; }; @@ -134,92 +133,94 @@ namespace cv void setColor(const Color &color); }; + ///////////////////////////////////////////////////////////////////////////// + /// Simple widgets + class CV_EXPORTS WLine : public Widget3D { public: - WLine(const Point3f &pt1, const Point3f &pt2, const Color &color = Color::white()); + WLine(const Point3d &pt1, const Point3d &pt2, const Color &color = Color::white()); }; class CV_EXPORTS WPlane : public Widget3D { public: - WPlane(const Vec4f& coefs, float size = 1.f, const Color &color = Color::white()); - WPlane(const Vec4f& coefs, const Point3f& pt, float size = 1.f, const Color &color = Color::white()); - private: - struct SetSizeImpl; + //! created default plane with center point at origin and normal oriented along z-axis + WPlane(const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); + + //! repositioned plane + WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Size2d& size = Size2d(1.0, 1.0), const Color &color = Color::white()); }; class CV_EXPORTS WSphere : public Widget3D { public: - WSphere(const cv::Point3f ¢er, float radius, int sphere_resolution = 10, const Color &color = Color::white()); + WSphere(const cv::Point3d ¢er, double radius, int sphere_resolution = 10, const Color &color = Color::white()); }; class CV_EXPORTS WArrow : public Widget3D { public: - WArrow(const Point3f& pt1, const Point3f& pt2, float thickness = 0.03f, const Color &color = Color::white()); + WArrow(const Point3d& pt1, const Point3d& pt2, double thickness = 0.03, const Color &color = Color::white()); }; class CV_EXPORTS WCircle : public Widget3D { public: - WCircle(const Point3f& pt, float radius, float thickness = 0.01f, const Color &color = Color::white()); + //! creates default planar circle centred at origin with plane normal along z-axis + WCircle(double radius, double thickness = 0.01, const Color &color = Color::white()); + + //! creates repositioned circle + WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness = 0.01, const Color &color = Color::white()); + }; + + class CV_EXPORTS WCone : public Widget3D + { + public: + //! create default cone, oriented along x-axis with center of its base located at origin + WCone(double length, double radius, int resolution = 6.0, const Color &color = Color::white()); + + //! creates repositioned cone + WCone(double radius, const Point3d& center, const Point3d& tip, int resolution = 6.0, const Color &color = Color::white()); }; class CV_EXPORTS WCylinder : public Widget3D { public: - WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides = 30, const Color &color = Color::white()); + WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides = 30, const Color &color = Color::white()); }; class CV_EXPORTS WCube : public Widget3D { public: - WCube(const Point3f& pt_min, const Point3f& pt_max, bool wire_frame = true, const Color &color = Color::white()); - }; - - class CV_EXPORTS WCoordinateSystem : public Widget3D - { - public: - WCoordinateSystem(float scale = 1.f); + WCube(const Point3d& min_point = Vec3d::all(-0.5), const Point3d& max_point = Vec3d::all(0.5), + bool wire_frame = true, const Color &color = Color::white()); }; class CV_EXPORTS WPolyLine : public Widget3D { public: WPolyLine(InputArray points, const Color &color = Color::white()); - - private: - struct CopyImpl; }; - class CV_EXPORTS WGrid : public Widget3D + ///////////////////////////////////////////////////////////////////////////// + /// Text and image widgets + + class CV_EXPORTS WText : public Widget2D { public: - //! Creates grid at the origin - WGrid(const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()); - //! Creates grid based on the plane equation - WGrid(const Vec4f &coeffs, const Vec2i &dimensions, const Vec2d &spacing, const Color &color = Color::white()); - - private: - struct GridImpl; - - }; - - class CV_EXPORTS WText3D : public Widget3D - { - public: - WText3D(const String &text, const Point3f &position, float text_scale = 1.f, bool face_camera = true, const Color &color = Color::white()); + WText(const String &text, const Point &pos, int font_size = 20, const Color &color = Color::white()); void setText(const String &text); String getText() const; }; - class CV_EXPORTS WText : public Widget2D + class CV_EXPORTS WText3D : public Widget3D { public: - WText(const String &text, const Point2i &pos, int font_size = 10, const Color &color = Color::white()); + //! creates text label in 3D. If face_camera = false, text plane normal is oriented along z-axis. Use widget pose to orient it properly + WText3D(const String &text, const Point3d &position, double text_scale = 1., bool face_camera = true, const Color &color = Color::white()); void setText(const String &text); String getText() const; @@ -228,63 +229,91 @@ namespace cv class CV_EXPORTS WImageOverlay : public Widget2D { public: - WImageOverlay(const Mat &image, const Rect &rect); - - void setImage(const Mat &image); + WImageOverlay(InputArray image, const Rect &rect); + void setImage(InputArray image); }; class CV_EXPORTS WImage3D : public Widget3D { public: - //! Creates 3D image at the origin - WImage3D(const Mat &image, const Size &size); - //! Creates 3D image at a given position, pointing in the direction of the normal, and having the up_vector orientation - WImage3D(const Vec3f &position, const Vec3f &normal, const Vec3f &up_vector, const Mat &image, const Size &size); + //! Creates 3D image in a plane centered at the origin with normal orientaion along z-axis, + //! image x- and y-axes are oriented along x- and y-axes of 3d world + WImage3D(InputArray image, const Size2d &size); - void setImage(const Mat &image); + //! Creates 3D image at a given position, pointing in the direction of the normal, and having the up_vector orientation + WImage3D(InputArray image, const Size2d &size, const Vec3d ¢er, const Vec3d &normal, const Vec3d &up_vector); + + void setImage(InputArray image); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Compond widgets + + class CV_EXPORTS WCoordinateSystem : public Widget3D + { + public: + WCoordinateSystem(double scale = 1.0); + }; + + class CV_EXPORTS WGrid : public Widget3D + { + public: + //! Creates grid at the origin and normal oriented along z-axis + WGrid(const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); + + //! Creates repositioned grid + WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, + const Vec2i &cells = Vec2i::all(10), const Vec2d &cells_spacing = Vec2d::all(1.0), const Color &color = Color::white()); }; class CV_EXPORTS WCameraPosition : public Widget3D { public: //! Creates camera coordinate frame (axes) at the origin - WCameraPosition(float scale = 1.f); + WCameraPosition(double scale = 1.0); //! Creates frustum based on the intrinsic marix K at the origin - WCameraPosition(const Matx33f &K, float scale = 1.f, const Color &color = Color::white()); + WCameraPosition(const Matx33d &K, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum based on the field of view at the origin - WCameraPosition(const Vec2f &fov, float scale = 1.f, const Color &color = Color::white()); + WCameraPosition(const Vec2d &fov, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Matx33f &K, const Mat &img, float scale = 1.f, const Color &color = Color::white()); + WCameraPosition(const Matx33d &K, InputArray image, double scale = 1.0, const Color &color = Color::white()); //! Creates frustum and display given image at the far plane - WCameraPosition(const Vec2f &fov, const Mat &img, float scale = 1.f, const Color &color = Color::white()); - - private: - struct ProjectImage; + WCameraPosition(const Vec2d &fov, InputArray image, double scale = 1.0, const Color &color = Color::white()); }; + ///////////////////////////////////////////////////////////////////////////// + /// Trajectories + class CV_EXPORTS WTrajectory : public Widget3D { public: - enum {DISPLAY_FRAMES = 1, DISPLAY_PATH = 2}; + enum {FRAMES = 1, PATH = 2, BOTH = FRAMES + PATH }; - //! Displays trajectory of the given path either by coordinate frames or polyline - WTrajectory(const std::vector &path, int display_mode = WTrajectory::DISPLAY_PATH, const Color &color = Color::white(), float scale = 1.f); - //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Matx33f &K, float scale = 1.f, const Color &color = Color::white()); - //! Displays trajectory of the given path by frustums - WTrajectory(const std::vector &path, const Vec2f &fov, float scale = 1.f, const Color &color = Color::white()); - - private: - struct ApplyPath; + //! Takes vector> and displays trajectory of the given path either by coordinate frames or polyline + WTrajectory(InputArray path, int display_mode = WTrajectory::PATH, double scale = 1.0, const Color &color = Color::white()); }; - class CV_EXPORTS WSpheresTrajectory: public Widget3D + class CV_EXPORTS WTrajectoryFrustums : public Widget3D { public: - WSpheresTrajectory(const std::vector &path, float line_length = 0.05f, float init_sphere_radius = 0.021f, - float sphere_radius = 0.007f, const Color &line_color = Color::white(), const Color &sphere_color = Color::white()); + //! Takes vector> and displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Matx33d &K, double scale = 1., const Color &color = Color::white()); + + //! Takes vector> and displays trajectory of the given path by frustums + WTrajectoryFrustums(InputArray path, const Vec2d &fov, double scale = 1., const Color &color = Color::white()); }; + class CV_EXPORTS WTrajectorySpheres: public Widget3D + { + public: + //! Takes vector> and displays trajectory of the given path + WTrajectorySpheres(InputArray path, double line_length = 0.05, double radius = 0.007, + const Color &from = Color::red(), const Color &to = Color::white()); + }; + + ///////////////////////////////////////////////////////////////////////////// + /// Clouds + class CV_EXPORTS WCloud: public Widget3D { public: @@ -292,9 +321,19 @@ namespace cv WCloud(InputArray cloud, InputArray colors); //! All points in cloud have the same color WCloud(InputArray cloud, const Color &color = Color::white()); + }; - private: - struct CreateCloudWidget; + 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 @@ -303,32 +342,27 @@ namespace cv WCloudCollection(); //! Each point in cloud is mapped to a color in colors - void addCloud(InputArray cloud, InputArray colors, const Affine3f &pose = Affine3f::Identity()); + void addCloud(InputArray cloud, InputArray colors, const Affine3d &pose = Affine3d::Identity()); //! All points in cloud have the same color - void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3f &pose = Affine3f::Identity()); - - private: - struct CreateCloudWidget; + void addCloud(InputArray cloud, const Color &color = Color::white(), const Affine3d &pose = Affine3d::Identity()); }; class CV_EXPORTS WCloudNormals : public Widget3D { public: - WCloudNormals(InputArray cloud, InputArray normals, int level = 100, float scale = 0.02f, const Color &color = Color::white()); - - private: - struct ApplyCloudNormals; + WCloudNormals(InputArray cloud, InputArray normals, int level = 64, double scale = 0.1, const Color &color = Color::white()); }; class CV_EXPORTS WMesh : public Widget3D { public: - WMesh(const Mesh3d &mesh); - - private: - struct CopyImpl; + WMesh(const Mesh &mesh); + WMesh(InputArray cloud, InputArray polygons, InputArray colors = noArray(), InputArray normals = noArray()); }; + ///////////////////////////////////////////////////////////////////////////// + /// Utility exports + template<> CV_EXPORTS Widget2D Widget::cast(); template<> CV_EXPORTS Widget3D Widget::cast(); template<> CV_EXPORTS WLine Widget::cast(); @@ -337,6 +371,7 @@ namespace cv template<> CV_EXPORTS WCylinder Widget::cast(); template<> CV_EXPORTS WArrow Widget::cast(); template<> CV_EXPORTS WCircle Widget::cast(); + template<> CV_EXPORTS WCone Widget::cast(); template<> CV_EXPORTS WCube Widget::cast(); template<> CV_EXPORTS WCoordinateSystem Widget::cast(); template<> CV_EXPORTS WPolyLine Widget::cast(); @@ -347,8 +382,10 @@ namespace cv template<> CV_EXPORTS WImage3D Widget::cast(); template<> CV_EXPORTS WCameraPosition Widget::cast(); template<> CV_EXPORTS WTrajectory Widget::cast(); - template<> CV_EXPORTS WSpheresTrajectory Widget::cast(); + 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/cloud_widgets.cpp b/modules/viz/src/cloud_widgets.cpp deleted file mode 100644 index 73cc26201..000000000 --- a/modules/viz/src/cloud_widgets.cpp +++ /dev/null @@ -1,773 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -// Authors: -// * Ozan Tonkal, ozantonkal@gmail.com -// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com -// -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// -//M*/ - -#include "precomp.hpp" - -namespace cv -{ - namespace viz - { - template Vec<_Tp, 3>* vtkpoints_data(vtkSmartPointer& points); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// Point Cloud Widget implementation - -struct cv::viz::WCloud::CreateCloudWidget -{ - static inline vtkSmartPointer create(const Mat &cloud, vtkIdType &nr_points) - { - vtkSmartPointer polydata = vtkSmartPointer::New(); - vtkSmartPointer vertices = vtkSmartPointer::New(); - - polydata->SetVerts(vertices); - - vtkSmartPointer points = polydata->GetPoints(); - vtkSmartPointer initcells; - nr_points = cloud.total(); - - 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); - - 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); - 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); - nr_points = data_end - data_beg; - } - points->SetNumberOfPoints(nr_points); - - // Update cells - vtkSmartPointer cells = vertices->GetData(); - // If no init cells and cells has not been initialized... - if (!cells) - cells = vtkSmartPointer::New(); - - // If we have less values then we need to recreate the array - if (cells->GetNumberOfTuples() < nr_points) - { - cells = vtkSmartPointer::New(); - - // If init cells is given, and there's enough data in it, use it - if (initcells && initcells->GetNumberOfTuples() >= nr_points) - { - cells->DeepCopy(initcells); - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - else - { - // If the number of tuples is still too small, we need to recreate the array - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - vtkIdType *cell = cells->GetPointer(0); - // Fill it with 1s - std::fill_n(cell, nr_points * 2, 1); - cell++; - for (vtkIdType i = 0; i < nr_points; ++i, cell += 2) - *cell = i; - // Save the results in initcells - initcells = vtkSmartPointer::New(); - initcells->DeepCopy(cells); - } - } - else - { - // The assumption here is that the current set of cells has more data than needed - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - - // Set the cells and the vertices - vertices->SetCells(nr_points, cells); - return polydata; - } -}; - -cv::viz::WCloud::WCloud(InputArray _cloud, InputArray _colors) -{ - 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()); - - if (cloud.isContinuous() && colors.isContinuous()) - { - cloud.reshape(cloud.channels(), 1); - colors.reshape(colors.channels(), 1); - } - - vtkIdType nr_points; - vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); - - // Filter colors - Vec3b* colors_data = new Vec3b[nr_points]; - NanFilter::copyColor(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 - polydata->GetPointData()->SetScalars(scalars); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(polydata); -#else - mapper->SetInputData(polydata); -#endif - - Vec3d minmax(scalars->GetRange()); - mapper->SetScalarRange(minmax.val); - mapper->SetScalarModeToUsePointData(); - - bool interpolation = (polydata && polydata->GetNumberOfCells() != polydata->GetNumberOfVerts()); - - mapper->SetInterpolateScalarsBeforeMapping(interpolation); - mapper->ScalarVisibilityOn(); - - mapper->ImmediateModeRenderingOff(); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetNumberOfCloudPoints(int(std::max(1, polydata->GetNumberOfPoints() / 10))); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -cv::viz::WCloud::WCloud(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); - - vtkIdType nr_points; - vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(polydata); -#else - mapper->SetInputData(polydata); -#endif - - bool interpolation = (polydata && polydata->GetNumberOfCells() != polydata->GetNumberOfVerts()); - - mapper->SetInterpolateScalarsBeforeMapping(interpolation); - mapper->ScalarVisibilityOff(); - - mapper->ImmediateModeRenderingOff(); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetNumberOfCloudPoints(int(std::max(1, polydata->GetNumberOfPoints() / 10))); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WCloud cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// Cloud Collection Widget implementation - -struct cv::viz::WCloudCollection::CreateCloudWidget -{ - static inline vtkSmartPointer create(const Mat &cloud, vtkIdType &nr_points) - { - vtkSmartPointer polydata = vtkSmartPointer::New(); - vtkSmartPointer vertices = vtkSmartPointer::New(); - - polydata->SetVerts(vertices); - - vtkSmartPointer points = polydata->GetPoints(); - vtkSmartPointer initcells; - nr_points = cloud.total(); - - 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); - - 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); - 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); - nr_points = data_end - data_beg; - } - points->SetNumberOfPoints(nr_points); - - // Update cells - vtkSmartPointer cells = vertices->GetData(); - // If no init cells and cells has not been initialized... - if (!cells) - cells = vtkSmartPointer::New(); - - // If we have less values then we need to recreate the array - if (cells->GetNumberOfTuples() < nr_points) - { - cells = vtkSmartPointer::New(); - - // If init cells is given, and there's enough data in it, use it - if (initcells && initcells->GetNumberOfTuples() >= nr_points) - { - cells->DeepCopy(initcells); - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - else - { - // If the number of tuples is still too small, we need to recreate the array - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - vtkIdType *cell = cells->GetPointer(0); - // Fill it with 1s - std::fill_n(cell, nr_points * 2, 1); - cell++; - for (vtkIdType i = 0; i < nr_points; ++i, cell += 2) - *cell = i; - // Save the results in initcells - initcells = vtkSmartPointer::New(); - initcells->DeepCopy(cells); - } - } - else - { - // The assumption here is that the current set of cells has more data than needed - cells->SetNumberOfComponents(2); - cells->SetNumberOfTuples(nr_points); - } - - // Set the cells and the vertices - vertices->SetCells(nr_points, cells); - return polydata; - } - - static void createMapper(vtkSmartPointer actor, vtkSmartPointer poly_data, Vec3d& minmax) - { - vtkDataSetMapper *mapper = vtkDataSetMapper::SafeDownCast(actor->GetMapper()); - if (!mapper) - { - // This is the first cloud - vtkSmartPointer mapper_new = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper_new->SetInputConnection(poly_data->GetProducerPort()); -#else - mapper_new->SetInputData(poly_data); -#endif - - mapper_new->SetScalarRange(minmax.val); - mapper_new->SetScalarModeToUsePointData(); - - bool interpolation = (poly_data && poly_data->GetNumberOfCells() != poly_data->GetNumberOfVerts()); - - mapper_new->SetInterpolateScalarsBeforeMapping(interpolation); - mapper_new->ScalarVisibilityOn(); - mapper_new->ImmediateModeRenderingOff(); - - actor->SetNumberOfCloudPoints(int(std::max(1, poly_data->GetNumberOfPoints() / 10))); - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper_new); - return ; - } - - vtkPolyData *data = vtkPolyData::SafeDownCast(mapper->GetInput()); - CV_Assert("Cloud Widget without data" && data); - - vtkSmartPointer appendFilter = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - appendFilter->AddInputConnection(mapper->GetInput()->GetProducerPort()); - appendFilter->AddInputConnection(poly_data->GetProducerPort()); -#else - appendFilter->AddInputData(data); - appendFilter->AddInputData(poly_data); -#endif - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - // Update the number of cloud points - vtkIdType old_cloud_points = actor->GetNumberOfCloudPoints(); - actor->SetNumberOfCloudPoints(int(std::max(1, old_cloud_points+poly_data->GetNumberOfPoints() / 10))); - } -}; - -cv::viz::WCloudCollection::WCloudCollection() -{ - // Just create the actor - vtkSmartPointer actor = vtkSmartPointer::New(); - WidgetAccessor::setProp(*this, actor); -} - -void cv::viz::WCloudCollection::addCloud(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()); - - if (cloud.isContinuous() && colors.isContinuous()) - { - cloud.reshape(cloud.channels(), 1); - colors.reshape(colors.channels(), 1); - } - - vtkIdType nr_points; - vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); - - // Filter colors - Vec3b* colors_data = new Vec3b[nr_points]; - NanFilter::copyColor(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 - polydata->GetPointData()->SetScalars(scalars); - - // Transform the poly data based on the pose - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(convertToVtkMatrix(pose.matrix)); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); -#if VTK_MAJOR_VERSION <= 5 - transform_filter->SetInputConnection(polydata->GetProducerPort()); -#else - transform_filter->SetInputData(polydata); -#endif - transform_filter->Update(); - - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("Incompatible widget type." && actor); - - Vec3d minmax(scalars->GetRange()); - CreateCloudWidget::createMapper(actor, transform_filter->GetOutput(), minmax); -} - -void cv::viz::WCloudCollection::addCloud(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); - - vtkIdType nr_points; - vtkSmartPointer polydata = CreateCloudWidget::create(cloud, nr_points); - - vtkSmartPointer scalars = vtkSmartPointer::New(); - scalars->SetNumberOfComponents(3); - scalars->SetNumberOfTuples(nr_points); - scalars->FillComponent(0, color[2]); - scalars->FillComponent(1, color[1]); - scalars->FillComponent(2, color[0]); - - // Assign the colors - polydata->GetPointData()->SetScalars(scalars); - - // Transform the poly data based on the pose - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(convertToVtkMatrix(pose.matrix)); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); -#if VTK_MAJOR_VERSION <= 5 - transform_filter->SetInputConnection(polydata->GetProducerPort()); -#else - transform_filter->SetInputData(polydata); -#endif - transform_filter->Update(); - - vtkLODActor *actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("Incompatible widget type." && actor); - - Vec3d minmax(scalars->GetRange()); - CreateCloudWidget::createMapper(actor, transform_filter->GetOutput(), minmax); -} - -template<> cv::viz::WCloudCollection cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// Cloud Normals Widget implementation - -struct cv::viz::WCloudNormals::ApplyCloudNormals -{ - template - struct Impl - { - static vtkSmartPointer applyOrganized(const Mat &cloud, const Mat& normals, double level, float scale, _Tp *&pts, vtkIdType &nr_normals) - { - vtkIdType point_step = static_cast(std::sqrt(level)); - nr_normals = (static_cast((cloud.cols - 1) / point_step) + 1) * - (static_cast((cloud.rows - 1) / point_step) + 1); - vtkSmartPointer lines = vtkSmartPointer::New(); - - pts = new _Tp[2 * nr_normals * 3]; - - int cch = cloud.channels(); - vtkIdType cell_count = 0; - for (vtkIdType y = 0; y < cloud.rows; y += point_step) - { - const _Tp *prow = cloud.ptr<_Tp>(y); - const _Tp *nrow = normals.ptr<_Tp>(y); - for (vtkIdType x = 0; x < cloud.cols; x += point_step * cch) - { - pts[2 * cell_count * 3 + 0] = prow[x]; - pts[2 * cell_count * 3 + 1] = prow[x+1]; - pts[2 * cell_count * 3 + 2] = prow[x+2]; - pts[2 * cell_count * 3 + 3] = prow[x] + nrow[x] * scale; - pts[2 * cell_count * 3 + 4] = prow[x+1] + nrow[x+1] * scale; - pts[2 * cell_count * 3 + 5] = prow[x+2] + nrow[x+2] * scale; - - lines->InsertNextCell(2); - lines->InsertCellPoint(2 * cell_count); - lines->InsertCellPoint(2 * cell_count + 1); - cell_count++; - } - } - return lines; - } - - static vtkSmartPointer applyUnorganized(const Mat &cloud, const Mat& normals, int level, float scale, _Tp *&pts, vtkIdType &nr_normals) - { - vtkSmartPointer lines = vtkSmartPointer::New(); - nr_normals = (cloud.size().area() - 1) / level + 1 ; - pts = new _Tp[2 * nr_normals * 3]; - - int cch = cloud.channels(); - const _Tp *p = cloud.ptr<_Tp>(); - const _Tp *n = normals.ptr<_Tp>(); - for (vtkIdType i = 0, j = 0; j < nr_normals; j++, i = j * level * cch) - { - - pts[2 * j * 3 + 0] = p[i]; - pts[2 * j * 3 + 1] = p[i+1]; - pts[2 * j * 3 + 2] = p[i+2]; - pts[2 * j * 3 + 3] = p[i] + n[i] * scale; - pts[2 * j * 3 + 4] = p[i+1] + n[i+1] * scale; - pts[2 * j * 3 + 5] = p[i+2] + n[i+2] * scale; - - lines->InsertNextCell(2); - lines->InsertCellPoint(2 * j); - lines->InsertCellPoint(2 * j + 1); - } - return lines; - } - }; - - template - static inline vtkSmartPointer apply(const Mat &cloud, const Mat& normals, int level, float scale, _Tp *&pts, vtkIdType &nr_normals) - { - if (cloud.cols > 1 && cloud.rows > 1) - return ApplyCloudNormals::Impl<_Tp>::applyOrganized(cloud, normals, level, scale, pts, nr_normals); - else - return ApplyCloudNormals::Impl<_Tp>::applyUnorganized(cloud, normals, level, scale, pts, nr_normals); - } -}; - -cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, float scale, const Color &color) -{ - Mat cloud = _cloud.getMat(); - 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; - - if (cloud.depth() == CV_32F) - { - points->SetDataTypeToFloat(); - - vtkSmartPointer data = vtkSmartPointer::New(); - data->SetNumberOfComponents(3); - - float* pts = 0; - lines = ApplyCloudNormals::apply(cloud, normals, level, scale, pts, nr_normals); - data->SetArray(&pts[0], 2 * nr_normals * 3, 0); - points->SetData(data); - } - else - { - points->SetDataTypeToDouble(); - - vtkSmartPointer data = vtkSmartPointer::New(); - data->SetNumberOfComponents(3); - - double* pts = 0; - lines = ApplyCloudNormals::apply(cloud, normals, level, scale, pts, nr_normals); - 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(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(polyData); -#else - mapper->SetInputData(polyData); -#endif - mapper->SetColorModeToMapScalars(); - mapper->SetScalarModeToUsePointData(); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WCloudNormals cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// Mesh Widget implementation - -struct cv::viz::WMesh::CopyImpl -{ - template - static Vec<_Tp, 3> * copy(const Mat &source, Vec<_Tp, 3> *output, int *look_up, const Mat &nan_mask) - { - CV_Assert(DataDepth<_Tp>::value == source.depth() && source.size() == nan_mask.size()); - CV_Assert(nan_mask.channels() == 3 || nan_mask.channels() == 4); - CV_DbgAssert(DataDepth<_Tp>::value == nan_mask.depth()); - - int s_chs = source.channels(); - int m_chs = nan_mask.channels(); - - int index = 0; - const _Tp* srow = source.ptr<_Tp>(0); - const _Tp* mrow = nan_mask.ptr<_Tp>(0); - - for (int x = 0; x < source.cols; ++x, srow += s_chs, mrow += m_chs) - { - if (!isNan(mrow[0]) && !isNan(mrow[1]) && !isNan(mrow[2])) - { - look_up[x] = index; - *output++ = Vec<_Tp, 3>(srow); - ++index; - } - } - return output; - } -}; - -cv::viz::WMesh::WMesh(const Mesh3d &mesh) -{ - CV_Assert(mesh.cloud.rows == 1 && (mesh.cloud.type() == CV_32FC3 || mesh.cloud.type() == CV_64FC3 || mesh.cloud.type() == CV_32FC4 || mesh.cloud.type() == CV_64FC4)); - CV_Assert(mesh.colors.empty() || (mesh.colors.type() == CV_8UC3 && mesh.cloud.size() == mesh.colors.size())); - CV_Assert(!mesh.polygons.empty() && mesh.polygons.type() == CV_32SC1); - - vtkSmartPointer points = vtkSmartPointer::New(); - vtkIdType nr_points = mesh.cloud.total(); - Mat look_up_mat(1, nr_points, CV_32SC1); - int * look_up = look_up_mat.ptr(); - points->SetNumberOfPoints(nr_points); - - // Copy data from cloud to vtkPoints - if (mesh.cloud.depth() == CV_32F) - { - points->SetDataTypeToFloat(); - Vec3f *data_beg = vtkpoints_data(points); - Vec3f *data_end = CopyImpl::copy(mesh.cloud, data_beg, look_up, mesh.cloud); - nr_points = data_end - data_beg; - } - else - { - points->SetDataTypeToDouble(); - Vec3d *data_beg = vtkpoints_data(points); - Vec3d *data_end = CopyImpl::copy(mesh.cloud, data_beg, look_up, mesh.cloud); - nr_points = data_end - data_beg; - } - - vtkSmartPointer scalars; - - if (!mesh.colors.empty()) - { - Vec3b * colors_data = 0; - colors_data = new Vec3b[nr_points]; - NanFilter::copyColor(mesh.colors, colors_data, mesh.cloud); - - scalars = vtkSmartPointer::New(); - scalars->SetNumberOfComponents(3); - scalars->SetNumberOfTuples(nr_points); - scalars->SetArray(colors_data->val, 3 * nr_points, 0); - } - - points->SetNumberOfPoints(nr_points); - - vtkSmartPointer data; - - if (mesh.polygons.size().area() > 1) - { - vtkSmartPointer cell_array = vtkSmartPointer::New(); - const int * polygons = mesh.polygons.ptr(); - - int idx = 0; - int poly_size = mesh.polygons.total(); - for (int i = 0; i < poly_size; ++idx) - { - int n_points = polygons[i++]; - - cell_array->InsertNextCell(n_points); - for (int j = 0; j < n_points; ++j, ++idx) - cell_array->InsertCellPoint(look_up[polygons[i++]]); - } - vtkSmartPointer polydata = vtkSmartPointer::New(); - cell_array->GetData()->SetNumberOfValues(idx); - cell_array->Squeeze(); - polydata->SetStrips(cell_array); - polydata->SetPoints(points); - - if (scalars) - polydata->GetPointData()->SetScalars(scalars); - - data = polydata; - } - else - { - // Only one polygon - vtkSmartPointer polygon = vtkSmartPointer::New(); - const int * polygons = mesh.polygons.ptr(); - int n_points = polygons[0]; - - polygon->GetPointIds()->SetNumberOfIds(n_points); - - for (int j = 1; j < n_points+1; ++j) - polygon->GetPointIds()->SetId(j, look_up[polygons[j]]); - - vtkSmartPointer poly_grid = vtkSmartPointer::New(); - poly_grid->Allocate(1, 1); - poly_grid->InsertNextCell(polygon->GetCellType(), polygon->GetPointIds()); - poly_grid->SetPoints(points); - - if (scalars) - poly_grid->GetPointData()->SetScalars(scalars); - - data = poly_grid; - } - - vtkSmartPointer actor = vtkSmartPointer::New(); - - actor->GetProperty()->SetRepresentationToSurface(); - actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency - actor->GetProperty()->SetInterpolationToFlat(); - actor->GetProperty()->EdgeVisibilityOff(); - actor->GetProperty()->ShadingOff(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(data); -#else - mapper->SetInputData(data); -#endif - mapper->ImmediateModeRenderingOff(); - - vtkIdType numberOfCloudPoints = nr_points * 0.1; - actor->SetNumberOfCloudPoints(int(numberOfCloudPoints > 1 ? numberOfCloudPoints : 1)); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} diff --git a/modules/viz/src/clouds.cpp b/modules/viz/src/clouds.cpp new file mode 100644 index 000000000..4b84e8e9e --- /dev/null +++ b/modules/viz/src/clouds.cpp @@ -0,0 +1,441 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Point Cloud Widget implementation + +cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors) +{ + CV_Assert(!cloud.empty() && !colors.empty()); + + vtkSmartPointer cloud_source = vtkSmartPointer::New(); + cloud_source->SetColorCloud(cloud, colors); + cloud_source->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cloud_source->GetOutput()); + 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); +} + +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()); + + vtkSmartPointer elevation = vtkSmartPointer::New(); + elevation->SetInputConnection(cloud_source->GetOutputPort()); + elevation->SetLowPoint(bounds[0], bounds[2], bounds[4]); + elevation->SetHighPoint(bounds[1], bounds[3], bounds[5]); + elevation->SetScalarRange(0.0, 1.0); + elevation->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +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, vtkPolyData::SafeDownCast(elevation->GetOutput())); + mapper->ImmediateModeRenderingOff(); + mapper->ScalarVisibilityOn(); + mapper->SetColorModeToMapScalars(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +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); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Cloud Collection Widget implementation + +cv::viz::WCloudCollection::WCloudCollection() +{ + // Just create the actor + vtkSmartPointer actor = vtkSmartPointer::New(); + WidgetAccessor::setProp(*this, actor); +} + +void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloud(cloud, colors); + + 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) + { + // This is the first cloud + mapper = vtkSmartPointer::New(); + mapper->SetScalarRange(0, 255); + mapper->SetScalarModeToUsePointData(); + mapper->ScalarVisibilityOn(); + mapper->ImmediateModeRenderingOff(); + VtkUtils::SetInputData(mapper, polydata); + + actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints()/10)); + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->BackfaceCullingOn(); + actor->SetMapper(mapper); + return; + } + + vtkPolyData *currdata = vtkPolyData::SafeDownCast(mapper->GetInput()); + CV_Assert("Cloud Widget without data" && currdata); + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + VtkUtils::AddInputData(append_filter, currdata); + VtkUtils::AddInputData(append_filter, polydata); + append_filter->Update(); + + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + + actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10)); +} + +void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose) +{ + addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose); +} + +template<> cv::viz::WCloudCollection cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Cloud Normals Widget implementation + +cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color) +{ + Mat cloud = _cloud.getMat(); + 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()); + + int sqlevel = (int)std::sqrt((double)level); + int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1; + int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level; + + vtkSmartPointer points = vtkSmartPointer::New(); + points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE); + + vtkSmartPointer lines = vtkSmartPointer::New(); + + int s_chs = cloud.channels(); + int n_chs = normals.channels(); + int total = 0; + + for(int y = 0; y < cloud.rows; y += ystep) + { + if (cloud.depth() == CV_32F) + { + const float *srow = cloud.ptr(y); + const float *send = srow + cloud.cols * s_chs; + const float *nrow = normals.ptr(y); + + for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) + if (!isNan(srow) && !isNan(nrow)) + { + Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale; + + points->InsertNextPoint(srow); + points->InsertNextPoint(endp.val); + + lines->InsertNextCell(2); + lines->InsertCellPoint(total++); + lines->InsertCellPoint(total++); + } + } + else + { + const double *srow = cloud.ptr(y); + const double *send = srow + cloud.cols * s_chs; + const double *nrow = normals.ptr(y); + + for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) + if (!isNan(srow) && !isNan(nrow)) + { + Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale; + + points->InsertNextPoint(srow); + points->InsertNextPoint(endp.val); + + lines->InsertNextCell(2); + lines->InsertCellPoint(total++); + lines->InsertCellPoint(total++); + } + } + } + + vtkSmartPointer polyData = vtkSmartPointer::New(); + polyData->SetPoints(points); + polyData->SetLines(lines); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetColorModeToMapScalars(); + mapper->SetScalarModeToUsePointData(); + 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() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Mesh Widget implementation + +cv::viz::WMesh::WMesh(const Mesh &mesh) +{ + CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords); + source->Update(); + + Mat lookup_buffer(1, mesh.cloud.total(), CV_32SC1); + int *lookup = lookup_buffer.ptr(); + for(int y = 0, index = 0; y < mesh.cloud.rows; ++y) + { + int s_chs = mesh.cloud.channels(); + + if (mesh.cloud.depth() == CV_32F) + { + const float* srow = mesh.cloud.ptr(y); + const float* send = srow + mesh.cloud.cols * s_chs; + + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; + } + + if (mesh.cloud.depth() == CV_64F) + { + const double* srow = mesh.cloud.ptr(y); + const double* send = srow + mesh.cloud.cols * s_chs; + + for (; srow != send; srow += s_chs, ++lookup) + if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) + *lookup = index++; + } + } + lookup = lookup_buffer.ptr(); + + vtkSmartPointer polydata = source->GetOutput(); + polydata->SetVerts(0); + + const int * polygons = mesh.polygons.ptr(); + vtkSmartPointer cell_array = vtkSmartPointer::New(); + + int idx = 0; + size_t polygons_size = mesh.polygons.total(); + for (size_t i = 0; i < polygons_size; ++idx) + { + int n_points = polygons[i++]; + + cell_array->InsertNextCell(n_points); + for (int j = 0; j < n_points; ++j, ++idx) + cell_array->InsertCellPoint(lookup[polygons[i++]]); + } + cell_array->GetData()->SetNumberOfValues(idx); + cell_array->Squeeze(); + polydata->SetStrips(cell_array); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUsePointData(); + mapper->ImmediateModeRenderingOff(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10)); + actor->GetProperty()->SetRepresentationToSurface(); + actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency + actor->GetProperty()->SetInterpolationToFlat(); + actor->GetProperty()->EdgeVisibilityOff(); + actor->GetProperty()->ShadingOff(); + actor->SetMapper(mapper); + + if (!mesh.texture.empty()) + { + vtkSmartPointer image_source = vtkSmartPointer::New(); + image_source->SetImage(mesh.texture); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_source->GetOutputPort()); + actor->SetTexture(texture); + } + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WMesh::WMesh(InputArray cloud, InputArray polygons, InputArray colors, InputArray normals) +{ + Mesh mesh; + mesh.cloud = cloud.getMat(); + mesh.colors = colors.getMat(); + mesh.normals = normals.getMat(); + mesh.polygons = polygons.getMat(); + *this = WMesh(mesh); +} + +template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/interactor_style.cpp b/modules/viz/src/interactor_style.cpp index ccf188ded..75003a2b6 100644 --- a/modules/viz/src/interactor_style.cpp +++ b/modules/viz/src/interactor_style.cpp @@ -48,20 +48,21 @@ #include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(InteractorStyle) +}} + + ////////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::InteractorStyle::Initialize() { - modifier_ = cv::viz::InteractorStyle::KB_MOD_ALT; // Set windows size (width, height) to unknown (-1) win_size_ = Vec2i(-1, -1); win_pos_ = Vec2i(0, 0); max_win_size_ = Vec2i(-1, -1); - // Create the image filter and PNG writer objects - wif_ = vtkSmartPointer::New(); - snapshot_writer_ = vtkSmartPointer::New(); - snapshot_writer_->SetInputConnection(wif_->GetOutputPort()); - init_ = true; stereo_anaglyph_mask_default_ = true; @@ -78,11 +79,37 @@ void cv::viz::InteractorStyle::Initialize() void cv::viz::InteractorStyle::saveScreenshot(const String &file) { FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); - wif_->SetInput(Interactor->GetRenderWindow()); - wif_->Modified(); // Update the WindowToImageFilter - snapshot_writer_->Modified(); - snapshot_writer_->SetFileName(file.c_str()); - snapshot_writer_->Write(); + + vtkSmartPointer wif = vtkSmartPointer::New(); + wif->SetInput(Interactor->GetRenderWindow()); + + vtkSmartPointer snapshot_writer = vtkSmartPointer::New(); + snapshot_writer->SetInputConnection(wif->GetOutputPort()); + snapshot_writer->SetFileName(file.c_str()); + snapshot_writer->Write(); + + cout << "Screenshot successfully captured (" << file.c_str() << ")" << endl; +} + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::InteractorStyle::exportScene(const String &file) +{ + vtkSmartPointer exporter; + if (file.size() > 5 && file.substr(file.size() - 5) == ".vrml") + { + exporter = vtkSmartPointer::New(); + vtkVRMLExporter::SafeDownCast(exporter)->SetFileName(file.c_str()); + } + else + { + exporter = vtkSmartPointer::New(); + vtkOBJExporter::SafeDownCast(exporter)->SetFilePrefix(file.c_str()); + } + + exporter->SetInput(Interactor->GetRenderWindow()); + exporter->Write(); + + cout << "Scene successfully exported (" << file.c_str() << ")" << endl; } ////////////////////////////////////////////////////////////////////////////////////////////// @@ -121,13 +148,7 @@ void cv::viz::InteractorStyle::OnChar() else if (key.find("XF86ZoomOut") != String::npos) zoomOut(); - int keymod = false; - switch (modifier_) - { - case KB_MOD_ALT: keymod = Interactor->GetAltKey(); break; - case KB_MOD_CTRL: keymod = Interactor->GetControlKey(); break; - case KB_MOD_SHIFT: keymod = Interactor->GetShiftKey(); break; - } + int keymod = Interactor->GetAltKey(); switch (Interactor->GetKeyCode()) { @@ -180,43 +201,32 @@ void cv::viz::InteractorStyle::registerKeyboardCallback(void (*callback)(const K } ////////////////////////////////////////////////////////////////////////////////////////////// -bool cv::viz::InteractorStyle::getAltKey() { return Interactor->GetAltKey() != 0; } -bool cv::viz::InteractorStyle::getShiftKey() { return Interactor->GetShiftKey()!= 0; } -bool cv::viz::InteractorStyle::getControlKey() { return Interactor->GetControlKey()!= 0; } +int cv::viz::InteractorStyle::getModifiers() +{ + int modifiers = KeyboardEvent::NONE; + + if (Interactor->GetAltKey()) + modifiers |= KeyboardEvent::ALT; + + if (Interactor->GetControlKey()) + modifiers |= KeyboardEvent::CTRL; + + if (Interactor->GetShiftKey()) + modifiers |= KeyboardEvent::SHIFT; + return modifiers; +} ////////////////////////////////////////////////////////////////////////////////////////////// -void -cv::viz::InteractorStyle::OnKeyDown() +void cv::viz::InteractorStyle::OnKeyDown() { CV_Assert("Interactor style not initialized. Please call Initialize() before continuing" && init_); - CV_Assert("No renderer given! Use SetRendererCollection() before continuing." && renderer_); - FindPokedRenderer(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1]); - if (wif_->GetInput() == NULL) - { - wif_->SetInput(Interactor->GetRenderWindow()); - wif_->Modified(); - snapshot_writer_->Modified(); - } - // Save the initial windows width/height if (win_size_[0] == -1 || win_size_[1] == -1) win_size_ = Vec2i(Interactor->GetRenderWindow()->GetSize()); - - // Get the status of special keys (Cltr+Alt+Shift) - bool shift = getShiftKey(); - bool ctrl = getControlKey(); - bool alt = getAltKey(); - - bool keymod = false; - switch (modifier_) - { - case KB_MOD_ALT: keymod = alt; break; - case KB_MOD_CTRL: keymod = ctrl; break; - case KB_MOD_SHIFT: keymod = shift; break; - } + bool alt = Interactor->GetAltKey() != 0; std::string key(Interactor->GetKeySym()); if (key.find("XF86ZoomIn") != std::string::npos) @@ -235,8 +245,10 @@ cv::viz::InteractorStyle::OnKeyDown() " s, S : switch to a surface-based representation (where available)\n" "\n" " j, J : take a .PNG snapshot of the current window view\n" + " k, K : export scene to Wavefront .obj format\n" + " ALT + k, K : export scene to VRML format\n" " c, C : display current camera/window parameters\n" - " f, F : fly to point mode\n" + " f, F : fly to point mode, hold the key and move mouse where to fly\n" "\n" " e, E : exit the interactor\n" " q, Q : stop and call VTK's TerminateApp\n" @@ -249,7 +261,7 @@ cv::viz::InteractorStyle::OnKeyDown() " ALT + s, S : turn stereo mode on/off\n" " ALT + f, F : switch between maximized window mode and original size\n" "\n" - << std::endl; + << std::endl; break; } @@ -261,66 +273,41 @@ cv::viz::InteractorStyle::OnKeyDown() for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) { - vtkActor* apart = reinterpret_cast (path->GetLastNode()->GetViewProp()); + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); apart->GetProperty()->SetRepresentationToPoints(); } break; } - // Save a PNG snapshot with the current screen + + // Save a PNG snapshot case 'j': case 'J': + saveScreenshot(cv::format("screenshot-%d.png", (unsigned int)time(0))); break; + + // Export scene as in obj or vrml format + case 'k': case 'K': { - unsigned int t = static_cast(time(0)); - String png_file = cv::format("screenshot-%d.png", t); - String cam_file = cv::format("screenshot-%d.cam", t); - - vtkSmartPointer cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera(); - Vec2d clip; - Vec3d focal, pos, view; - cam->GetClippingRange(clip.val); - cam->GetFocalPoint(focal.val); - cam->GetPosition(pos.val); - cam->GetViewUp(view.val); - Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition()); - Vec2i win_size(Interactor->GetRenderWindow()->GetSize()); - double angle = cam->GetViewAngle() / 180.0 * CV_PI; - - String data = cv::format("%f,%f/%f,%f,%f/%f,%f,%f/%f,%f,%f/%f/%d,%d/%d,%d", clip[0],clip[1], focal[0],focal[1],focal[2], - pos[0],pos[1],pos[2], view[0],view[1], view[2], angle , win_size[0],win_size[1], win_pos[0], win_pos[1]); - - saveScreenshot(png_file); - ofstream ofs_cam(cam_file.c_str()); - ofs_cam << data.c_str() << endl; - ofs_cam.close(); - - cout << "Screenshot (" << png_file.c_str() << ") and camera information (" << cam_file.c_str() << ") successfully captured." << endl; + String format = alt ? "scene-%d.vrml" : "scene-%d"; + exportScene(cv::format(format.c_str(), (unsigned int)time(0))); break; } + // display current camera settings/parameters case 'c': case 'C': { vtkSmartPointer cam = Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera(); - Vec2d clip; - Vec3d focal, pose, view; - cam->GetClippingRange(clip.val); - cam->GetFocalPoint(focal.val); - cam->GetPosition(pose.val); - cam->GetViewUp(view.val); + Vec2d clip(cam->GetClippingRange()); + Vec3d focal(cam->GetFocalPoint()), pos(cam->GetPosition()), view(cam->GetViewUp()); Vec2i win_pos(Interactor->GetRenderWindow()->GetPosition()); Vec2i win_size(Interactor->GetRenderWindow()->GetSize()); + double angle = cam->GetViewAngle () / 180.0 * CV_PI; + + String data = cv::format("clip(%f,%f) focal(%f,%f,%f) pos(%f,%f,%f) view(%f,%f,%f) angle(%f) winsz(%d,%d) winpos(%d,%d)", + clip[0], clip[1], focal[0], focal[1], focal[2], pos[0], pos[1], pos[2], view[0], view[1], view[2], + angle, win_size[0], win_size[1], win_pos[0], win_pos[1]); + + std::cout << data.c_str() << std::endl; - cv::print(Mat(clip, false).reshape(1, 1)); - std::cout << "/"; - cv::print(Mat(focal, false).reshape(1, 1)); - std::cout << "/"; - cv::print(Mat(pose, false).reshape(1, 1)); - std::cout << "/"; - cv::print(Mat(view, false).reshape(1, 1)); - std::cout << "/" << cam->GetViewAngle () / 180.0 * CV_PI; - cv::print(Mat(win_size, false).reshape(1, 1)); - std::cout << "/"; - cv::print(Mat(win_pos, false).reshape(1, 1)); - std::cout << std::endl; break; } case '=': @@ -339,7 +326,7 @@ cv::viz::InteractorStyle::OnKeyDown() for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) { - vtkActor* apart = reinterpret_cast (path->GetLastNode()->GetViewProp()); + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); float psize = apart->GetProperty()->GetPointSize(); if (psize < 63.0f) apart->GetProperty()->SetPointSize(psize + 1.0f); @@ -358,7 +345,7 @@ cv::viz::InteractorStyle::OnKeyDown() for (ac->InitTraversal(ait); vtkActor* actor = ac->GetNextActor(ait); ) for (actor->InitPathTraversal(); vtkAssemblyPath* path = actor->GetNextPath(); ) { - vtkActor* apart = static_cast(path->GetLastNode()->GetViewProp()); + vtkActor* apart = vtkActor::SafeDownCast(path->GetLastNode()->GetViewProp()); float psize = apart->GetProperty()->GetPointSize(); if (psize > 1.0f) apart->GetProperty()->SetPointSize(psize - 1.0f); @@ -369,7 +356,7 @@ cv::viz::InteractorStyle::OnKeyDown() // Switch between maximize and original window size case 'f': case 'F': { - if (keymod) + if (alt) { Vec2i screen_size(Interactor->GetRenderWindow()->GetScreenSize()); Vec2i win_size(Interactor->GetRenderWindow()->GetSize()); @@ -397,13 +384,11 @@ cv::viz::InteractorStyle::OnKeyDown() else { AnimState = VTKIS_ANIM_ON; - vtkAssemblyPath *path = NULL; Interactor->GetPicker()->Pick(Interactor->GetEventPosition()[0], Interactor->GetEventPosition()[1], 0.0, CurrentRenderer); - vtkAbstractPropPicker *picker; - if ((picker = vtkAbstractPropPicker::SafeDownCast(Interactor->GetPicker()))) - path = picker->GetPath(); - if (path != NULL) - Interactor->FlyTo(CurrentRenderer, picker->GetPickPosition()); + vtkSmartPointer picker = vtkAbstractPropPicker::SafeDownCast(Interactor->GetPicker()); + if (picker) + if (picker->GetPath()) + Interactor->FlyTo(CurrentRenderer, picker->GetPickPosition()); AnimState = VTKIS_ANIM_OFF; } break; @@ -411,24 +396,16 @@ cv::viz::InteractorStyle::OnKeyDown() // 's'/'S' w/out ALT case 's': case 'S': { - if (keymod) + if (alt) { - int stereo_render = Interactor->GetRenderWindow()->GetStereoRender(); - if (!stereo_render) + vtkSmartPointer window = Interactor->GetRenderWindow(); + if (!window->GetStereoRender()) { - if (stereo_anaglyph_mask_default_) - { - Interactor->GetRenderWindow()->SetAnaglyphColorMask(4, 3); - stereo_anaglyph_mask_default_ = false; - } - else - { - Interactor->GetRenderWindow()->SetAnaglyphColorMask(2, 5); - stereo_anaglyph_mask_default_ = true; - } + static Vec2i red_blue(4, 3), magenta_green(2, 5); + window->SetAnaglyphColorMask (stereo_anaglyph_mask_default_ ? red_blue.val : magenta_green.val); + stereo_anaglyph_mask_default_ = !stereo_anaglyph_mask_default_; } - Interactor->GetRenderWindow()->SetStereoRender(!stereo_render); - Interactor->GetRenderWindow()->Render(); + window->SetStereoRender(!window->GetStereoRender()); Interactor->Render(); } else @@ -440,43 +417,34 @@ cv::viz::InteractorStyle::OnKeyDown() { vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); cam->SetParallelProjection(!cam->GetParallelProjection()); - CurrentRenderer->SetActiveCamera(cam); CurrentRenderer->Render(); break; } - // Overwrite the camera reset + // Overwrite the camera reset case 'r': case 'R': { - if (!keymod) + if (!alt) { Superclass::OnKeyDown(); break; } - vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); - - static WidgetActorMap::iterator it = widget_actor_map_->begin(); + WidgetActorMap::iterator it = widget_actor_map_->begin(); // it might be that some actors don't have a valid transformation set -> we skip them to avoid a seg fault. - bool found_transformation = false; - - for (size_t idx = 0; idx < widget_actor_map_->size(); ++idx, ++it) + for (; it != widget_actor_map_->end(); ++it) { - if (it == widget_actor_map_->end()) - it = widget_actor_map_->begin(); - vtkProp3D * actor = vtkProp3D::SafeDownCast(it->second); if (actor && actor->GetUserMatrix()) - { - found_transformation = true; break; - } } + vtkSmartPointer cam = CurrentRenderer->GetActiveCamera(); + // if a valid transformation was found, use it otherwise fall back to default view point. - if (found_transformation) + if (it != widget_actor_map_->end()) { - const vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix(); + vtkMatrix4x4* m = vtkProp3D::SafeDownCast(it->second)->GetUserMatrix(); cam->SetFocalPoint(m->GetElement(0, 3) - m->GetElement(0, 2), m->GetElement(1, 3) - m->GetElement(1, 2), @@ -516,23 +484,18 @@ cv::viz::InteractorStyle::OnKeyDown() } } - KeyboardEvent event(true, Interactor->GetKeySym(), Interactor->GetKeyCode(), getAltKey(), getControlKey(), getShiftKey()); - // Check if there is a keyboard callback registered + KeyboardEvent event(KeyboardEvent::KEY_DOWN, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers()); if (keyboardCallback_) - keyboardCallback_(event, keyboard_callback_cookie_); - - renderer_->Render(); + keyboardCallback_(event, keyboard_callback_cookie_); Interactor->Render(); } ////////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::InteractorStyle::OnKeyUp() { - KeyboardEvent event(false, Interactor->GetKeySym(), Interactor->GetKeyCode(), getAltKey(), getControlKey(), getShiftKey()); - // Check if there is a keyboard callback registered + KeyboardEvent event(KeyboardEvent::KEY_UP, Interactor->GetKeySym(), Interactor->GetKeyCode(), getModifiers()); if (keyboardCallback_) - keyboardCallback_(event, keyboard_callback_cookie_); - + keyboardCallback_(event, keyboard_callback_cookie_); Superclass::OnKeyUp(); } @@ -540,9 +503,9 @@ void cv::viz::InteractorStyle::OnKeyUp() void cv::viz::InteractorStyle::OnMouseMove() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(MouseEvent::MouseMove, MouseEvent::NoButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnMouseMove(); } @@ -551,9 +514,9 @@ void cv::viz::InteractorStyle::OnLeftButtonDown() { Vec2i p(Interactor->GetEventPosition()); MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; - MouseEvent event(type, MouseEvent::LeftButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(type, MouseEvent::LeftButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnLeftButtonDown(); } @@ -561,9 +524,9 @@ void cv::viz::InteractorStyle::OnLeftButtonDown() void cv::viz::InteractorStyle::OnLeftButtonUp() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::LeftButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnLeftButtonUp(); } @@ -571,11 +534,10 @@ void cv::viz::InteractorStyle::OnLeftButtonUp() void cv::viz::InteractorStyle::OnMiddleButtonDown() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; - MouseEvent event(type, MouseEvent::MiddleButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(type, MouseEvent::MiddleButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnMiddleButtonDown(); } @@ -583,9 +545,9 @@ void cv::viz::InteractorStyle::OnMiddleButtonDown() void cv::viz::InteractorStyle::OnMiddleButtonUp() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::MiddleButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnMiddleButtonUp(); } @@ -593,11 +555,10 @@ void cv::viz::InteractorStyle::OnMiddleButtonUp() void cv::viz::InteractorStyle::OnRightButtonDown() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent::Type type = (Interactor->GetRepeatCount() == 0) ? MouseEvent::MouseButtonPress : MouseEvent::MouseDblClick; - MouseEvent event(type, MouseEvent::RightButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(type, MouseEvent::RightButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnRightButtonDown(); } @@ -605,9 +566,9 @@ void cv::viz::InteractorStyle::OnRightButtonDown() void cv::viz::InteractorStyle::OnRightButtonUp() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getAltKey(), getControlKey(), getShiftKey()); + MouseEvent event(MouseEvent::MouseButtonRelease, MouseEvent::RightButton, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); Superclass::OnRightButtonUp(); } @@ -615,12 +576,11 @@ void cv::viz::InteractorStyle::OnRightButtonUp() void cv::viz::InteractorStyle::OnMouseWheelForward() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getAltKey(), getControlKey(), getShiftKey()); - // If a mouse callback registered, call it! + MouseEvent event(MouseEvent::MouseScrollUp, MouseEvent::VScroll, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); if (Interactor->GetRepeatCount() && mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); if (Interactor->GetAltKey()) { @@ -632,11 +592,9 @@ void cv::viz::InteractorStyle::OnMouseWheelForward() cam->SetViewAngle(opening_angle); cam->Modified(); - CurrentRenderer->SetActiveCamera(cam); CurrentRenderer->ResetCameraClippingRange(); CurrentRenderer->Modified(); CurrentRenderer->Render(); - renderer_->Render(); Interactor->Render(); } else @@ -647,13 +605,12 @@ void cv::viz::InteractorStyle::OnMouseWheelForward() void cv::viz::InteractorStyle::OnMouseWheelBackward() { Vec2i p(Interactor->GetEventPosition()); - MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getAltKey(), getControlKey(), getShiftKey()); - // If a mouse callback registered, call it! + MouseEvent event(MouseEvent::MouseScrollDown, MouseEvent::VScroll, p, getModifiers()); if (mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); if (Interactor->GetRepeatCount() && mouseCallback_) - mouseCallback_(event, mouse_callback_cookie_); + mouseCallback_(event, mouse_callback_cookie_); if (Interactor->GetAltKey()) { @@ -665,11 +622,9 @@ void cv::viz::InteractorStyle::OnMouseWheelBackward() cam->SetViewAngle(opening_angle); cam->Modified(); - CurrentRenderer->SetActiveCamera(cam); CurrentRenderer->ResetCameraClippingRange(); CurrentRenderer->Modified(); CurrentRenderer->Render(); - renderer_->Render(); Interactor->Render(); } else @@ -680,13 +635,5 @@ void cv::viz::InteractorStyle::OnMouseWheelBackward() void cv::viz::InteractorStyle::OnTimer() { CV_Assert("Interactor style not initialized." && init_); - CV_Assert("Renderer has not been set." && renderer_); - renderer_->Render(); Interactor->Render(); } - -namespace cv { namespace viz -{ - //Standard VTK macro for *New() - vtkStandardNewMacro(InteractorStyle) -}} diff --git a/modules/viz/src/interactor_style.hpp b/modules/viz/src/interactor_style.hpp index 3af13fcc4..8d01697a8 100644 --- a/modules/viz/src/interactor_style.hpp +++ b/modules/viz/src/interactor_style.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_INTERACTOR_STYLE_H__ @@ -56,9 +53,6 @@ namespace cv class InteractorStyle : public vtkInteractorStyleTrackballCamera { public: - - enum KeyboardModifier { KB_MOD_ALT, KB_MOD_CTRL, KB_MOD_SHIFT }; - static InteractorStyle *New(); virtual ~InteractorStyle() {} @@ -69,31 +63,21 @@ namespace cv virtual void Initialize(); void setWidgetActorMap(const Ptr& actors) { widget_actor_map_ = actors; } - void setRenderer(vtkSmartPointer& ren) { renderer_ = ren; } void registerMouseCallback(void (*callback)(const MouseEvent&, void*), void* cookie = 0); void registerKeyboardCallback(void (*callback)(const KeyboardEvent&, void*), void * cookie = 0); void saveScreenshot(const String &file); - - /** \brief Change the default keyboard modified from ALT to a different special key.*/ - inline void setKeyboardModifier(const KeyboardModifier &modifier) { modifier_ = modifier; } + void exportScene(const String &file); private: /** \brief Set to true after initialization is complete. */ bool init_; - vtkSmartPointer renderer_; Ptr widget_actor_map_; Vec2i win_size_; Vec2i win_pos_; Vec2i max_win_size_; - /** \brief A PNG writer for screenshot captures. */ - vtkSmartPointer snapshot_writer_; - - /** \brief Internal window to image filter. Needed by \a snapshot_writer_. */ - vtkSmartPointer wif_; - /** \brief Interactor style internal method. Gets called whenever a key is pressed. */ virtual void OnChar(); @@ -121,17 +105,13 @@ namespace cv /** \brief True if we're using red-blue colors for anaglyphic stereo, false if magenta-green. */ bool stereo_anaglyph_mask_default_; - KeyboardModifier modifier_; - void (*keyboardCallback_)(const KeyboardEvent&, void*); void *keyboard_callback_cookie_; void (*mouseCallback_)(const MouseEvent&, void*); void *mouse_callback_cookie_; - bool getAltKey(); - bool getControlKey(); - bool getShiftKey(); + int getModifiers(); }; } } diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp index ab673b389..de5346ebf 100644 --- a/modules/viz/src/precomp.hpp +++ b/modules/viz/src/precomp.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifndef __OPENCV_VIZ_PRECOMP_HPP__ @@ -53,6 +50,8 @@ #include #include #include +#include +#include #include #include @@ -94,13 +93,13 @@ #include #include #include -#include #include #include #include #include #include #include +#include #include #include #include @@ -110,12 +109,50 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if !defined(_WIN32) || defined(__CYGWIN__) +# include /* unlink */ +#else +# include /* unlink */ +#endif + +#include +#include +#include +#include +#include +#include #include #include #include #include + namespace cv { namespace viz @@ -144,11 +181,145 @@ namespace cv static VizMap storage; friend class Viz3d; }; + + template inline _Tp normalized(const _Tp& v) { return v * 1/norm(v); } + + template inline bool isNan(const _Tp* data) + { + return isNan(data[0]) || isNan(data[1]) || isNan(data[2]); + } + + inline vtkSmartPointer getActor(const Widget3D& widget) + { + return vtkActor::SafeDownCast(WidgetAccessor::getProp(widget)); + } + + inline vtkSmartPointer getPolyData(const Widget3D& widget) + { + vtkSmartPointer mapper = getActor(widget)->GetMapper(); + return vtkPolyData::SafeDownCast(mapper->GetInput()); + } + + inline vtkSmartPointer vtkmatrix(const cv::Matx44d &matrix) + { + vtkSmartPointer vtk_matrix = vtkSmartPointer::New(); + vtk_matrix->DeepCopy(matrix.val); + return vtk_matrix; + } + + inline Color vtkcolor(const Color& color) + { + Color scaled_color = color * (1.0/255.0); + std::swap(scaled_color[0], scaled_color[2]); + return scaled_color; + } + + inline Vec3d get_random_vec(double from = -10.0, double to = 10.0) + { + RNG& rng = theRNG(); + return Vec3d(rng.uniform(from, to), rng.uniform(from, to), rng.uniform(from, to)); + } + + struct VtkUtils + { + template + static void SetInputData(vtkSmartPointer filter, vtkPolyData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetInput(polydata); + #else + filter->SetInputData(polydata); + #endif + } + template + static void SetSourceData(vtkSmartPointer filter, vtkPolyData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetSource(polydata); + #else + filter->SetSourceData(polydata); + #endif + } + + template + static void SetInputData(vtkSmartPointer filter, vtkImageData* polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->SetInput(polydata); + #else + filter->SetInputData(polydata); + #endif + } + + template + static void AddInputData(vtkSmartPointer filter, vtkPolyData *polydata) + { + #if VTK_MAJOR_VERSION <= 5 + filter->AddInput(polydata); + #else + filter->AddInputData(polydata); + #endif + } + + static vtkSmartPointer FillScalars(size_t size, const Color& color) + { + Vec3b rgb = Vec3d(color[2], color[1], color[0]); + Vec3b* color_data = new Vec3b[size]; + std::fill(color_data, color_data + size, rgb); + + vtkSmartPointer scalars = vtkSmartPointer::New(); + scalars->SetName("Colors"); + scalars->SetNumberOfComponents(3); + scalars->SetNumberOfTuples(size); + scalars->SetArray(color_data->val, size * 3, 0); + return scalars; + } + + static vtkSmartPointer ComputeNormals(vtkSmartPointer polydata) + { + vtkSmartPointer normals_generator = vtkSmartPointer::New(); + normals_generator->ComputePointNormalsOn(); + normals_generator->ComputeCellNormalsOff(); + normals_generator->SetFeatureAngle(0.1); + normals_generator->SetSplitting(0); + normals_generator->SetConsistency(1); + normals_generator->SetAutoOrientNormals(0); + normals_generator->SetFlipNormals(0); + normals_generator->SetNonManifoldTraversal(1); + VtkUtils::SetInputData(normals_generator, polydata); + normals_generator->Update(); + return normals_generator->GetOutput(); + } + + static vtkSmartPointer TransformPolydata(vtkSmartPointer algorithm_output_port, const Affine3d& pose) + { + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(pose.matrix)); + + vtkSmartPointer transform_filter = vtkSmartPointer::New(); + transform_filter->SetTransform(transform); + transform_filter->SetInputConnection(algorithm_output_port); + transform_filter->Update(); + return transform_filter->GetOutput(); + } + + static vtkSmartPointer TransformPolydata(vtkSmartPointer polydata, const Affine3d& pose) + { + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(pose.matrix)); + + vtkSmartPointer transform_filter = vtkSmartPointer::New(); + VtkUtils::SetInputData(transform_filter, polydata); + transform_filter->SetTransform(transform); + transform_filter->Update(); + return transform_filter->GetOutput(); + } + }; } } #include "interactor_style.hpp" -#include "viz3d_impl.hpp" +#include "vizimpl.hpp" #endif diff --git a/modules/viz/src/shape_widgets.cpp b/modules/viz/src/shape_widgets.cpp deleted file mode 100644 index 6e4f4c70f..000000000 --- a/modules/viz/src/shape_widgets.cpp +++ /dev/null @@ -1,1497 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -// Authors: -// * Ozan Tonkal, ozantonkal@gmail.com -// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com -// -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// -//M*/ - -#include "precomp.hpp" - -namespace cv -{ - namespace viz - { - template Vec<_Tp, 3>* vtkpoints_data(vtkSmartPointer& points); - } -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// line widget implementation -cv::viz::WLine::WLine(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); - line->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(line->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WLine cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// plane widget implementation - -struct cv::viz::WPlane::SetSizeImpl -{ - template - static vtkSmartPointer setSize(const Vec<_Tp, 3> ¢er, vtkSmartPointer poly_data_port, double size) - { - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->Translate(center[0], center[1], center[2]); - transform->Scale(size, size, size); - transform->Translate(-center[0], -center[1], -center[2]); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetInputConnection(poly_data_port); - transform_filter->SetTransform(transform); - transform_filter->Update(); - - return transform_filter; - } -}; - -cv::viz::WPlane::WPlane(const Vec4f& coefs, float size, const Color &color) -{ - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetNormal(coefs[0], coefs[1], coefs[2]); - double norm = cv::norm(Vec3f(coefs.val)); - plane->Push(-coefs[3] / norm); - - Vec3d p_center; - plane->GetOrigin(p_center.val); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(SetSizeImpl::setSize(p_center, plane->GetOutputPort(), size)->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -cv::viz::WPlane::WPlane(const Vec4f& coefs, const Point3f& pt, float size, const Color &color) -{ - vtkSmartPointer plane = vtkSmartPointer::New(); - Point3f coefs3(coefs[0], coefs[1], coefs[2]); - double norm_sqr = 1.0 / coefs3.dot(coefs3); - plane->SetNormal(coefs[0], coefs[1], coefs[2]); - - double t = coefs3.dot(pt) + coefs[3]; - Vec3f p_center = pt - coefs3 * t * norm_sqr; - plane->SetCenter(p_center[0], p_center[1], p_center[2]); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(SetSizeImpl::setSize(p_center, plane->GetOutputPort(), size)->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WPlane cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// sphere widget implementation - -cv::viz::WSphere::WSphere(const Point3f ¢er, float radius, int sphere_resolution, const Color &color) -{ - vtkSmartPointer sphere = vtkSmartPointer::New(); - sphere->SetRadius(radius); - sphere->SetCenter(center.x, center.y, center.z); - sphere->SetPhiResolution(sphere_resolution); - sphere->SetThetaResolution(sphere_resolution); - sphere->LatLongTessellationOff(); - sphere->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(sphere->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WSphere cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// arrow widget implementation - -cv::viz::WArrow::WArrow(const Point3f& pt1, const Point3f& pt2, float thickness, const Color &color) -{ - vtkSmartPointer arrowSource = vtkSmartPointer::New(); - arrowSource->SetShaftRadius(thickness); - // The thickness and radius of the tip are adjusted based on the thickness of the arrow - arrowSource->SetTipRadius(thickness * 3.0); - arrowSource->SetTipLength(thickness * 10.0); - - float startPoint[3], endPoint[3]; - startPoint[0] = pt1.x; - startPoint[1] = pt1.y; - startPoint[2] = pt1.z; - endPoint[0] = pt2.x; - endPoint[1] = pt2.y; - endPoint[2] = pt2.z; - float normalizedX[3], normalizedY[3], normalizedZ[3]; - - // The X axis is a vector from start to end - vtkMath::Subtract(endPoint, startPoint, normalizedX); - float length = vtkMath::Norm(normalizedX); - vtkMath::Normalize(normalizedX); - - // The Z axis is an arbitrary vecotr cross X - float arbitrary[3]; - arbitrary[0] = vtkMath::Random(-10,10); - arbitrary[1] = vtkMath::Random(-10,10); - arbitrary[2] = vtkMath::Random(-10,10); - vtkMath::Cross(normalizedX, arbitrary, normalizedZ); - vtkMath::Normalize(normalizedZ); - - // The Y axis is Z cross X - vtkMath::Cross(normalizedZ, normalizedX, normalizedY); - vtkSmartPointer matrix = vtkSmartPointer::New(); - - // Create the direction cosine matrix - matrix->Identity(); - for (unsigned int i = 0; i < 3; i++) - { - matrix->SetElement(i, 0, normalizedX[i]); - matrix->SetElement(i, 1, normalizedY[i]); - matrix->SetElement(i, 2, normalizedZ[i]); - } - - // Apply the transforms - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->Translate(startPoint); - transform->Concatenate(matrix); - transform->Scale(length, length, length); - - // Transform the polydata - vtkSmartPointer transformPD = vtkSmartPointer::New(); - transformPD->SetTransform(transform); - transformPD->SetInputConnection(arrowSource->GetOutputPort()); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(transformPD->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WArrow cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// circle widget implementation - -cv::viz::WCircle::WCircle(const Point3f& pt, float radius, float thickness, const Color& color) -{ - vtkSmartPointer disk = vtkSmartPointer::New(); - // Maybe the resolution should be lower e.g. 50 or 25 - disk->SetCircumferentialResolution(50); - disk->SetInnerRadius(radius - thickness); - disk->SetOuterRadius(radius + thickness); - - // Set the circle origin - vtkSmartPointer t = vtkSmartPointer::New(); - t->Identity(); - t->Translate(pt.x, pt.y, pt.z); - - vtkSmartPointer tf = vtkSmartPointer::New(); - tf->SetTransform(t); - tf->SetInputConnection(disk->GetOutputPort()); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(tf->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WCircle cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// cylinder widget implementation - -cv::viz::WCylinder::WCylinder(const Point3f& pt_on_axis, const Point3f& axis_direction, float radius, int numsides, const Color &color) -{ - const 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); - line->SetPoint2(pt2.x, pt2.y, pt2.z); - - vtkSmartPointer tuber = vtkSmartPointer::New(); - tuber->SetInputConnection(line->GetOutputPort()); - tuber->SetRadius(radius); - tuber->SetNumberOfSides(numsides); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(tuber->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WCylinder cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// cylinder widget implementation - -cv::viz::WCube::WCube(const Point3f& pt_min, const Point3f& pt_max, bool wire_frame, const Color &color) -{ - vtkSmartPointer mapper = vtkSmartPointer::New(); - if (wire_frame) - { - vtkSmartPointer cube = vtkSmartPointer::New(); - cube->SetBounds(pt_min.x, pt_max.x, pt_min.y, pt_max.y, pt_min.z, pt_max.z); - mapper->SetInputConnection(cube->GetOutputPort()); - } - else - { - vtkSmartPointer cube = vtkSmartPointer::New(); - cube->SetBounds(pt_min.x, pt_max.x, pt_min.y, pt_max.y, pt_min.z, pt_max.z); - mapper->SetInputConnection(cube->GetOutputPort()); - } - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WCube cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// coordinate system widget implementation - -cv::viz::WCoordinateSystem::WCoordinateSystem(float scale) -{ - vtkSmartPointer axes = vtkSmartPointer::New(); - axes->SetOrigin(0, 0, 0); - axes->SetScaleFactor(scale); - - vtkSmartPointer axes_colors = vtkSmartPointer::New(); - axes_colors->Allocate(6); - axes_colors->InsertNextValue(0.0); - axes_colors->InsertNextValue(0.0); - axes_colors->InsertNextValue(0.5); - axes_colors->InsertNextValue(0.5); - axes_colors->InsertNextValue(1.0); - axes_colors->InsertNextValue(1.0); - - vtkSmartPointer axes_data = axes->GetOutput(); -#if VTK_MAJOR_VERSION <= 5 - axes_data->Update(); -#else - axes->Update(); -#endif - axes_data->GetPointData()->SetScalars(axes_colors); - - vtkSmartPointer axes_tubes = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - axes_tubes->SetInput(axes_data); -#else - axes_tubes->SetInputData(axes_data); -#endif - axes_tubes->SetRadius(axes->GetScaleFactor() / 50.0); - axes_tubes->SetNumberOfSides(6); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetScalarModeToUsePointData(); - mapper->SetInputConnection(axes_tubes->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// polyline widget implementation - -struct cv::viz::WPolyLine::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); - } - } - } -}; - -cv::viz::WPolyLine::WPolyLine(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(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(polyData); -#else - mapper->SetInputData(polyData); -#endif - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WPolyLine cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// grid widget implementation - -struct cv::viz::WGrid::GridImpl -{ - static vtkSmartPointer createGrid(const Vec2i &dimensions, const Vec2d &spacing) - { - // 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); - - // Extract the edges so we have the grid - vtkSmartPointer filter = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - filter->SetInputConnection(grid->GetProducerPort()); -#else - filter->SetInputData(grid); -#endif - filter->Update(); - return filter->GetOutput(); - } -}; - -cv::viz::WGrid::WGrid(const Vec2i &dimensions, const Vec2d &spacing, const Color &color) -{ - vtkSmartPointer grid = GridImpl::createGrid(dimensions, spacing); - - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInputConnection(grid->GetProducerPort()); -#else - mapper->SetInputData(grid); -#endif - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -cv::viz::WGrid::WGrid(const Vec4f &coefs, const Vec2i &dimensions, const Vec2d &spacing, const Color &color) -{ - vtkSmartPointer grid = GridImpl::createGrid(dimensions, spacing); - - // Estimate the transform to set the normal based on the coefficients - Vec3f normal(coefs[0], coefs[1], coefs[2]); - Vec3f up_vector(0.0f, 1.0f, 0.0f); // Just set as default - double push_distance = -coefs[3]/cv::norm(Vec3f(coefs.val)); - Vec3f u,v,n; - n = normalize(normal); - u = normalize(up_vector.cross(n)); - v = n.cross(u); - - vtkSmartPointer mat_trans = vtkSmartPointer::New(); - mat_trans->SetElement(0,0,u[0]); - mat_trans->SetElement(0,1,u[1]); - mat_trans->SetElement(0,2,u[2]); - mat_trans->SetElement(1,0,v[0]); - mat_trans->SetElement(1,1,v[1]); - mat_trans->SetElement(1,2,v[2]); - mat_trans->SetElement(2,0,n[0]); - mat_trans->SetElement(2,1,n[1]); - mat_trans->SetElement(2,2,n[2]); - // Inverse rotation (orthogonal, so just take transpose) - mat_trans->Transpose(); - mat_trans->SetElement(0,3,n[0] * push_distance); - mat_trans->SetElement(1,3,n[1] * push_distance); - mat_trans->SetElement(2,3,n[2] * push_distance); - mat_trans->SetElement(3,3,1); - - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(mat_trans); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); -#if VTK_MAJOR_VERSION <= 5 - transform_filter->SetInputConnection(grid->GetProducerPort()); -#else - transform_filter->SetInputData(grid); -#endif - transform_filter->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(transform_filter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WGrid cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// text3D widget implementation - -cv::viz::WText3D::WText3D(const String &text, const Point3f &position, float text_scale, bool face_camera, const Color &color) -{ - vtkSmartPointer textSource = vtkSmartPointer::New(); - textSource->SetText(text.c_str()); - textSource->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(textSource->GetOutputPort()); - - if (face_camera) - { - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - actor->SetPosition(position.x, position.y, position.z); - actor->SetScale(text_scale); - WidgetAccessor::setProp(*this, actor); - } - else - { - 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 cv::viz::WText3D::setText(const String &text) -{ - vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support text." && actor); - - // Update text source - vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); - vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); - CV_Assert("This widget does not support text." && textSource); - - textSource->SetText(text.c_str()); - textSource->Update(); -} - -cv::String cv::viz::WText3D::getText() const -{ - vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support text." && actor); - - vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); - vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); - CV_Assert("This widget does not support text." && textSource); - - return textSource->GetText(); -} - -template<> cv::viz::WText3D cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// text widget implementation - -cv::viz::WText::WText(const String &text, const Point2i &pos, int font_size, const Color &color) -{ - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetPosition(pos.x, pos.y); - actor->SetInput(text.c_str()); - - vtkSmartPointer tprop = actor->GetTextProperty(); - tprop->SetFontSize(font_size); - tprop->SetFontFamilyToArial(); - tprop->SetJustificationToLeft(); - tprop->BoldOn(); - - Color c = vtkcolor(color); - tprop->SetColor(c.val); - - WidgetAccessor::setProp(*this, actor); -} - -template<> cv::viz::WText cv::viz::Widget::cast() -{ - Widget2D widget = this->cast(); - return static_cast(widget); -} - -void cv::viz::WText::setText(const String &text) -{ - vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support text." && actor); - actor->SetInput(text.c_str()); -} - -cv::String cv::viz::WText::getText() const -{ - vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support text." && actor); - return actor->GetInput(); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// image overlay widget implementation - -cv::viz::WImageOverlay::WImageOverlay(const Mat &image, const Rect &rect) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - - // Create the vtk image and set its parameters based on input image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - // Scale the image based on the Rect - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->Scale(double(image.cols)/rect.width,double(image.rows)/rect.height,1.0); - - vtkSmartPointer image_reslice = vtkSmartPointer::New(); - image_reslice->SetResliceTransform(transform); - image_reslice->SetInputConnection(flipFilter->GetOutputPort()); - image_reslice->SetOutputDimensionality(2); - image_reslice->InterpolateOn(); - image_reslice->AutoCropOutputOn(); - - vtkSmartPointer imageMapper = vtkSmartPointer::New(); - imageMapper->SetInputConnection(image_reslice->GetOutputPort()); - imageMapper->SetColorWindow(255); // OpenCV color - imageMapper->SetColorLevel(127.5); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(imageMapper); - actor->SetPosition(rect.x, rect.y); - - WidgetAccessor::setProp(*this, actor); -} - -void cv::viz::WImageOverlay::setImage(const Mat &image) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - - vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support overlay image." && actor); - - vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper()); - CV_Assert("This widget does not support overlay image." && mapper); - - // Create the vtk image and set its parameters based on input image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - mapper->SetInputConnection(flipFilter->GetOutputPort()); -} - -template<> cv::viz::WImageOverlay cv::viz::Widget::cast() -{ - Widget2D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// image 3D widget implementation - -cv::viz::WImage3D::WImage3D(const Mat &image, const Size &size) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - - // Create the vtk image and set its parameters based on input image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - Vec3d plane_center(size.width * 0.5, size.height * 0.5, 0.0); - - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetCenter(plane_center[0], plane_center[1], plane_center[2]); - plane->SetNormal(0.0, 0.0, 1.0); - - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->Translate(plane_center[0], plane_center[1], plane_center[2]); - transform->Scale(size.width, size.height, 1.0); - transform->Translate(-plane_center[0], -plane_center[1], -plane_center[2]); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); - transform_filter->SetInputConnection(plane->GetOutputPort()); - transform_filter->Update(); - - // Apply the texture - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(flipFilter->GetOutputPort()); - - vtkSmartPointer texturePlane = vtkSmartPointer::New(); - texturePlane->SetInputConnection(transform_filter->GetOutputPort()); - - vtkSmartPointer planeMapper = vtkSmartPointer::New(); - planeMapper->SetInputConnection(texturePlane->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(planeMapper); - actor->SetTexture(texture); - - WidgetAccessor::setProp(*this, actor); -} - -cv::viz::WImage3D::WImage3D(const Vec3f &position, const Vec3f &normal, const Vec3f &up_vector, const Mat &image, const Size &size) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - - // Create the vtk image and set its parameters based on input image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetCenter(0.0, 0.0, 0.0); - plane->SetNormal(0.0, 0.0, 1.0); - - // Compute the transformation matrix for drawing the camera frame in a scene - Vec3f u,v,n; - n = normalize(normal); - u = normalize(up_vector.cross(n)); - v = n.cross(u); - - vtkSmartPointer mat_trans = vtkSmartPointer::New(); - mat_trans->SetElement(0,0,u[0]); - mat_trans->SetElement(0,1,u[1]); - mat_trans->SetElement(0,2,u[2]); - mat_trans->SetElement(1,0,v[0]); - mat_trans->SetElement(1,1,v[1]); - mat_trans->SetElement(1,2,v[2]); - mat_trans->SetElement(2,0,n[0]); - mat_trans->SetElement(2,1,n[1]); - mat_trans->SetElement(2,2,n[2]); - // Inverse rotation (orthogonal, so just take transpose) - mat_trans->Transpose(); - // Then translate the coordinate frame to camera position - mat_trans->SetElement(0,3,position[0]); - mat_trans->SetElement(1,3,position[1]); - mat_trans->SetElement(2,3,position[2]); - mat_trans->SetElement(3,3,1); - - // Apply the texture - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(flipFilter->GetOutputPort()); - - vtkSmartPointer texturePlane = vtkSmartPointer::New(); - texturePlane->SetInputConnection(plane->GetOutputPort()); - - // Apply the transform after texture mapping - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->SetMatrix(mat_trans); - transform->Scale(size.width, size.height, 1.0); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); - transform_filter->SetInputConnection(texturePlane->GetOutputPort()); - transform_filter->Update(); - - vtkSmartPointer planeMapper = vtkSmartPointer::New(); - planeMapper->SetInputConnection(transform_filter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(planeMapper); - actor->SetTexture(texture); - - WidgetAccessor::setProp(*this, actor); -} - -void cv::viz::WImage3D::setImage(const Mat &image) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - - vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); - CV_Assert("This widget does not support 3D image." && actor); - - // Create the vtk image and set its parameters based on input image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - // Apply the texture - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(flipFilter->GetOutputPort()); - - actor->SetTexture(texture); -} - -template<> cv::viz::WImage3D cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// camera position widget implementation - -struct cv::viz::WCameraPosition::ProjectImage -{ - static void projectImage(float fovy, float far_end_height, const Mat &image, - double scale, const Color &color, vtkSmartPointer actor) - { - // Create a camera - vtkSmartPointer camera = vtkSmartPointer::New(); - float aspect_ratio = float(image.cols)/float(image.rows); - - // Create the vtk image - vtkSmartPointer vtk_image = vtkSmartPointer::New(); - ConvertToVtkImage::convert(image, vtk_image); - - // Adjust a pixel of the vtk_image - vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 0, color[2]); - vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 1, color[1]); - vtk_image->SetScalarComponentFromDouble(0, image.rows-1, 0, 2, color[0]); - - // Need to flip the image as the coordinates are different in OpenCV and VTK - vtkSmartPointer flipFilter = vtkSmartPointer::New(); - flipFilter->SetFilteredAxis(1); // Vertical flip -#if VTK_MAJOR_VERSION <= 5 - flipFilter->SetInputConnection(vtk_image->GetProducerPort()); -#else - flipFilter->SetInputData(vtk_image); -#endif - flipFilter->Update(); - - Vec3d plane_center(0.0, 0.0, scale); - - vtkSmartPointer plane = vtkSmartPointer::New(); - plane->SetCenter(plane_center[0], plane_center[1], plane_center[2]); - plane->SetNormal(0.0, 0.0, 1.0); - - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - transform->Translate(plane_center[0], plane_center[1], plane_center[2]); - transform->Scale(far_end_height*aspect_ratio, far_end_height, 1.0); - transform->RotateY(180.0); - transform->Translate(-plane_center[0], -plane_center[1], -plane_center[2]); - - // Apply the texture - vtkSmartPointer texture = vtkSmartPointer::New(); - texture->SetInputConnection(flipFilter->GetOutputPort()); - - vtkSmartPointer texturePlane = vtkSmartPointer::New(); - texturePlane->SetInputConnection(plane->GetOutputPort()); - - vtkSmartPointer transform_filter = vtkSmartPointer::New(); - transform_filter->SetTransform(transform); - transform_filter->SetInputConnection(texturePlane->GetOutputPort()); - transform_filter->Update(); - - // Create frustum - camera->SetViewAngle(fovy); - camera->SetPosition(0.0,0.0,0.0); - camera->SetViewUp(0.0,1.0,0.0); - camera->SetFocalPoint(0.0,0.0,1.0); - camera->SetClippingRange(0.01, scale); - - double planesArray[24]; - camera->GetFrustumPlanes(aspect_ratio, planesArray); - - vtkSmartPointer planes = vtkSmartPointer::New(); - planes->SetFrustumPlanes(planesArray); - - vtkSmartPointer frustumSource = - vtkSmartPointer::New(); - frustumSource->SetPlanes(planes); - frustumSource->Update(); - - vtkSmartPointer filter = vtkSmartPointer::New(); - filter->SetInputConnection(frustumSource->GetOutputPort()); - filter->Update(); - - // Frustum needs to be textured or else it can't be combined with image - vtkSmartPointer frustum_texture = vtkSmartPointer::New(); - frustum_texture->SetInputConnection(filter->GetOutputPort()); - // Texture mapping with only one pixel from the image to have constant color - frustum_texture->SetSRange(0.0, 0.0); - frustum_texture->SetTRange(0.0, 0.0); - - vtkSmartPointer appendFilter = vtkSmartPointer::New(); - appendFilter->AddInputConnection(frustum_texture->GetOutputPort()); - appendFilter->AddInputConnection(transform_filter->GetOutputPort()); - - vtkSmartPointer planeMapper = vtkSmartPointer::New(); - planeMapper->SetInputConnection(appendFilter->GetOutputPort()); - - actor->SetMapper(planeMapper); - actor->SetTexture(texture); - } -}; - -cv::viz::WCameraPosition::WCameraPosition(float scale) -{ - vtkSmartPointer axes = vtkSmartPointer::New(); - axes->SetOrigin(0, 0, 0); - axes->SetScaleFactor(scale); - - vtkSmartPointer axes_colors = vtkSmartPointer::New(); - axes_colors->Allocate(6); - axes_colors->InsertNextValue(0.0); - axes_colors->InsertNextValue(0.0); - axes_colors->InsertNextValue(0.5); - axes_colors->InsertNextValue(0.5); - axes_colors->InsertNextValue(1.0); - axes_colors->InsertNextValue(1.0); - - vtkSmartPointer axes_data = axes->GetOutput(); -#if VTK_MAJOR_VERSION <= 5 - axes_data->Update(); -#else - axes->Update(); -#endif - axes_data->GetPointData()->SetScalars(axes_colors); - - vtkSmartPointer axes_tubes = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - axes_tubes->SetInput(axes_data); -#else - axes_tubes->SetInputData(axes_data); -#endif - axes_tubes->SetRadius(axes->GetScaleFactor() / 50.0); - axes_tubes->SetNumberOfSides(6); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetScalarModeToUsePointData(); - mapper->SetInputConnection(axes_tubes->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, float scale, const Color &color) -{ - vtkSmartPointer camera = vtkSmartPointer::New(); - float f_x = K(0,0); - float f_y = K(1,1); - float c_y = K(1,2); - float aspect_ratio = f_y / f_x; - // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) - float fovy = 2.0f * atan2(c_y,f_y) * 180 / CV_PI; - - camera->SetViewAngle(fovy); - camera->SetPosition(0.0,0.0,0.0); - camera->SetViewUp(0.0,1.0,0.0); - camera->SetFocalPoint(0.0,0.0,1.0); - camera->SetClippingRange(0.01, scale); - - double planesArray[24]; - camera->GetFrustumPlanes(aspect_ratio, planesArray); - - vtkSmartPointer planes = vtkSmartPointer::New(); - planes->SetFrustumPlanes(planesArray); - - vtkSmartPointer frustumSource = - vtkSmartPointer::New(); - frustumSource->SetPlanes(planes); - frustumSource->Update(); - - vtkSmartPointer filter = vtkSmartPointer::New(); - filter->SetInputConnection(frustumSource->GetOutputPort()); - filter->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(filter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - - -cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, float scale, const Color &color) -{ - vtkSmartPointer camera = vtkSmartPointer::New(); - - camera->SetViewAngle(fov[1] * 180 / CV_PI); // Vertical field of view - camera->SetPosition(0.0,0.0,0.0); - camera->SetViewUp(0.0,1.0,0.0); - camera->SetFocalPoint(0.0,0.0,1.0); - camera->SetClippingRange(0.01, scale); - - double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5); - - double planesArray[24]; - camera->GetFrustumPlanes(aspect_ratio, planesArray); - - vtkSmartPointer planes = vtkSmartPointer::New(); - planes->SetFrustumPlanes(planesArray); - - vtkSmartPointer frustumSource = - vtkSmartPointer::New(); - frustumSource->SetPlanes(planes); - frustumSource->Update(); - - // Extract the edges so we have the grid - vtkSmartPointer filter = vtkSmartPointer::New(); - filter->SetInputConnection(frustumSource->GetOutputPort()); - filter->Update(); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(filter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -cv::viz::WCameraPosition::WCameraPosition(const Matx33f &K, const Mat &image, float scale, const Color &color) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - float f_y = K(1,1); - float c_y = K(1,2); - // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) - float fovy = 2.0f * atan2(c_y,f_y) * 180.0f / CV_PI; - float far_end_height = 2.0f * c_y * scale / f_y; - - vtkSmartPointer actor = vtkSmartPointer::New(); - ProjectImage::projectImage(fovy, far_end_height, image, scale, color, actor); - WidgetAccessor::setProp(*this, actor); -} - -cv::viz::WCameraPosition::WCameraPosition(const Vec2f &fov, const Mat &image, float scale, const Color &color) -{ - CV_Assert(!image.empty() && image.depth() == CV_8U); - float fovy = fov[1] * 180.0f / CV_PI; - float far_end_height = 2.0 * scale * tan(fov[1] * 0.5); - - vtkSmartPointer actor = vtkSmartPointer::New(); - ProjectImage::projectImage(fovy, far_end_height, image, scale, color, actor); - WidgetAccessor::setProp(*this, actor); -} - -template<> cv::viz::WCameraPosition cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// trajectory widget implementation - -struct cv::viz::WTrajectory::ApplyPath -{ - static void applyPath(vtkSmartPointer poly_data, vtkSmartPointer append_filter, const std::vector &path) - { - vtkIdType nr_points = path.size(); - - for (vtkIdType i = 0; i < nr_points; ++i) - { - vtkSmartPointer new_data = vtkSmartPointer::New(); - new_data->DeepCopy(poly_data); - - // Transform the default coordinate frame - vtkSmartPointer transform = vtkSmartPointer::New(); - transform->PreMultiply(); - vtkSmartPointer mat_trans = vtkSmartPointer::New(); - mat_trans = convertToVtkMatrix(path[i].matrix); - transform->SetMatrix(mat_trans); - - vtkSmartPointer filter = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - filter->SetInput(new_data); -#else - filter->SetInputData(new_data); -#endif - filter->SetTransform(transform); - filter->Update(); - - append_filter->AddInputConnection(filter->GetOutputPort()); - } - } -}; - -cv::viz::WTrajectory::WTrajectory(const std::vector &path, int display_mode, const Color &color, float scale) -{ - vtkSmartPointer appendFilter = vtkSmartPointer::New(); - - // Bitwise and with 3 in order to limit the domain to 2 bits - if ((~display_mode & 3) ^ WTrajectory::DISPLAY_PATH) - { - // Create a poly line along the path - vtkIdType nr_points = path.size(); - - vtkSmartPointer points = vtkSmartPointer::New(); - vtkSmartPointer polyData = vtkSmartPointer::New(); - vtkSmartPointer polyLine = vtkSmartPointer::New(); - - points->SetDataTypeToFloat(); - points->SetNumberOfPoints(nr_points); - polyLine->GetPointIds()->SetNumberOfIds(nr_points); - - Vec3f *data_beg = vtkpoints_data(points); - - for (vtkIdType i = 0; i < nr_points; ++i) - { - Vec3f cam_pose = path[i].translation(); - *data_beg++ = cam_pose; - polyLine->GetPointIds()->SetId(i,i); - } - - vtkSmartPointer cells = vtkSmartPointer::New(); - cells->InsertNextCell(polyLine); - - polyData->SetPoints(points); - polyData->SetLines(cells); - - // Set the color for polyData - vtkSmartPointer colors = vtkSmartPointer::New(); - colors->SetNumberOfComponents(3); - colors->SetNumberOfTuples(nr_points); - colors->FillComponent(0, color[2]); - colors->FillComponent(1, color[1]); - colors->FillComponent(2, color[0]); - - polyData->GetPointData()->SetScalars(colors); -#if VTK_MAJOR_VERSION <= 5 - appendFilter->AddInputConnection(polyData->GetProducerPort()); -#else - appendFilter->AddInputData(polyData); -#endif - } - - if ((~display_mode & 3) ^ WTrajectory::DISPLAY_FRAMES) - { - // Create frames and transform along the path - vtkSmartPointer axes = vtkSmartPointer::New(); - axes->SetOrigin(0, 0, 0); - axes->SetScaleFactor(scale); - - vtkSmartPointer axes_colors = vtkSmartPointer::New(); - axes_colors->SetNumberOfComponents(3); - axes_colors->InsertNextTuple3(255,0,0); - axes_colors->InsertNextTuple3(255,0,0); - axes_colors->InsertNextTuple3(0,255,0); - axes_colors->InsertNextTuple3(0,255,0); - axes_colors->InsertNextTuple3(0,0,255); - axes_colors->InsertNextTuple3(0,0,255); - - vtkSmartPointer axes_data = axes->GetOutput(); -#if VTK_MAJOR_VERSION <= 5 - axes_data->Update(); -#else - axes->Update(); -#endif - axes_data->GetPointData()->SetScalars(axes_colors); - - vtkSmartPointer axes_tubes = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - axes_tubes->SetInput(axes_data); -#else - axes_tubes->SetInputData(axes_data); -#endif - axes_tubes->SetRadius(axes->GetScaleFactor() / 50.0); - axes_tubes->SetNumberOfSides(6); - axes_tubes->Update(); - - ApplyPath::applyPath(axes_tubes->GetOutput(), appendFilter, path); - } - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetScalarModeToUsePointData(); - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Matx33f &K, float scale, const Color &color) -{ - vtkSmartPointer camera = vtkSmartPointer::New(); - float f_x = K(0,0); - float f_y = K(1,1); - float c_y = K(1,2); - float aspect_ratio = f_y / f_x; - // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) - float fovy = 2.0f * atan2(c_y,f_y) * 180 / CV_PI; - - camera->SetViewAngle(fovy); - camera->SetPosition(0.0,0.0,0.0); - camera->SetViewUp(0.0,1.0,0.0); - camera->SetFocalPoint(0.0,0.0,1.0); - camera->SetClippingRange(0.01, scale); - - double planesArray[24]; - camera->GetFrustumPlanes(aspect_ratio, planesArray); - - vtkSmartPointer planes = vtkSmartPointer::New(); - planes->SetFrustumPlanes(planesArray); - - vtkSmartPointer frustumSource = vtkSmartPointer::New(); - frustumSource->SetPlanes(planes); - frustumSource->Update(); - - // Extract the edges - vtkSmartPointer filter = vtkSmartPointer::New(); - filter->SetInputConnection(frustumSource->GetOutputPort()); - filter->Update(); - - vtkSmartPointer appendFilter = vtkSmartPointer::New(); - ApplyPath::applyPath(filter->GetOutput(), appendFilter, path); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -cv::viz::WTrajectory::WTrajectory(const std::vector &path, const Vec2f &fov, float scale, const Color &color) -{ - vtkSmartPointer camera = vtkSmartPointer::New(); - - camera->SetViewAngle(fov[1] * 180 / CV_PI); // Vertical field of view - camera->SetPosition(0.0,0.0,0.0); - camera->SetViewUp(0.0,1.0,0.0); - camera->SetFocalPoint(0.0,0.0,1.0); - camera->SetClippingRange(0.01, scale); - - double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5); - - double planesArray[24]; - camera->GetFrustumPlanes(aspect_ratio, planesArray); - - vtkSmartPointer planes = vtkSmartPointer::New(); - planes->SetFrustumPlanes(planesArray); - - vtkSmartPointer frustumSource = vtkSmartPointer::New(); - frustumSource->SetPlanes(planes); - frustumSource->Update(); - - // Extract the edges - vtkSmartPointer filter = vtkSmartPointer::New(); - filter->SetInputConnection(frustumSource->GetOutputPort()); - filter->Update(); - - vtkSmartPointer appendFilter = vtkSmartPointer::New(); - ApplyPath::applyPath(filter->GetOutput(), appendFilter, path); - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); - setColor(color); -} - -template<> cv::viz::WTrajectory cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// spheres trajectory widget implementation - -cv::viz::WSpheresTrajectory::WSpheresTrajectory(const std::vector &path, float line_length, float init_sphere_radius, float sphere_radius, - const Color &line_color, const Color &sphere_color) -{ - vtkSmartPointer appendFilter = vtkSmartPointer::New(); - vtkIdType nr_poses = path.size(); - - // Create color arrays - vtkSmartPointer line_scalars = vtkSmartPointer::New(); - line_scalars->SetNumberOfComponents(3); - line_scalars->InsertNextTuple3(line_color[2], line_color[1], line_color[0]); - - // Create color array for sphere - vtkSphereSource * dummy_sphere = vtkSphereSource::New(); - // Create the array for big sphere - dummy_sphere->SetRadius(init_sphere_radius); - dummy_sphere->Update(); - vtkIdType nr_points = dummy_sphere->GetOutput()->GetNumberOfCells(); - vtkSmartPointer sphere_scalars_init = vtkSmartPointer::New(); - sphere_scalars_init->SetNumberOfComponents(3); - sphere_scalars_init->SetNumberOfTuples(nr_points); - sphere_scalars_init->FillComponent(0, sphere_color[2]); - sphere_scalars_init->FillComponent(1, sphere_color[1]); - sphere_scalars_init->FillComponent(2, sphere_color[0]); - // Create the array for small sphere - dummy_sphere->SetRadius(sphere_radius); - dummy_sphere->Update(); - nr_points = dummy_sphere->GetOutput()->GetNumberOfCells(); - vtkSmartPointer sphere_scalars = vtkSmartPointer::New(); - sphere_scalars->SetNumberOfComponents(3); - sphere_scalars->SetNumberOfTuples(nr_points); - sphere_scalars->FillComponent(0, sphere_color[2]); - sphere_scalars->FillComponent(1, sphere_color[1]); - sphere_scalars->FillComponent(2, sphere_color[0]); - dummy_sphere->Delete(); - - for (vtkIdType i = 0; i < nr_poses; ++i) - { - Point3f new_pos = path[i].translation(); - - vtkSmartPointer sphere_source = vtkSmartPointer::New(); - sphere_source->SetCenter(new_pos.x, new_pos.y, new_pos.z); - if (i == 0) - { - sphere_source->SetRadius(init_sphere_radius); - sphere_source->Update(); - sphere_source->GetOutput()->GetCellData()->SetScalars(sphere_scalars_init); - appendFilter->AddInputConnection(sphere_source->GetOutputPort()); - continue; - } - else - { - sphere_source->SetRadius(sphere_radius); - sphere_source->Update(); - sphere_source->GetOutput()->GetCellData()->SetScalars(sphere_scalars); - appendFilter->AddInputConnection(sphere_source->GetOutputPort()); - } - - - Affine3f relativeAffine = path[i].inv() * path[i-1]; - Vec3f v = path[i].rotation() * relativeAffine.translation(); - v = normalize(v) * line_length; - - vtkSmartPointer line_source = vtkSmartPointer::New(); - line_source->SetPoint1(new_pos.x + v[0], new_pos.y + v[1], new_pos.z + v[2]); - line_source->SetPoint2(new_pos.x, new_pos.y, new_pos.z); - line_source->Update(); - line_source->GetOutput()->GetCellData()->SetScalars(line_scalars); - - appendFilter->AddInputConnection(line_source->GetOutputPort()); - } - - vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetScalarModeToUseCellData(); - mapper->SetInputConnection(appendFilter->GetOutputPort()); - - vtkSmartPointer actor = vtkSmartPointer::New(); - actor->SetMapper(mapper); - - WidgetAccessor::setProp(*this, actor); -} - -template<> cv::viz::WSpheresTrajectory cv::viz::Widget::cast() -{ - Widget3D widget = this->cast(); - return static_cast(widget); -} diff --git a/modules/viz/src/shapes.cpp b/modules/viz/src/shapes.cpp new file mode 100644 index 000000000..cc3a51ce4 --- /dev/null +++ b/modules/viz/src/shapes.cpp @@ -0,0 +1,1088 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// line widget implementation +cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color) +{ + vtkSmartPointer line = vtkSmartPointer::New(); + line->SetPoint1(pt1.x, pt1.y, pt1.z); + line->SetPoint2(pt2.x, pt2.y, pt2.z); + line->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, line->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WLine cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// sphere widget implementation + +cv::viz::WSphere::WSphere(const Point3d ¢er, double radius, int sphere_resolution, const Color &color) +{ + vtkSmartPointer sphere = vtkSmartPointer::New(); + sphere->SetRadius(radius); + sphere->SetCenter(center.x, center.y, center.z); + sphere->SetPhiResolution(sphere_resolution); + sphere->SetThetaResolution(sphere_resolution); + sphere->LatLongTessellationOff(); + sphere->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, sphere->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WSphere cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// plane widget implementation + +cv::viz::WPlane::WPlane(const Size2d& size, const Color &color) +{ + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint2(-0.5 * size.width, 0.5 * size.height, 0.0); + plane->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, plane->GetOutput()); + + 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) +{ + Vec3d zvec = normalize(normal); + Vec3d xvec = normalize(new_yaxis.cross(zvec)); + Vec3d yvec = zvec.cross(xvec); + + WPlane plane(size, color); + plane.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = plane; +} + +template<> cv::viz::WPlane cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// arrow widget implementation + +cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color) +{ + vtkSmartPointer arrow_source = vtkSmartPointer::New(); + arrow_source->SetShaftRadius(thickness); + arrow_source->SetTipRadius(thickness * 3.0); + arrow_source->SetTipLength(thickness * 10.0); + + Vec3d arbitrary = get_random_vec(); + Vec3d start_point(pt1.x, pt1.y, pt1.z), end_point(pt2.x, pt2.y, pt2.z); + + double length = norm(end_point - start_point); + + Vec3d xvec = normalized(end_point - start_point); + Vec3d zvec = normalized(xvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + Matx33d R = makeTransformToGlobal(xvec, yvec, zvec).rotation(); + Affine3d transform_with_scale(R * length, start_point); + + vtkSmartPointer polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WArrow cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// circle widget implementation + +cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color) +{ + vtkSmartPointer disk = vtkSmartPointer::New(); + disk->SetCircumferentialResolution(30); + disk->SetInnerRadius(radius - thickness); + disk->SetOuterRadius(radius + thickness); + disk->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, disk->GetOutput()); + + 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) +{ + Vec3d arbitrary = get_random_vec(); + Vec3d zvec = normalized(normal); + Vec3d xvec = normalized(zvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + WCircle circle(radius, thickness, color); + circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = circle; +} + +template<> cv::viz::WCircle cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WCone widget implementation + +cv::viz::WCone::WCone(double length, double radius, int resolution, const Color &color) +{ + vtkSmartPointer cone_source = vtkSmartPointer::New(); + cone_source->SetCenter(length*0.5, 0.0, 0.0); + cone_source->SetHeight(length); + cone_source->SetRadius(radius); + cone_source->SetResolution(resolution); + cone_source->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cone_source->GetOutput()); + + 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) +{ + Vec3d arbitrary = get_random_vec(); + Vec3d xvec = normalized(Vec3d(tip - center)); + Vec3d zvec = normalized(xvec.cross(arbitrary)); + Vec3d yvec = zvec.cross(xvec); + + WCone circle(norm(tip - center), radius, resolution, color); + circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = circle; +} + +template<> cv::viz::WCone cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// cylinder widget implementation + +cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides, const Color &color) +{ + vtkSmartPointer line = vtkSmartPointer::New(); + line->SetPoint1(axis_point1.x, axis_point1.y, axis_point1.z); + line->SetPoint2(axis_point2.x, axis_point2.y, axis_point2.z); + + vtkSmartPointer tuber = vtkSmartPointer::New(); + tuber->SetInputConnection(line->GetOutputPort()); + tuber->SetNumberOfSides(numsides); + tuber->SetRadius(radius); + tuber->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tuber->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WCylinder cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// cylinder widget implementation + +cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool wire_frame, const Color &color) +{ + double bounds[6]; + bounds[0] = std::min(min_point.x, max_point.x); + bounds[1] = std::max(min_point.x, max_point.x); + bounds[2] = std::min(min_point.y, max_point.y); + bounds[3] = std::max(min_point.y, max_point.y); + bounds[4] = std::min(min_point.z, max_point.z); + bounds[5] = std::max(min_point.z, max_point.z); + + vtkSmartPointer cube; + if (wire_frame) + { + cube = vtkSmartPointer::New(); + vtkOutlineSource::SafeDownCast(cube)->SetBounds(bounds); + } + else + { + cube = vtkSmartPointer::New(); + vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds); + } + cube->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, cube->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WCube cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// coordinate system widget implementation + +cv::viz::WCoordinateSystem::WCoordinateSystem(double scale) +{ + vtkSmartPointer axes = vtkSmartPointer::New(); + axes->SetOrigin(0, 0, 0); + axes->SetScaleFactor(scale); + axes->Update(); + + vtkSmartPointer colors = vtkSmartPointer::New(); + colors->SetNumberOfComponents(3); + colors->InsertNextTuple3(255, 0, 0); + colors->InsertNextTuple3(255, 0, 0); + colors->InsertNextTuple3(0, 255, 0); + colors->InsertNextTuple3(0, 255, 0); + colors->InsertNextTuple3(0, 0, 255); + colors->InsertNextTuple3(0, 0, 255); + + vtkSmartPointer polydata = axes->GetOutput(); + polydata->GetPointData()->SetScalars(colors); + + vtkSmartPointer tube_filter = vtkSmartPointer::New(); + VtkUtils::SetInputData(tube_filter, polydata); + tube_filter->SetRadius(axes->GetScaleFactor() / 50.0); + tube_filter->SetNumberOfSides(6); + tube_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUsePointData(); + VtkUtils::SetInputData(mapper, tube_filter->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// polyline widget implementation + +cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color) +{ + CV_Assert(_points.type() == CV_32FC3 || _points.type() == CV_32FC4 || _points.type() == CV_64FC3 || _points.type() == CV_64FC4); + + const float *fpoints = _points.getMat().ptr(); + 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(total); + + if (_points.depth() == CV_32F) + for(size_t i = 0; i < total; ++i, fpoints += s_chs) + points->SetPoint(i, fpoints); + + if (_points.depth() == CV_64F) + for(size_t i = 0; i < total; ++i, dpoints += s_chs) + points->SetPoint(i, dpoints); + + vtkSmartPointer cell_array = vtkSmartPointer::New(); + cell_array->Allocate(cell_array->EstimateSize(1, total)); + cell_array->InsertNextCell(total); + for(size_t i = 0; i < total; ++i) + cell_array->InsertCellPoint(i); + + vtkSmartPointer scalars = VtkUtils::FillScalars(total, color); + + 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); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WPolyLine cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// grid widget implementation + + +cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Color &color) +{ + vtkSmartPointer grid_data = vtkSmartPointer::New(); + + // Add 1 to dimensions because in ImageData dimensions is the number of lines + // - however here it means number of cells + grid_data->SetDimensions(cells[0]+1, cells[1]+1, 1); + grid_data->SetSpacing(cells_spacing[0], cells_spacing[1], 0.); + + // Set origin of the grid to be the middle of the grid + grid_data->SetOrigin(cells[0] * cells_spacing[0] * (-0.5), cells[1] * cells_spacing[1] * (-0.5), 0); + + // Extract the edges so we have the grid + vtkSmartPointer extract_edges = vtkSmartPointer::New(); + VtkUtils::SetInputData(extract_edges, grid_data); + extract_edges->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, extract_edges->GetOutput()); + + 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) +{ + Vec3d zvec = normalize(normal); + Vec3d xvec = normalize(new_yaxis.cross(zvec)); + Vec3d yvec = zvec.cross(xvec); + + WGrid grid(cells, cells_spacing, color); + grid.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center)); + *this = grid; +} + +template<> cv::viz::WGrid cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// text3D widget implementation + +cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color) +{ + vtkSmartPointer textSource = vtkSmartPointer::New(); + textSource->SetText(text.c_str()); + textSource->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(textSource->GetOutputPort()); + + if (face_camera) + { + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetPosition(position.x, position.y, position.z); + actor->SetScale(text_scale); + WidgetAccessor::setProp(*this, actor); + } + else + { + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetPosition(position.x, position.y, position.z); + actor->SetScale(text_scale); + actor->GetProperty()->LightingOff(); + WidgetAccessor::setProp(*this, actor); + } + + setColor(color); +} + +void cv::viz::WText3D::setText(const String &text) +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + + // Update text source + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert("This widget does not support text." && textSource); + + textSource->SetText(text.c_str()); + textSource->Modified(); + textSource->Update(); +} + +cv::String cv::viz::WText3D::getText() const +{ + vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + + vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer()); + CV_Assert("This widget does not support text." && textSource); + + return textSource->GetText(); +} + +template<> cv::viz::WText3D cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// text widget implementation + +cv::viz::WText::WText(const String &text, const Point &pos, int font_size, const Color &color) +{ + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetDisplayPosition(pos.x, pos.y); + actor->SetInput(text.c_str()); + + actor->GetProperty()->SetDisplayLocationToForeground(); + + vtkSmartPointer tprop = actor->GetTextProperty(); + tprop->SetFontSize(font_size); + tprop->SetFontFamilyToCourier(); + tprop->SetJustificationToLeft(); + tprop->BoldOn(); + + Color c = vtkcolor(color); + tprop->SetColor(c.val); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WText cv::viz::Widget::cast() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +void cv::viz::WText::setText(const String &text) +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + actor->SetInput(text.c_str()); +} + +cv::String cv::viz::WText::getText() const +{ + vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support text." && actor); + return actor->GetInput(); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// image overlay widget implementation + +cv::viz::WImageOverlay::WImageOverlay(InputArray image, const Rect &rect) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + Size sz = image.size(); + + // Scale the image based on the Rect, and flip to match y-ais orientation + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Scale(sz.width/(double)rect.width, sz.height/(double)rect.height, 1.0); + transform->RotateX(180); + + vtkSmartPointer image_reslice = vtkSmartPointer::New(); + image_reslice->SetResliceTransform(transform); + image_reslice->SetInputConnection(source->GetOutputPort()); + image_reslice->SetOutputDimensionality(2); + image_reslice->InterpolateOn(); + image_reslice->AutoCropOutputOn(); + image_reslice->Update(); + + vtkSmartPointer image_mapper = vtkSmartPointer::New(); + image_mapper->SetInputConnection(image_reslice->GetOutputPort()); + image_mapper->SetColorWindow(255); // OpenCV color + image_mapper->SetColorLevel(127.5); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(image_mapper); + actor->SetPosition(rect.x, rect.y); + actor->GetProperty()->SetDisplayLocationToForeground(); + + WidgetAccessor::setProp(*this, actor); +} + +void cv::viz::WImageOverlay::setImage(InputArray image) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support overlay image." && actor); + + vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("This widget does not support overlay image." && mapper); + \ + Vec6i extent; + mapper->GetInput()->GetExtent(extent.val); + Size size(extent[1], extent[3]); + + // Create the vtk image and set its parameters based on input image + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + Size sz = image.size(); + + // Scale the image based on the Rect, and flip to match y-ais orientation + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->Scale(sz.width/(double)size.width, sz.height/(double)size.height, 1.0); + transform->RotateX(180); + + vtkSmartPointer image_reslice = vtkSmartPointer::New(); + image_reslice->SetResliceTransform(transform); + image_reslice->SetInputConnection(source->GetOutputPort()); + image_reslice->SetOutputDimensionality(2); + image_reslice->InterpolateOn(); + image_reslice->AutoCropOutputOn(); + image_reslice->Update(); + + mapper->SetInputConnection(image_reslice->GetOutputPort()); +} + +template<> cv::viz::WImageOverlay cv::viz::Widget::cast() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// image 3D widget implementation + +cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(source->GetOutputPort()); + + vtkSmartPointer plane = vtkSmartPointer::New(); + plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0); + plane->SetPoint2(-0.5 * size.width, 0.5 * size.height, 0.0); + + vtkSmartPointer textured_plane = vtkSmartPointer::New(); + textured_plane->SetInputConnection(plane->GetOutputPort()); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetInputConnection(textured_plane->GetOutputPort()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + actor->SetTexture(texture); + actor->GetProperty()->ShadingOff(); + actor->GetProperty()->LightingOff(); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d ¢er, const Vec3d &normal, const Vec3d &up_vector) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + // Compute the transformation matrix for drawing the camera frame in a scene + Vec3d n = normalize(normal); + Vec3d u = normalize(up_vector.cross(n)); + Vec3d v = n.cross(u); + Affine3d pose = makeTransformToGlobal(u, v, n, center); + + WImage3D image3d(image, size); + image3d.applyTransform(pose); + *this = image3d; +} + +void cv::viz::WImage3D::setImage(InputArray image) +{ + CV_Assert(!image.empty() && image.depth() == CV_8U); + + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("This widget does not support 3D image." && actor); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(source->GetOutputPort()); + + actor->SetTexture(texture); +} + +template<> cv::viz::WImage3D cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// camera position widget implementation + +namespace cv { namespace viz { namespace +{ + struct CameraPositionUtils + { + static vtkSmartPointer createFrustum(double aspect_ratio, double fovy, double scale) + { + vtkSmartPointer camera = vtkSmartPointer::New(); + camera->SetViewAngle(fovy); + camera->SetPosition(0.0, 0.0, 0.0); + camera->SetViewUp(0.0, 1.0, 0.0); + camera->SetFocalPoint(0.0, 0.0, 1.0); + camera->SetClippingRange(1e-9, scale); + + double planes_array[24]; + camera->GetFrustumPlanes(aspect_ratio, planes_array); + + vtkSmartPointer planes = vtkSmartPointer::New(); + planes->SetFrustumPlanes(planes_array); + + vtkSmartPointer frustumSource = vtkSmartPointer::New(); + frustumSource->SetPlanes(planes); + + vtkSmartPointer extract_edges = vtkSmartPointer::New(); + extract_edges->SetInputConnection(frustumSource->GetOutputPort()); + extract_edges->Update(); + + return extract_edges->GetOutput(); + } + + static Mat ensureColorImage(InputArray image) + { + Mat color(image.size(), CV_8UC3); + if (image.channels() == 1) + { + Vec3b *drow = color.ptr(); + for(int y = 0; y < color.rows; ++y) + { + const unsigned char *srow = image.getMat().ptr(y); + const unsigned char *send = srow + color.cols; + for(;srow < send;) + *drow++ = Vec3b::all(*srow++); + } + } + else + image.copyTo(color); + return color; + } + }; +}}} + +cv::viz::WCameraPosition::WCameraPosition(double scale) +{ + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale))); + mapper->SetScalarModeToUsePointData(); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color) +{ + double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2); + + // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) + double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI; + double aspect_ratio = f_y / f_x; + + vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color) +{ + double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5); + double fovy = fov[1] * 180 / CV_PI; + + vtkSmartPointer polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, polydata); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color) +{ + CV_Assert(!_image.empty() && _image.depth() == CV_8U); + Mat image = CameraPositionUtils::ensureColorImage(_image); + image.at(0, 0) = Vec3d(color.val); //workaround of VTK limitation + + double f_y = K(1,1), c_y = K(1,2); + // Assuming that this is an ideal camera (c_y and c_x are at the center of the image) + double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI; + double far_end_height = 2.00 * c_y * scale / f_y; + double aspect_ratio = image.cols/(double)image.rows; + double image_scale = far_end_height/image.rows; + + WImage3D image_widget(image, Size2d(image.size()) * image_scale); + image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale))); + vtkSmartPointer plane = getPolyData(image_widget); + + vtkSmartPointer frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + // Frustum needs to be textured or else it can't be combined with image + vtkSmartPointer frustum_texture = vtkSmartPointer::New(); + VtkUtils::SetInputData(frustum_texture, frustum); + frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel + frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + append_filter->AddInputConnection(frustum_texture->GetOutputPort()); + VtkUtils::AddInputData(append_filter, plane); + + vtkSmartPointer actor = getActor(image_widget); + actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort()); + WidgetAccessor::setProp(*this, actor); +} + +cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, InputArray _image, double scale, const Color &color) +{ + CV_Assert(!_image.empty() && _image.depth() == CV_8U); + Mat image = CameraPositionUtils::ensureColorImage(_image); + image.at(0, 0) = Vec3d(color.val); //workaround of VTK limitation + + double fovy = fov[1] * 180.0 / CV_PI; + double far_end_height = 2.0 * scale * tan(fov[1] * 0.5); + double aspect_ratio = image.cols/(double)image.rows; + double image_scale = far_end_height/image.rows; + + WImage3D image_widget(image, Size2d(image.size()) * image_scale); + image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale))); + vtkSmartPointer plane = getPolyData(image_widget); + + vtkSmartPointer frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale); + + // Frustum needs to be textured or else it can't be combined with image + vtkSmartPointer frustum_texture = vtkSmartPointer::New(); + VtkUtils::SetInputData(frustum_texture, frustum); + frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel + frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + append_filter->AddInputConnection(frustum_texture->GetOutputPort()); + VtkUtils::AddInputData(append_filter, plane); + + vtkSmartPointer actor = getActor(image_widget); + actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort()); + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WCameraPosition cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// trajectory widget implementation + +cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color) +{ + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + // Bitwise and with 3 in order to limit the domain to 2 bits + if (display_mode & WTrajectory::PATH) + { + Mat points = vtkTrajectorySource::ExtractPoints(_path); + vtkSmartPointer polydata = getPolyData(WPolyLine(points, color)); + VtkUtils::AddInputData(append_filter, polydata); + } + + if (display_mode & WTrajectory::FRAMES) + { + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCoordinateSystem(scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + + append_filter->AddInputConnection(tensor_glyph->GetOutputPort()); + } + append_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + mapper->SetScalarModeToUsePointData(); + mapper->SetScalarRange(0, 255); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WTrajectory cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WTrajectoryFrustums widget implementation + +cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33d &K, double scale, const Color &color) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCameraPosition(K, scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + tensor_glyph->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color) +{ + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetTrajectory(_path); + + vtkSmartPointer glyph = getPolyData(WCameraPosition(fov, scale)); + + vtkSmartPointer tensor_glyph = vtkSmartPointer::New(); + tensor_glyph->SetInputConnection(source->GetOutputPort()); + VtkUtils::SetSourceData(tensor_glyph, glyph); + tensor_glyph->ExtractEigenvaluesOff(); // Treat as a rotation matrix, not as something with eigenvalues + tensor_glyph->ThreeGlyphsOff(); + tensor_glyph->SymmetricOff(); + tensor_glyph->ColorGlyphsOff(); + tensor_glyph->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); + setColor(color); +} + +template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// WTrajectorySpheres widget implementation + +cv::viz::WTrajectorySpheres::WTrajectorySpheres(InputArray _path, double line_length, double radius, const Color &from, const Color &to) +{ + CV_Assert(_path.kind() == _InputArray::STD_VECTOR || _path.kind() == _InputArray::MAT); + CV_Assert(_path.type() == CV_32FC(16) || _path.type() == CV_64FC(16)); + + Mat path64; + _path.getMat().convertTo(path64, CV_64F); + Affine3d *traj = path64.ptr(); + size_t total = path64.total(); + + vtkSmartPointer append_filter = vtkSmartPointer::New(); + + for(size_t i = 0; i < total; ++i) + { + Vec3d curr = traj[i].translation(); + + vtkSmartPointer sphere_source = vtkSmartPointer::New(); + sphere_source->SetCenter(curr.val); + sphere_source->SetRadius( (i == 0) ? 2 * radius : radius ); + sphere_source->Update(); + + double alpha = static_cast(i)/total; + Color c = from * (1 - alpha) + to * alpha; + + vtkSmartPointer polydata = sphere_source->GetOutput(); + polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c)); + VtkUtils::AddInputData(append_filter, polydata); + + if (i > 0) + { + Vec3d prev = traj[i-1].translation(); + Vec3d lvec = prev - curr; + + if(norm(lvec) > line_length) + lvec = normalize(lvec) * line_length; + + Vec3d lend = curr + lvec; + + vtkSmartPointer line_source = vtkSmartPointer::New(); + line_source->SetPoint1(curr.val); + line_source->SetPoint2(lend.val); + line_source->Update(); + vtkSmartPointer polydata_ = line_source->GetOutput(); + polydata_->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata_->GetNumberOfCells(), c)); + VtkUtils::AddInputData(append_filter, polydata_); + } + } + append_filter->Update(); + + vtkSmartPointer mapper = vtkSmartPointer::New(); + mapper->SetScalarModeToUseCellData(); + VtkUtils::SetInputData(mapper, append_filter->GetOutput()); + + vtkSmartPointer actor = vtkSmartPointer::New(); + actor->SetMapper(mapper); + + WidgetAccessor::setProp(*this, actor); +} + +template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} diff --git a/modules/viz/src/types.cpp b/modules/viz/src/types.cpp index 861a78318..2e32a6327 100644 --- a/modules/viz/src/types.cpp +++ b/modules/viz/src/types.cpp @@ -41,138 +41,63 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #include "precomp.hpp" //////////////////////////////////////////////////////////////////// -/// cv::viz::KeyboardEvent +/// Events -cv::viz::KeyboardEvent::KeyboardEvent(bool _action, const String& _key_sym, unsigned char key, bool alt, bool ctrl, bool shift) - : action_(_action), modifiers_(0), key_code_(key), key_sym_(_key_sym) -{ - if (alt) - modifiers_ = Alt; +cv::viz::KeyboardEvent::KeyboardEvent(Action _action, const String& _symbol, unsigned char _code, int _modifiers) + : action(_action), symbol(_symbol), code(_code), modifiers(_modifiers) {} - if (ctrl) - modifiers_ |= Ctrl; - - if (shift) - modifiers_ |= Shift; -} - -bool cv::viz::KeyboardEvent::isAltPressed() const { return (modifiers_ & Alt) != 0; } -bool cv::viz::KeyboardEvent::isCtrlPressed() const { return (modifiers_ & Ctrl) != 0; } -bool cv::viz::KeyboardEvent::isShiftPressed() const { return (modifiers_ & Shift) != 0; } -unsigned char cv::viz::KeyboardEvent::getKeyCode() const { return key_code_; } -const cv::String& cv::viz::KeyboardEvent::getKeySym() const { return key_sym_; } -bool cv::viz::KeyboardEvent::keyDown() const { return action_; } -bool cv::viz::KeyboardEvent::keyUp() const { return !action_; } - -//////////////////////////////////////////////////////////////////// -/// cv::viz::MouseEvent - -cv::viz::MouseEvent::MouseEvent(const Type& _type, const MouseButton& _button, const Point& _p, bool alt, bool ctrl, bool shift) - : type(_type), button(_button), pointer(_p), key_state(0) -{ - if (alt) - key_state = KeyboardEvent::Alt; - - if (ctrl) - key_state |= KeyboardEvent::Ctrl; - - if (shift) - key_state |= KeyboardEvent::Shift; -} +cv::viz::MouseEvent::MouseEvent(const Type& _type, const MouseButton& _button, const Point& _pointer, int _modifiers) + : type(_type), button(_button), pointer(_pointer), modifiers(_modifiers) {} //////////////////////////////////////////////////////////////////// /// cv::viz::Mesh3d -struct cv::viz::Mesh3d::loadMeshImpl +cv::viz::Mesh cv::viz::Mesh::load(const String& file) { - static cv::viz::Mesh3d loadMesh(const String &file) + vtkSmartPointer reader = vtkSmartPointer::New(); + reader->SetFileName(file.c_str()); + reader->Update(); + + vtkSmartPointer polydata = reader->GetOutput(); + CV_Assert("File does not exist or file format is not supported." && polydata); + + Mesh mesh; + vtkSmartPointer sink = vtkSmartPointer::New(); + sink->SetOutput(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords); + sink->SetInputConnection(reader->GetOutputPort()); + sink->Write(); + + // Now handle the polygons + vtkSmartPointer polygons = polydata->GetPolys(); + mesh.polygons.create(1, polygons->GetSize(), CV_32SC1); + int* poly_ptr = mesh.polygons.ptr(); + + polygons->InitTraversal(); + vtkIdType nr_cell_points, *cell_points; + while (polygons->GetNextCell(nr_cell_points, cell_points)) { - Mesh3d mesh; - - vtkSmartPointer reader = vtkSmartPointer::New(); - reader->SetFileName(file.c_str()); - reader->Update(); - - vtkSmartPointer poly_data = reader->GetOutput(); - CV_Assert("File does not exist or file format is not supported." && poly_data); - - vtkSmartPointer mesh_points = poly_data->GetPoints(); - vtkIdType nr_points = mesh_points->GetNumberOfPoints(); - - mesh.cloud.create(1, nr_points, CV_32FC3); - - Vec3f *mesh_cloud = mesh.cloud.ptr(); - for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints(); i++) - { - Vec3d point; - mesh_points->GetPoint(i, point.val); - mesh_cloud[i] = point; - } - - // Then the color information, if any - vtkUnsignedCharArray* poly_colors = 0; - if (poly_data->GetPointData()) - poly_colors = vtkUnsignedCharArray::SafeDownCast(poly_data->GetPointData()->GetScalars()); - - if (poly_colors && (poly_colors->GetNumberOfComponents() == 3)) - { - mesh.colors.create(1, nr_points, CV_8UC3); - Vec3b *mesh_colors = mesh.colors.ptr(); - - for (vtkIdType i = 0; i < mesh_points->GetNumberOfPoints(); i++) - { - Vec3b point_color; - poly_colors->GetTupleValue(i, point_color.val); - - std::swap(point_color[0], point_color[2]); // RGB -> BGR - mesh_colors[i] = point_color; - } - } - else - mesh.colors.release(); - - // Now handle the polygons - vtkIdType* cell_points; - vtkIdType nr_cell_points; - vtkCellArray * mesh_polygons = poly_data->GetPolys(); - mesh_polygons->InitTraversal(); - - mesh.polygons.create(1, mesh_polygons->GetSize(), CV_32SC1); - - int* polygons = mesh.polygons.ptr(); - while (mesh_polygons->GetNextCell(nr_cell_points, cell_points)) - { - *polygons++ = nr_cell_points; - for (int i = 0; i < nr_cell_points; ++i) - *polygons++ = static_cast(cell_points[i]); - } - - return mesh; + *poly_ptr++ = nr_cell_points; + for (vtkIdType i = 0; i < nr_cell_points; ++i) + *poly_ptr++ = (int)cell_points[i]; } -}; -cv::viz::Mesh3d cv::viz::Mesh3d::loadMesh(const String& file) -{ - return loadMeshImpl::loadMesh(file); + return mesh; } //////////////////////////////////////////////////////////////////// /// Camera implementation -cv::viz::Camera::Camera(float f_x, float f_y, float c_x, float c_y, const Size &window_size) +cv::viz::Camera::Camera(double fx, double fy, double cx, double cy, const Size &window_size) { - init(f_x, f_y, c_x, c_y, window_size); + init(fx, fy, cx, cy, window_size); } -cv::viz::Camera::Camera(const Vec2f &fov, const Size &window_size) +cv::viz::Camera::Camera(const Vec2d &fov, const Size &window_size) { CV_Assert(window_size.width > 0 && window_size.height > 0); setClip(Vec2d(0.01, 1000.01)); // Default clipping @@ -183,16 +108,16 @@ cv::viz::Camera::Camera(const Vec2f &fov, const Size &window_size) focal_ = Vec2f(principal_point_[0] / tan(fov_[0]*0.5f), principal_point_[1] / tan(fov_[1]*0.5f)); } -cv::viz::Camera::Camera(const cv::Matx33f & K, const Size &window_size) +cv::viz::Camera::Camera(const cv::Matx33d & K, const Size &window_size) { - float f_x = K(0,0); - float f_y = K(1,1); - float c_x = K(0,2); - float c_y = K(1,2); + double f_x = K(0,0); + double f_y = K(1,1); + double c_x = K(0,2); + double c_y = K(1,2); init(f_x, f_y, c_x, c_y, window_size); } -cv::viz::Camera::Camera(const Matx44f &proj, const Size &window_size) +cv::viz::Camera::Camera(const Matx44d &proj, const Size &window_size) { CV_Assert(window_size.width > 0 && window_size.height > 0); @@ -205,34 +130,32 @@ cv::viz::Camera::Camera(const Matx44f &proj, const Size &window_size) double epsilon = 2.2204460492503131e-16; - if (fabs(left-right) < epsilon) principal_point_[0] = static_cast(window_size.width) * 0.5f; - else principal_point_[0] = (left * static_cast(window_size.width)) / (left - right); - focal_[0] = -near * principal_point_[0] / left; + principal_point_[0] = fabs(left-right) < epsilon ? window_size.width * 0.5 : (left * window_size.width) / (left - right); + principal_point_[1] = fabs(top-bottom) < epsilon ? window_size.height * 0.5 : (top * window_size.height) / (top - bottom); - if (fabs(top-bottom) < epsilon) principal_point_[1] = static_cast(window_size.height) * 0.5f; - else principal_point_[1] = (top * static_cast(window_size.height)) / (top - bottom); - focal_[1] = near * principal_point_[1] / top; + focal_[0] = -near * principal_point_[0] / left; + focal_[1] = near * principal_point_[1] / top; setClip(Vec2d(near, far)); - fov_[0] = (atan2(principal_point_[0],focal_[0]) + atan2(window_size.width-principal_point_[0],focal_[0])); - fov_[1] = (atan2(principal_point_[1],focal_[1]) + atan2(window_size.height-principal_point_[1],focal_[1])); + fov_[0] = atan2(principal_point_[0], focal_[0]) + atan2(window_size.width-principal_point_[0], focal_[0]); + fov_[1] = atan2(principal_point_[1], focal_[1]) + atan2(window_size.height-principal_point_[1], focal_[1]); window_size_ = window_size; } -void cv::viz::Camera::init(float f_x, float f_y, float c_x, float c_y, const Size &window_size) +void cv::viz::Camera::init(double fx, double fy, double cx, double cy, const Size &window_size) { CV_Assert(window_size.width > 0 && window_size.height > 0); setClip(Vec2d(0.01, 1000.01));// Default clipping - fov_[0] = (atan2(c_x,f_x) + atan2(window_size.width-c_x,f_x)); - fov_[1] = (atan2(c_y,f_y) + atan2(window_size.height-c_y,f_y)); + fov_[0] = atan2(cx, fx) + atan2(window_size.width - cx, fx); + fov_[1] = atan2(cy, fy) + atan2(window_size.height - cy, fy); - principal_point_[0] = c_x; - principal_point_[1] = c_y; + principal_point_[0] = cx; + principal_point_[1] = cy; - focal_[0] = f_x; - focal_[1] = f_y; + focal_[0] = fx; + focal_[1] = fy; window_size_ = window_size; } @@ -254,7 +177,7 @@ void cv::viz::Camera::setWindowSize(const Size &window_size) window_size_ = window_size; } -void cv::viz::Camera::computeProjectionMatrix(Matx44f &proj) const +void cv::viz::Camera::computeProjectionMatrix(Matx44d &proj) const { double top = clip_[0] * principal_point_[1] / focal_[1]; double left = -clip_[0] * principal_point_[0] / focal_[0]; @@ -278,13 +201,6 @@ void cv::viz::Camera::computeProjectionMatrix(Matx44f &proj) const cv::viz::Camera cv::viz::Camera::KinectCamera(const Size &window_size) { - // Without distortion, RGB Camera - // Received from http://nicolas.burrus.name/index.php/Research/KinectCalibration - Matx33f K = Matx33f::zeros(); - K(0,0) = 5.2921508098293293e+02; - K(0,2) = 3.2894272028759258e+02; - K(1,1) = 5.2556393630057437e+02; - K(1,2) = 2.6748068171871557e+02; - K(2,2) = 1.0f; + Matx33d K(525.0, 0.0, 320.0, 0.0, 525.0, 240.0, 0.0, 0.0, 1.0); return Camera(K, window_size); } diff --git a/modules/viz/src/viz.cpp b/modules/viz/src/viz.cpp deleted file mode 100644 index 6a08dfa34..000000000 --- a/modules/viz/src/viz.cpp +++ /dev/null @@ -1,165 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -// Authors: -// * Ozan Tonkal, ozantonkal@gmail.com -// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com -// -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// -//M*/ - -#include "precomp.hpp" - -cv::Affine3f cv::viz::makeTransformToGlobal(const Vec3f& axis_x, const Vec3f& axis_y, const Vec3f& axis_z, const Vec3f& origin) -{ - Affine3f::Mat3 R(axis_x[0], axis_y[0], axis_z[0], - axis_x[1], axis_y[1], axis_z[1], - axis_x[2], axis_y[2], axis_z[2]); - - return Affine3f(R, origin); -} - -cv::Affine3f cv::viz::makeCameraPose(const Vec3f& position, const Vec3f& focal_point, const Vec3f& y_dir) -{ - // Compute the transformation matrix for drawing the camera frame in a scene - Vec3f n = normalize(focal_point - position); - Vec3f u = normalize(y_dir.cross(n)); - Vec3f v = n.cross(u); - - return makeTransformToGlobal(u, v, n, position); -} - -vtkSmartPointer cv::viz::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; -} - -cv::Matx44f cv::viz::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; -} - -namespace cv { namespace viz -{ - template Vec<_Tp, 3>* vtkpoints_data(vtkSmartPointer& points); - - template<> Vec3f* vtkpoints_data(vtkSmartPointer& points) - { - CV_Assert(points->GetDataType() == VTK_FLOAT); - vtkDataArray *data = points->GetData(); - float *pointer = static_cast(data)->GetPointer(0); - return reinterpret_cast(pointer); - } - - template<> Vec3d* vtkpoints_data(vtkSmartPointer& points) - { - CV_Assert(points->GetDataType() == VTK_DOUBLE); - vtkDataArray *data = points->GetData(); - double *pointer = static_cast(data)->GetPointer(0); - return reinterpret_cast(pointer); - } -}} - -/////////////////////////////////////////////////////////////////////////////////////////////// -/// VizStorage implementation - -cv::viz::VizMap cv::viz::VizStorage::storage; -void cv::viz::VizStorage::unregisterAll() { storage.clear(); } - -cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name) -{ - String name = generateWindowName(window_name); - VizMap::iterator vm_itr = storage.find(name); - CV_Assert(vm_itr != storage.end()); - return vm_itr->second; -} - -void cv::viz::VizStorage::add(const Viz3d& window) -{ - String window_name = window.getWindowName(); - VizMap::iterator vm_itr = storage.find(window_name); - CV_Assert(vm_itr == storage.end()); - storage.insert(std::make_pair(window_name, window)); -} - -bool cv::viz::VizStorage::windowExists(const String &window_name) -{ - String name = generateWindowName(window_name); - return storage.find(name) != storage.end(); -} - -void cv::viz::VizStorage::removeUnreferenced() -{ - for(VizMap::iterator pos = storage.begin(); pos != storage.end();) - if(pos->second.impl_->ref_counter == 1) - storage.erase(pos++); - else - ++pos; -} - -cv::String cv::viz::VizStorage::generateWindowName(const String &window_name) -{ - String output = "Viz"; - // Already is Viz - if (window_name == output) - return output; - - String prefixed = output + " - "; - if (window_name.substr(0, prefixed.length()) == prefixed) - output = window_name; // Already has "Viz - " - else if (window_name.substr(0, output.length()) == output) - output = prefixed + window_name; // Doesn't have prefix - else - output = (window_name == "" ? output : prefixed + window_name); - - return output; -} - -cv::viz::Viz3d cv::viz::get(const String &window_name) { return Viz3d (window_name); } -void cv::viz::unregisterAllWindows() { VizStorage::unregisterAll(); } diff --git a/modules/viz/src/viz3d.cpp b/modules/viz/src/viz3d.cpp index 08cb880de..56f978c0e 100644 --- a/modules/viz/src/viz3d.cpp +++ b/modules/viz/src/viz3d.cpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #include "precomp.hpp" @@ -104,6 +101,7 @@ void cv::viz::Viz3d::release() void cv::viz::Viz3d::spin() { impl_->spin(); } void cv::viz::Viz3d::spinOnce(int time, bool force_redraw) { impl_->spinOnce(time, force_redraw); } bool cv::viz::Viz3d::wasStopped() const { return impl_->wasStopped(); } +void cv::viz::Viz3d::close() { impl_->close(); } void cv::viz::Viz3d::registerKeyboardCallback(KeyboardCallback callback, void* cookie) { impl_->registerKeyboardCallback(callback, cookie); } @@ -111,18 +109,21 @@ void cv::viz::Viz3d::registerKeyboardCallback(KeyboardCallback callback, void* c void cv::viz::Viz3d::registerMouseCallback(MouseCallback callback, void* cookie) { impl_->registerMouseCallback(callback, cookie); } -void cv::viz::Viz3d::showWidget(const String &id, const Widget &widget, const Affine3f &pose) { impl_->showWidget(id, widget, pose); } +void cv::viz::Viz3d::showWidget(const String &id, const Widget &widget, const Affine3d &pose) { impl_->showWidget(id, widget, pose); } void cv::viz::Viz3d::removeWidget(const String &id) { impl_->removeWidget(id); } cv::viz::Widget cv::viz::Viz3d::getWidget(const String &id) const { return impl_->getWidget(id); } void cv::viz::Viz3d::removeAllWidgets() { impl_->removeAllWidgets(); } -void cv::viz::Viz3d::setWidgetPose(const String &id, const Affine3f &pose) { impl_->setWidgetPose(id, pose); } -void cv::viz::Viz3d::updateWidgetPose(const String &id, const Affine3f &pose) { impl_->updateWidgetPose(id, pose); } -cv::Affine3f cv::viz::Viz3d::getWidgetPose(const String &id) const { return impl_->getWidgetPose(id); } + +void cv::viz::Viz3d::showImage(InputArray image, const Size& window_size) { impl_->showImage(image, window_size); } + +void cv::viz::Viz3d::setWidgetPose(const String &id, const Affine3d &pose) { impl_->setWidgetPose(id, pose); } +void cv::viz::Viz3d::updateWidgetPose(const String &id, const Affine3d &pose) { impl_->updateWidgetPose(id, pose); } +cv::Affine3d cv::viz::Viz3d::getWidgetPose(const String &id) const { return impl_->getWidgetPose(id); } void cv::viz::Viz3d::setCamera(const Camera &camera) { impl_->setCamera(camera); } cv::viz::Camera cv::viz::Viz3d::getCamera() const { return impl_->getCamera(); } -void cv::viz::Viz3d::setViewerPose(const Affine3f &pose) { impl_->setViewerPose(pose); } -cv::Affine3f cv::viz::Viz3d::getViewerPose() { return impl_->getViewerPose(); } +void cv::viz::Viz3d::setViewerPose(const Affine3d &pose) { impl_->setViewerPose(pose); } +cv::Affine3d cv::viz::Viz3d::getViewerPose() { return impl_->getViewerPose(); } void cv::viz::Viz3d::resetCameraViewpoint(const String &id) { impl_->resetCameraViewpoint(id); } void cv::viz::Viz3d::resetCamera() { impl_->resetCamera(); } @@ -131,17 +132,17 @@ void cv::viz::Viz3d::convertToWindowCoordinates(const Point3d &pt, Point3d &wind void cv::viz::Viz3d::converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction) { impl_->converTo3DRay(window_coord, origin, direction); } cv::Size cv::viz::Viz3d::getWindowSize() const { return impl_->getWindowSize(); } -void cv::viz::Viz3d::setWindowSize(const Size &window_size) { impl_->setWindowSize(window_size.width, window_size.height); } +void cv::viz::Viz3d::setWindowSize(const Size &window_size) { impl_->setWindowSize(window_size); } cv::String cv::viz::Viz3d::getWindowName() const { return impl_->getWindowName(); } void cv::viz::Viz3d::saveScreenshot(const String &file) { impl_->saveScreenshot(file); } -void cv::viz::Viz3d::setWindowPosition(int x, int y) { impl_->setWindowPosition(x,y); } +void cv::viz::Viz3d::setWindowPosition(const Point& window_position) { impl_->setWindowPosition(window_position); } void cv::viz::Viz3d::setFullScreen(bool mode) { impl_->setFullScreen(mode); } -void cv::viz::Viz3d::setBackgroundColor(const Color& color) { impl_->setBackgroundColor(color); } +void cv::viz::Viz3d::setBackgroundColor(const Color& color, const Color& color2) { impl_->setBackgroundColor(color, color2); } + +void cv::viz::Viz3d::setBackgroundTexture(InputArray image) { impl_->setBackgroundTexture(image); } +void cv::viz::Viz3d::setBackgroundMeshLab() {impl_->setBackgroundMeshLab(); } void cv::viz::Viz3d::setRenderingProperty(const String &id, int property, double value) { getWidget(id).setRenderingProperty(property, value); } double cv::viz::Viz3d::getRenderingProperty(const String &id, int property) { return getWidget(id).getRenderingProperty(property); } -void cv::viz::Viz3d::setDesiredUpdateRate(double rate) { impl_->setDesiredUpdateRate(rate); } -double cv::viz::Viz3d::getDesiredUpdateRate() { return impl_->getDesiredUpdateRate(); } - void cv::viz::Viz3d::setRepresentation(int representation) { impl_->setRepresentation(representation); } diff --git a/modules/viz/src/viz3d_impl.hpp b/modules/viz/src/viz3d_impl.hpp deleted file mode 100644 index 59f45a8fa..000000000 --- a/modules/viz/src/viz3d_impl.hpp +++ /dev/null @@ -1,368 +0,0 @@ -/*M/////////////////////////////////////////////////////////////////////////////////////// -// -// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. -// -// By downloading, copying, installing or using the software you agree to this license. -// If you do not agree to this license, do not download, install, -// copy or use the software. -// -// -// License Agreement -// For Open Source Computer Vision Library -// -// Copyright (C) 2013, OpenCV Foundation, all rights reserved. -// Third party copyrights are property of their respective owners. -// -// Redistribution and use in source and binary forms, with or without modification, -// are permitted provided that the following conditions are met: -// -// * Redistribution's of source code must retain the above copyright notice, -// this list of conditions and the following disclaimer. -// -// * Redistribution's in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// * The name of the copyright holders may not be used to endorse or promote products -// derived from this software without specific prior written permission. -// -// This software is provided by the copyright holders and contributors "as is" and -// any express or implied warranties, including, but not limited to, the implied -// warranties of merchantability and fitness for a particular purpose are disclaimed. -// In no event shall the Intel Corporation or contributors be liable for any direct, -// indirect, incidental, special, exemplary, or consequential damages -// (including, but not limited to, procurement of substitute goods or services; -// loss of use, data, or profits; or business interruption) however caused -// and on any theory of liability, whether in contract, strict liability, -// or tort (including negligence or otherwise) arising in any way out of -// the use of this software, even if advised of the possibility of such damage. -// -// Authors: -// * Ozan Tonkal, ozantonkal@gmail.com -// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com -// -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// -//M*/ - -#ifndef __OPENCV_VIZ_VIZ3D_IMPL_HPP__ -#define __OPENCV_VIZ_VIZ3D_IMPL_HPP__ - -struct cv::viz::Viz3d::VizImpl -{ -public: - typedef Viz3d::KeyboardCallback KeyboardCallback; - typedef Viz3d::MouseCallback MouseCallback; - - int ref_counter; - - VizImpl(const String &name); - virtual ~VizImpl(); - - void showWidget(const String &id, const Widget &widget, const Affine3f &pose = Affine3f::Identity()); - void removeWidget(const String &id); - Widget getWidget(const String &id) const; - void removeAllWidgets(); - - void setWidgetPose(const String &id, const Affine3f &pose); - void updateWidgetPose(const String &id, const Affine3f &pose); - Affine3f getWidgetPose(const String &id) const; - - void setDesiredUpdateRate(double rate); - double getDesiredUpdateRate(); - - /** \brief Returns true when the user tried to close the window */ - bool wasStopped() const { if (interactor_ != NULL) return (stopped_); else return true; } - - /** \brief Set the stopped flag back to false */ - void resetStoppedFlag() { if (interactor_ != NULL) stopped_ = false; } - - /** \brief Stop the interaction and close the visualizaton window. */ - void close() - { - stopped_ = true; - if (interactor_) - { - interactor_->GetRenderWindow()->Finalize(); - interactor_->TerminateApp(); // This tends to close the window... - } - } - - void setRepresentation(int representation); - - void setCamera(const Camera &camera); - Camera getCamera() const; - - /** \brief Reset the camera to a given widget */ - void resetCameraViewpoint(const String& id); - void resetCamera(); - - void setViewerPose(const Affine3f &pose); - Affine3f getViewerPose(); - - void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord); - void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction); - - void saveScreenshot(const String &file); - void setWindowPosition(int x, int y); - Size getWindowSize() const; - void setWindowSize(int xw, int yw); - void setFullScreen(bool mode); - String getWindowName() const; - void setBackgroundColor(const Color& color); - - void spin(); - void spinOnce(int time = 1, bool force_redraw = false); - - void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); - void registerMouseCallback(MouseCallback callback, void* cookie = 0); - -private: - vtkSmartPointer interactor_; - - struct ExitMainLoopTimerCallback : public vtkCommand - { - static ExitMainLoopTimerCallback* New() { return new ExitMainLoopTimerCallback; } - virtual void Execute(vtkObject* vtkNotUsed(caller), unsigned long event_id, void* call_data) - { - if (event_id != vtkCommand::TimerEvent) - return; - - int timer_id = *reinterpret_cast(call_data); - if (timer_id != right_timer_id) - return; - - // Stop vtk loop and send notification to app to wake it up - viz_->interactor_->TerminateApp(); - } - int right_timer_id; - VizImpl* viz_; - }; - - struct ExitCallback : public vtkCommand - { - static ExitCallback* New() { return new ExitCallback; } - virtual void Execute(vtkObject*, unsigned long event_id, void*) - { - if (event_id == vtkCommand::ExitEvent) - { - viz_->stopped_ = true; - viz_->interactor_->GetRenderWindow()->Finalize(); - viz_->interactor_->TerminateApp(); - } - } - VizImpl* viz_; - }; - - /** \brief Set to false if the interaction loop is running. */ - bool stopped_; - - double s_lastDone_; - - /** \brief Global timer ID. Used in destructor only. */ - int timer_id_; - - /** \brief Callback object enabling us to leave the main loop, when a timer fires. */ - vtkSmartPointer exit_main_loop_timer_callback_; - vtkSmartPointer exit_callback_; - - vtkSmartPointer renderer_; - vtkSmartPointer window_; - - /** \brief The render window interactor style. */ - vtkSmartPointer style_; - - /** \brief Internal list with actor pointers and name IDs for all widget actors */ - cv::Ptr widget_actor_map_; - - /** \brief Boolean that holds whether or not the camera parameters were manually initialized*/ - bool camera_set_; - - bool removeActorFromRenderer(const vtkSmartPointer &actor); -}; - - - -namespace cv -{ - namespace viz - { - vtkSmartPointer convertToVtkMatrix(const cv::Matx44f &m); - cv::Matx44f convertToMatx(const vtkSmartPointer& vtk_matrix); - - struct NanFilter - { - template - struct Impl - { - typedef Vec<_Tp, 3> _Out; - - static _Out* copy(const Mat& source, _Out* output, const Mat& nan_mask) - { - CV_Assert(DataDepth<_Tp>::value == source.depth() && source.size() == nan_mask.size()); - CV_Assert(nan_mask.channels() == 3 || nan_mask.channels() == 4); - CV_DbgAssert(DataDepth<_Msk>::value == nan_mask.depth()); - - int s_chs = source.channels(); - int m_chs = nan_mask.channels(); - - for (int y = 0; y < source.rows; ++y) - { - const _Tp* srow = source.ptr<_Tp>(y); - const _Msk* mrow = nan_mask.ptr<_Msk>(y); - - for (int x = 0; x < source.cols; ++x, srow += s_chs, mrow += m_chs) - if (!isNan(mrow[0]) && !isNan(mrow[1]) && !isNan(mrow[2])) - *output++ = _Out(srow); - } - return output; - } - - static _Out* copyColor(const Mat& source, _Out* output, const Mat& nan_mask) - { - CV_Assert(DataDepth<_Tp>::value == source.depth() && source.size() == nan_mask.size()); - CV_Assert(nan_mask.channels() == 3 || nan_mask.channels() == 4); - CV_DbgAssert(DataDepth<_Msk>::value == nan_mask.depth()); - - int s_chs = source.channels(); - int m_chs = nan_mask.channels(); - - for (int y = 0; y < source.rows; ++y) - { - const _Tp* srow = source.ptr<_Tp>(y); - const _Msk* mrow = nan_mask.ptr<_Msk>(y); - - for (int x = 0; x < source.cols; ++x, srow += s_chs, mrow += m_chs) - if (!isNan(mrow[0]) && !isNan(mrow[1]) && !isNan(mrow[2])) - { - *output = _Out(srow); - std::swap((*output)[0], (*output)[2]); // BGR -> RGB - ++output; - } - } - return output; - } - }; - - template - static inline Vec<_Tp, 3>* copy(const Mat& source, Vec<_Tp, 3>* output, const Mat& nan_mask) - { - CV_Assert(nan_mask.depth() == CV_32F || nan_mask.depth() == CV_64F); - - typedef Vec<_Tp, 3>* (*copy_func)(const Mat&, Vec<_Tp, 3>*, const Mat&); - const static copy_func table[2] = { &NanFilter::Impl<_Tp, float>::copy, &NanFilter::Impl<_Tp, double>::copy }; - - return table[nan_mask.depth() - 5](source, output, nan_mask); - } - - template - static inline Vec<_Tp, 3>* copyColor(const Mat& source, Vec<_Tp, 3>* output, const Mat& nan_mask) - { - CV_Assert(nan_mask.depth() == CV_32F || nan_mask.depth() == CV_64F); - - typedef Vec<_Tp, 3>* (*copy_func)(const Mat&, Vec<_Tp, 3>*, const Mat&); - const static copy_func table[2] = { &NanFilter::Impl<_Tp, float>::copyColor, &NanFilter::Impl<_Tp, double>::copyColor }; - - return table[nan_mask.depth() - 5](source, output, nan_mask); - } - }; - - struct ApplyAffine - { - const Affine3f& affine_; - ApplyAffine(const Affine3f& affine) : affine_(affine) {} - - template Point3_<_Tp> operator()(const Point3_<_Tp>& p) const { return affine_ * p; } - - template Vec<_Tp, 3> operator()(const Vec<_Tp, 3>& v) const - { - const float* m = affine_.matrix.val; - - Vec<_Tp, 3> result; - result[0] = (_Tp)(m[0] * v[0] + m[1] * v[1] + m[ 2] * v[2] + m[ 3]); - result[1] = (_Tp)(m[4] * v[0] + m[5] * v[1] + m[ 6] * v[2] + m[ 7]); - result[2] = (_Tp)(m[8] * v[0] + m[9] * v[1] + m[10] * v[2] + m[11]); - return result; - } - - private: - ApplyAffine(const ApplyAffine&); - ApplyAffine& operator=(const ApplyAffine&); - }; - - - inline Color vtkcolor(const Color& color) - { - Color scaled_color = color * (1.0/255.0); - std::swap(scaled_color[0], scaled_color[2]); - return scaled_color; - } - - inline Vec3d vtkpoint(const Point3f& point) { return Vec3d(point.x, point.y, point.z); } - template inline _Tp normalized(const _Tp& v) { return v * 1/cv::norm(v); } - - struct ConvertToVtkImage - { - struct Impl - { - static void copyImageMultiChannel(const Mat &image, vtkSmartPointer output) - { - int i_chs = image.channels(); - - for (int i = 0; i < image.rows; ++i) - { - const unsigned char * irows = image.ptr(i); - for (int j = 0; j < image.cols; ++j, irows += i_chs) - { - unsigned char * vrows = static_cast(output->GetScalarPointer(j,i,0)); - memcpy(vrows, irows, i_chs); - std::swap(vrows[0], vrows[2]); // BGR -> RGB - } - } - output->Modified(); - } - - static void copyImageSingleChannel(const Mat &image, vtkSmartPointer output) - { - for (int i = 0; i < image.rows; ++i) - { - const unsigned char * irows = image.ptr(i); - for (int j = 0; j < image.cols; ++j, ++irows) - { - unsigned char * vrows = static_cast(output->GetScalarPointer(j,i,0)); - *vrows = *irows; - } - } - output->Modified(); - } - }; - - static void convert(const Mat &image, vtkSmartPointer output) - { - // Create the vtk image - output->SetDimensions(image.cols, image.rows, 1); -#if VTK_MAJOR_VERSION <= 5 - output->SetNumberOfScalarComponents(image.channels()); - output->SetScalarTypeToUnsignedChar(); - output->AllocateScalars(); -#else - output->AllocateScalars(VTK_UNSIGNED_CHAR, image.channels()); -#endif - - int i_chs = image.channels(); - if (i_chs > 1) - { - // Multi channel images are handled differently because of BGR <-> RGB - Impl::copyImageMultiChannel(image, output); - } - else - { - Impl::copyImageSingleChannel(image, output); - } - } - }; - } -} - -#endif diff --git a/modules/viz/src/vizcore.cpp b/modules/viz/src/vizcore.cpp new file mode 100644 index 000000000..29d4b4688 --- /dev/null +++ b/modules/viz/src/vizcore.cpp @@ -0,0 +1,312 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +cv::Affine3d cv::viz::makeTransformToGlobal(const Vec3d& axis_x, const Vec3d& axis_y, const Vec3d& axis_z, const Vec3d& origin) +{ + Affine3d::Mat3 R(axis_x[0], axis_y[0], axis_z[0], + axis_x[1], axis_y[1], axis_z[1], + axis_x[2], axis_y[2], axis_z[2]); + + return Affine3d(R, origin); +} + +cv::Affine3d cv::viz::makeCameraPose(const Vec3d& position, const Vec3d& focal_point, const Vec3d& y_dir) +{ + // Compute the transformation matrix for drawing the camera frame in a scene + Vec3d n = normalize(focal_point - position); + Vec3d u = normalize(y_dir.cross(n)); + Vec3d v = n.cross(u); + + return makeTransformToGlobal(u, v, n, position); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// VizStorage implementation + +cv::viz::VizMap cv::viz::VizStorage::storage; +void cv::viz::VizStorage::unregisterAll() { storage.clear(); } + +cv::viz::Viz3d& cv::viz::VizStorage::get(const String &window_name) +{ + String name = generateWindowName(window_name); + VizMap::iterator vm_itr = storage.find(name); + CV_Assert(vm_itr != storage.end()); + return vm_itr->second; +} + +void cv::viz::VizStorage::add(const Viz3d& window) +{ + String window_name = window.getWindowName(); + VizMap::iterator vm_itr = storage.find(window_name); + CV_Assert(vm_itr == storage.end()); + storage.insert(std::make_pair(window_name, window)); +} + +bool cv::viz::VizStorage::windowExists(const String &window_name) +{ + String name = generateWindowName(window_name); + return storage.find(name) != storage.end(); +} + +void cv::viz::VizStorage::removeUnreferenced() +{ + for(VizMap::iterator pos = storage.begin(); pos != storage.end();) + if(pos->second.impl_->ref_counter == 1) + storage.erase(pos++); + else + ++pos; +} + +cv::String cv::viz::VizStorage::generateWindowName(const String &window_name) +{ + String output = "Viz"; + // Already is Viz + if (window_name == output) + return output; + + String prefixed = output + " - "; + if (window_name.substr(0, prefixed.length()) == prefixed) + output = window_name; // Already has "Viz - " + else if (window_name.substr(0, output.length()) == output) + output = prefixed + window_name; // Doesn't have prefix + else + output = (window_name == "" ? output : prefixed + window_name); + + return output; +} + +cv::viz::Viz3d cv::viz::getWindowByName(const String &window_name) { return Viz3d (window_name); } +void cv::viz::unregisterAllWindows() { VizStorage::unregisterAll(); } + +cv::viz::Viz3d cv::viz::imshow(const String& window_name, InputArray image, const Size& window_size) +{ + Viz3d viz = getWindowByName(window_name); + viz.showImage(image, window_size); + return viz; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Read/write clouds. Supported formats: ply, stl, xyz, obj + +void cv::viz::writeCloud(const String& file, InputArray cloud, InputArray colors, InputArray normals, bool binary) +{ + CV_Assert(file.size() > 4 && "Extention is required"); + String extention = file.substr(file.size()-4); + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetColorCloudNormals(cloud, colors, normals); + + vtkSmartPointer writer; + if (extention == ".xyz") + { + writer = vtkSmartPointer::New(); + vtkXYZWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + } + else if (extention == ".ply") + { + writer = vtkSmartPointer::New(); + vtkPLYWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + vtkPLYWriter::SafeDownCast(writer)->SetFileType(binary ? VTK_BINARY : VTK_ASCII); + vtkPLYWriter::SafeDownCast(writer)->SetArrayName("Colors"); + } + else if (extention == ".obj") + { + writer = vtkSmartPointer::New(); + vtkOBJWriter::SafeDownCast(writer)->SetFileName(file.c_str()); + } + else + CV_Assert(!"Unsupported format"); + + writer->SetInputConnection(source->GetOutputPort()); + writer->Write(); +} + +cv::Mat cv::viz::readCloud(const String& file, OutputArray colors, OutputArray normals) +{ + CV_Assert(file.size() > 4 && "Extention is required"); + String extention = file.substr(file.size()-4); + + vtkSmartPointer reader; + if (extention == ".xyz") + { + reader = vtkSmartPointer::New(); + vtkSimplePointsReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".ply") + { + reader = vtkSmartPointer::New(); + CV_Assert(vtkPLYReader::CanReadFile(file.c_str())); + vtkPLYReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".obj") + { + reader = vtkSmartPointer::New(); + vtkOBJReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else if (extention == ".stl") + { + reader = vtkSmartPointer::New(); + vtkSTLReader::SafeDownCast(reader)->SetFileName(file.c_str()); + } + else + CV_Assert(!"Unsupported format"); + + cv::Mat cloud; + + vtkSmartPointer sink = vtkSmartPointer::New(); + sink->SetInputConnection(reader->GetOutputPort()); + sink->SetOutput(cloud, colors, normals); + sink->Write(); + + return cloud; +} + +cv::viz::Mesh cv::viz::readMesh(const String& file) { return Mesh::load(file); } + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Read/write poses and trajectories + +bool cv::viz::readPose(const String& file, Affine3d& pose, const String& tag) +{ + FileStorage fs(file, FileStorage::READ); + if (!fs.isOpened()) + return false; + + Mat hdr(pose.matrix, false); + fs[tag] >> hdr; + if (hdr.empty() || hdr.cols != pose.matrix.cols || hdr.rows != pose.matrix.rows) + return false; + + hdr.convertTo(pose.matrix, CV_64F); + return true; +} + +void cv::viz::writePose(const String& file, const Affine3d& pose, const String& tag) +{ + FileStorage fs(file, FileStorage::WRITE); + fs << tag << Mat(pose.matrix, false); +} + +void cv::viz::readTrajectory(OutputArray _traj, const String& files_format, int start, int end, const String& tag) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + + start = max(0, std::min(start, end)); + end = std::max(start, end); + + std::vector traj; + + for(int i = start; i < end; ++i) + { + Affine3d affine; + bool ok = readPose(cv::format(files_format.c_str(), i), affine, tag); + if (!ok) + break; + + traj.push_back(affine); + } + + Mat(traj).convertTo(_traj, _traj.depth()); +} + +void cv::viz::writeTrajectory(InputArray _traj, const String& files_format, int start, const String& tag) +{ + if (_traj.kind() == _InputArray::STD_VECTOR_MAT) + { + std::vector& v = *(std::vector*)_traj.getObj(); + + for(size_t i = 0, index = max(0, start); i < v.size(); ++i, ++index) + { + Affine3d affine; + Mat pose = v[i]; + CV_Assert(pose.type() == CV_32FC(16) || pose.type() == CV_64FC(16)); + pose.copyTo(affine.matrix); + writePose(cv::format(files_format.c_str(), index), affine, tag); + } + return; + } + + if (_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT) + { + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat traj = _traj.getMat(); + + if (traj.depth() == CV_32F) + for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index) + writePose(cv::format(files_format.c_str(), index), traj.at(i), tag); + + if (traj.depth() == CV_64F) + for(size_t i = 0, index = max(0, start); i < traj.total(); ++i, ++index) + writePose(cv::format(files_format.c_str(), index), traj.at(i), tag); + } + + CV_Assert(!"Unsupported array kind"); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// Computing normals for mesh + +void cv::viz::computeNormals(const Mesh& mesh, OutputArray _normals) +{ + vtkSmartPointer polydata = getPolyData(WMesh(mesh)); + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(polydata); + + vtkSmartPointer generic_normals = with_normals->GetPointData()->GetNormals(); + if(generic_normals) + { + Mat normals(1, generic_normals->GetNumberOfTuples(), CV_64FC3); + Vec3d *optr = normals.ptr(); + + for(int i = 0; i < generic_normals->GetNumberOfTuples(); ++i, ++optr) + generic_normals->GetTuple(i, optr->val); + + normals.convertTo(_normals, mesh.cloud.type()); + } + else + _normals.release(); +} diff --git a/modules/viz/src/viz3d_impl.cpp b/modules/viz/src/vizimpl.cpp similarity index 65% rename from modules/viz/src/viz3d_impl.cpp rename to modules/viz/src/vizimpl.cpp index b1173f645..5fa49e2f9 100644 --- a/modules/viz/src/viz3d_impl.cpp +++ b/modules/viz/src/vizimpl.cpp @@ -41,94 +41,143 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #include "precomp.hpp" -vtkRenderWindowInteractor* vtkRenderWindowInteractorFixNew(); - -#if 1 || !defined __APPLE__ -vtkRenderWindowInteractor* vtkRenderWindowInteractorFixNew() -{ - return vtkRenderWindowInteractor::New(); -} -#endif ///////////////////////////////////////////////////////////////////////////////////////////// -cv::viz::Viz3d::VizImpl::VizImpl(const String &name) - : s_lastDone_(0.0), style_(vtkSmartPointer::New()), widget_actor_map_(new WidgetActorMap) +cv::viz::Viz3d::VizImpl::VizImpl(const String &name) : spin_once_state_(false), + window_position_(Vec2i(std::numeric_limits::min())), widget_actor_map_(new WidgetActorMap) { renderer_ = vtkSmartPointer::New(); + window_name_ = VizStorage::generateWindowName(name); - // Create a RendererWindow + // Create render window window_ = vtkSmartPointer::New(); - - // Set the window size as 1/2 of the screen size cv::Vec2i window_size = cv::Vec2i(window_->GetScreenSize()) / 2; window_->SetSize(window_size.val); - window_->AddRenderer(renderer_); // Create the interactor style - style_->Initialize(); - style_->setRenderer(renderer_); + style_ = vtkSmartPointer::New(); style_->setWidgetActorMap(widget_actor_map_); style_->UseTimersOn(); + style_->Initialize(); - ///////////////////////////////////////////////// - interactor_ = vtkSmartPointer::Take(vtkRenderWindowInteractorFixNew()); + timer_callback_ = vtkSmartPointer::New(); + exit_callback_ = vtkSmartPointer::New(); + exit_callback_->viz = this; +} +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::TimerCallback::Execute(vtkObject* caller, unsigned long event_id, void* cookie) +{ + if (event_id == vtkCommand::TimerEvent && timer_id == *reinterpret_cast(cookie)) + { + vtkSmartPointer interactor = vtkRenderWindowInteractor::SafeDownCast(caller); + interactor->TerminateApp(); + } +} + +void cv::viz::Viz3d::VizImpl::ExitCallback::Execute(vtkObject*, unsigned long event_id, void*) +{ + if (event_id == vtkCommand::ExitEvent) + { + viz->interactor_->TerminateApp(); + viz->interactor_ = 0; + } +} + +///////////////////////////////////////////////////////////////////////////////////////////// + +bool cv::viz::Viz3d::VizImpl::wasStopped() const +{ + bool stopped = spin_once_state_ ? interactor_ == 0 : false; + spin_once_state_ &= !stopped; + return stopped; +} + +void cv::viz::Viz3d::VizImpl::close() +{ + if (!interactor_) + return; + interactor_->GetRenderWindow()->Finalize(); + interactor_->TerminateApp(); // This tends to close the window... + interactor_ = 0; +} + +void cv::viz::Viz3d::VizImpl::recreateRenderWindow() +{ +#if !defined _MSC_VER + //recreating is workaround for Ubuntu -- a crash in x-server + Vec2i window_size(window_->GetSize()); + int fullscreen = window_->GetFullScreen(); + + window_ = vtkSmartPointer::New(); + if (window_position_[0] != std::numeric_limits::min()) //also workaround + window_->SetPosition(window_position_.val); + + window_->SetSize(window_size.val); + window_->SetFullScreen(fullscreen); + window_->AddRenderer(renderer_); +#endif +} + + +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::spin() +{ + recreateRenderWindow(); + interactor_ = vtkSmartPointer::New(); + interactor_->SetRenderWindow(window_); + interactor_->SetInteractorStyle(style_); window_->AlphaBitPlanesOff(); window_->PointSmoothingOff(); window_->LineSmoothingOff(); window_->PolygonSmoothingOff(); window_->SwapBuffersOn(); window_->SetStereoTypeToAnaglyph(); - - interactor_->SetRenderWindow(window_); - interactor_->SetInteractorStyle(style_); - interactor_->SetDesiredUpdateRate(30.0); - - // Initialize and create timer, also create window - interactor_->Initialize(); - timer_id_ = interactor_->CreateRepeatingTimer(5000L); - - // Set a simple PointPicker - //vtkSmartPointer pp = vtkSmartPointer::New(); - //pp->SetTolerance(pp->GetTolerance() * 2); - //interactor_->SetPicker(pp); - - exit_main_loop_timer_callback_ = vtkSmartPointer::New(); - exit_main_loop_timer_callback_->viz_ = this; - exit_main_loop_timer_callback_->right_timer_id = -1; - interactor_->AddObserver(vtkCommand::TimerEvent, exit_main_loop_timer_callback_); - - exit_callback_ = vtkSmartPointer::New(); - exit_callback_->viz_ = this; - interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_); - - resetStoppedFlag(); - - - ////////////////////////////// - String window_name = VizStorage::generateWindowName(name); - window_->SetWindowName(window_name.c_str()); + window_->Render(); + window_->SetWindowName(window_name_.c_str()); + interactor_->Start(); + interactor_ = 0; } ///////////////////////////////////////////////////////////////////////////////////////////// -cv::viz::Viz3d::VizImpl::~VizImpl() +void cv::viz::Viz3d::VizImpl::spinOnce(int time, bool force_redraw) { - if (interactor_) - interactor_->DestroyTimer(timer_id_); - if (renderer_) - renderer_->Clear(); + if (interactor_ == 0) + { + spin_once_state_ = true; + recreateRenderWindow(); + interactor_ = vtkSmartPointer::New(); + interactor_->SetRenderWindow(window_); + interactor_->SetInteractorStyle(style_); + interactor_->AddObserver(vtkCommand::TimerEvent, timer_callback_); + interactor_->AddObserver(vtkCommand::ExitEvent, exit_callback_); + window_->AlphaBitPlanesOff(); + window_->PointSmoothingOff(); + window_->LineSmoothingOff(); + window_->PolygonSmoothingOff(); + window_->SwapBuffersOn(); + window_->SetStereoTypeToAnaglyph(); + window_->Render(); + window_->SetWindowName(window_name_.c_str()); + } + + vtkSmartPointer local = interactor_; + + if (force_redraw) + local->Render(); + + timer_callback_->timer_id = local->CreateRepeatingTimer(std::max(1, time)); + local->Start(); + local->DestroyTimer(timer_callback_->timer_id); } ///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget, const Affine3f &pose) +void cv::viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget, const Affine3d &pose) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); @@ -142,7 +191,7 @@ void cv::viz::Viz3d::VizImpl::showWidget(const String &id, const Widget &widget, if (actor) { // If the actor is 3D, apply pose - vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); + vtkSmartPointer matrix = vtkmatrix(pose.matrix); actor->SetUserMatrix(matrix); actor->Modified(); } @@ -180,7 +229,7 @@ cv::viz::Widget cv::viz::Viz3d::VizImpl::getWidget(const String &id) const } ///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3f &pose) +void cv::viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3d &pose) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); @@ -189,13 +238,13 @@ void cv::viz::Viz3d::VizImpl::setWidgetPose(const String &id, const Affine3f &po vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second); CV_Assert("Widget is not 3D." && actor); - vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); + vtkSmartPointer matrix = vtkmatrix(pose.matrix); actor->SetUserMatrix(matrix); actor->Modified(); } ///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3f &pose) +void cv::viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3d &pose) { WidgetActorMap::iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); @@ -210,16 +259,15 @@ void cv::viz::Viz3d::VizImpl::updateWidgetPose(const String &id, const Affine3f setWidgetPose(id, pose); return ; } - Matx44f matrix_cv = convertToMatx(matrix); - Affine3f updated_pose = pose * Affine3f(matrix_cv); - matrix = convertToVtkMatrix(updated_pose.matrix); + Affine3d updated_pose = pose * Affine3d(*matrix->Element); + matrix = vtkmatrix(updated_pose.matrix); actor->SetUserMatrix(matrix); actor->Modified(); } ///////////////////////////////////////////////////////////////////////////////////////////// -cv::Affine3f cv::viz::Viz3d::VizImpl::getWidgetPose(const String &id) const +cv::Affine3d cv::viz::Viz3d::VizImpl::getWidgetPose(const String &id) const { WidgetActorMap::const_iterator wam_itr = widget_actor_map_->find(id); bool exists = wam_itr != widget_actor_map_->end(); @@ -228,24 +276,7 @@ cv::Affine3f cv::viz::Viz3d::VizImpl::getWidgetPose(const String &id) const vtkProp3D *actor = vtkProp3D::SafeDownCast(wam_itr->second); CV_Assert("Widget is not 3D." && actor); - vtkSmartPointer matrix = actor->GetUserMatrix(); - Matx44f matrix_cv = convertToMatx(matrix); - return Affine3f(matrix_cv); -} - -///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setDesiredUpdateRate(double rate) -{ - if (interactor_) - interactor_->SetDesiredUpdateRate(rate); -} - -///////////////////////////////////////////////////////////////////////////////////////////// -double cv::viz::Viz3d::VizImpl::getDesiredUpdateRate() -{ - if (interactor_) - return interactor_->GetDesiredUpdateRate(); - return 0.0; + return Affine3d(*actor->GetUserMatrix()->Element); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -258,37 +289,6 @@ void cv::viz::Viz3d::VizImpl::registerMouseCallback(MouseCallback callback, void void cv::viz::Viz3d::VizImpl::registerKeyboardCallback(KeyboardCallback callback, void* cookie) { style_->registerKeyboardCallback(callback, cookie); } -///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::spin() -{ - resetStoppedFlag(); - window_->Render(); - interactor_->Start(); -} - -///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::spinOnce(int time, bool force_redraw) -{ - resetStoppedFlag(); - - if (time <= 0) - time = 1; - - if (force_redraw) - interactor_->Render(); - - double s_now_ = cv::getTickCount() / cv::getTickFrequency(); - if (s_lastDone_ > s_now_) - s_lastDone_ = s_now_; - - if ((s_now_ - s_lastDone_) > (1.0 / interactor_->GetDesiredUpdateRate())) - { - exit_main_loop_timer_callback_->right_timer_id = interactor_->CreateRepeatingTimer(time); - interactor_->Start(); - interactor_->DestroyTimer(exit_main_loop_timer_callback_->right_timer_id); - s_lastDone_ = s_now_; - } -} ////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::Viz3d::VizImpl::removeAllWidgets() @@ -296,50 +296,98 @@ void cv::viz::Viz3d::VizImpl::removeAllWidgets() widget_actor_map_->clear(); renderer_->RemoveAllViewProps(); } +///////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::showImage(InputArray image, const Size& window_size) +{ + removeAllWidgets(); + if (window_size.width > 0 && window_size.height > 0) + setWindowSize(window_size); + + showWidget("showImage", WImageOverlay(image, Rect(Point(0,0), getWindowSize()))); +} ///////////////////////////////////////////////////////////////////////////////////////////// -bool cv::viz::Viz3d::VizImpl::removeActorFromRenderer(const vtkSmartPointer &actor) +bool cv::viz::Viz3d::VizImpl::removeActorFromRenderer(vtkSmartPointer actor) { - vtkProp* actor_to_remove = vtkProp::SafeDownCast(actor); - vtkPropCollection* actors = renderer_->GetViewProps(); actors->InitTraversal(); vtkProp* current_actor = NULL; while ((current_actor = actors->GetNextProp()) != NULL) - { - if (current_actor != actor_to_remove) - continue; - renderer_->RemoveActor(actor); - return true; - } + if (current_actor == actor) + { + renderer_->RemoveActor(actor); + return true; + } return false; } ////////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setBackgroundColor(const Color& color) +void cv::viz::Viz3d::VizImpl::setBackgroundColor(const Color& color, const Color& color2) { - Color c = vtkcolor(color); - renderer_->SetBackground(c.val); + Color c = vtkcolor(color), c2 = vtkcolor(color2); + bool gradient = color2[0] >= 0 && color2[1] >= 0 && color2[2] >= 0; + + if (gradient) + { + renderer_->SetBackground(c2.val); + renderer_->SetBackground2(c.val); + renderer_->GradientBackgroundOn(); + } + else + { + renderer_->SetBackground(c.val); + renderer_->GradientBackgroundOff(); + } +} + +void cv::viz::Viz3d::VizImpl::setBackgroundMeshLab() +{ setBackgroundColor(Color(2, 1, 1), Color(240, 120, 120)); } + +////////////////////////////////////////////////////////////////////////////////////////////// +void cv::viz::Viz3d::VizImpl::setBackgroundTexture(InputArray image) +{ + if (image.empty()) + { + renderer_->SetBackgroundTexture(0); + renderer_->TexturedBackgroundOff(); + return; + } + + vtkSmartPointer source = vtkSmartPointer::New(); + source->SetImage(image); + + vtkSmartPointer image_flip = vtkSmartPointer::New(); + image_flip->SetFilteredAxis(1); // Vertical flip + image_flip->SetInputConnection(source->GetOutputPort()); + + vtkSmartPointer texture = vtkSmartPointer::New(); + texture->SetInputConnection(image_flip->GetOutputPort()); + //texture->Update(); + + renderer_->SetBackgroundTexture(texture); + renderer_->TexturedBackgroundOn(); } ///////////////////////////////////////////////////////////////////////////////////////////// void cv::viz::Viz3d::VizImpl::setCamera(const Camera &camera) { - vtkCamera& active_camera = *renderer_->GetActiveCamera(); + vtkSmartPointer active_camera = renderer_->GetActiveCamera(); // Set the intrinsic parameters of the camera window_->SetSize(camera.getWindowSize().width, camera.getWindowSize().height); double aspect_ratio = static_cast(camera.getWindowSize().width)/static_cast(camera.getWindowSize().height); - Matx44f proj_mat; + Matx44d proj_mat; camera.computeProjectionMatrix(proj_mat); + // Use the intrinsic parameters of the camera to simulate more realistically - Matx44f old_proj_mat = convertToMatx(active_camera.GetProjectionTransformMatrix(aspect_ratio, -1.0, 1.0)); - vtkTransform *transform = vtkTransform::New(); + vtkSmartPointer vtk_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0, 1.0); + Matx44d old_proj_mat(*vtk_matrix->Element); + // This is a hack around not being able to set Projection Matrix - transform->SetMatrix(convertToVtkMatrix(proj_mat * old_proj_mat.inv())); - active_camera.SetUserTransform(transform); - transform->Delete(); + vtkSmartPointer transform = vtkSmartPointer::New(); + transform->SetMatrix(vtkmatrix(proj_mat * old_proj_mat.inv())); + active_camera->SetUserTransform(transform); renderer_->ResetCameraClippingRange(); renderer_->Render(); @@ -348,44 +396,42 @@ void cv::viz::Viz3d::VizImpl::setCamera(const Camera &camera) ///////////////////////////////////////////////////////////////////////////////////////////// cv::viz::Camera cv::viz::Viz3d::VizImpl::getCamera() const { - vtkCamera& active_camera = *renderer_->GetActiveCamera(); + vtkSmartPointer active_camera = renderer_->GetActiveCamera(); Size window_size(renderer_->GetRenderWindow()->GetSize()[0], renderer_->GetRenderWindow()->GetSize()[1]); double aspect_ratio = window_size.width / (double)window_size.height; - Matx44f proj_matrix = convertToMatx(active_camera.GetProjectionTransformMatrix(aspect_ratio, -1.0f, 1.0f)); - Camera camera(proj_matrix, window_size); - return camera; + vtkSmartPointer proj_matrix = active_camera->GetProjectionTransformMatrix(aspect_ratio, -1.0f, 1.0f); + return Camera(Matx44d(*proj_matrix->Element), window_size); } ///////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setViewerPose(const Affine3f &pose) +void cv::viz::Viz3d::VizImpl::setViewerPose(const Affine3d &pose) { vtkCamera& camera = *renderer_->GetActiveCamera(); // Position = extrinsic translation - cv::Vec3f pos_vec = pose.translation(); + cv::Vec3d pos_vec = pose.translation(); // Rotate the view vector - cv::Matx33f rotation = pose.rotation(); - cv::Vec3f y_axis(0.f, 1.f, 0.f); - cv::Vec3f up_vec(rotation * y_axis); + cv::Matx33d rotation = pose.rotation(); + cv::Vec3d y_axis(0.0, 1.0, 0.0); + cv::Vec3d up_vec(rotation * y_axis); // Compute the new focal point - cv::Vec3f z_axis(0.f, 0.f, 1.f); - cv::Vec3f focal_vec = pos_vec + rotation * z_axis; + cv::Vec3d z_axis(0.0, 0.0, 1.0); + cv::Vec3d focal_vec = pos_vec + rotation * z_axis; - camera.SetPosition(pos_vec[0], pos_vec[1], pos_vec[2]); - camera.SetFocalPoint(focal_vec[0], focal_vec[1], focal_vec[2]); - camera.SetViewUp(up_vec[0], up_vec[1], up_vec[2]); + camera.SetPosition(pos_vec.val); + camera.SetFocalPoint(focal_vec.val); + camera.SetViewUp(up_vec.val); renderer_->ResetCameraClippingRange(); - renderer_->Render(); } ///////////////////////////////////////////////////////////////////////////////////////////// -cv::Affine3f cv::viz::Viz3d::VizImpl::getViewerPose() +cv::Affine3d cv::viz::Viz3d::VizImpl::getViewerPose() { vtkCamera& camera = *renderer_->GetActiveCamera(); @@ -397,20 +443,7 @@ cv::Affine3f cv::viz::Viz3d::VizImpl::getViewerPose() Vec3d z_axis = normalized(focal - pos); Vec3d x_axis = normalized(y_axis.cross(z_axis)); - cv::Matx33d R; - R(0, 0) = x_axis[0]; - R(0, 1) = y_axis[0]; - R(0, 2) = z_axis[0]; - - R(1, 0) = x_axis[1]; - R(1, 1) = y_axis[1]; - R(1, 2) = z_axis[1]; - - R(2, 0) = x_axis[2]; - R(2, 1) = y_axis[2]; - R(2, 2) = z_axis[2]; - - return cv::Affine3f(R, pos); + return makeTransformToGlobal(x_axis, y_axis, z_axis, pos); } ///////////////////////////////////////////////////////////////////////////////////////////// @@ -426,10 +459,7 @@ void cv::viz::Viz3d::VizImpl::converTo3DRay(const Point3d &window_coord, Point3d { Vec4d world_pt; vtkInteractorObserver::ComputeDisplayToWorld(renderer_, window_coord.x, window_coord.y, window_coord.z, world_pt.val); - - vtkCamera &active_camera = *renderer_->GetActiveCamera(); - Vec3d cam_pos; - active_camera.GetPosition(cam_pos.val); + Vec3d cam_pos(renderer_->GetActiveCamera()->GetPosition()); origin = cam_pos; direction = normalize(Vec3d(world_pt.val) - cam_pos); } @@ -504,21 +534,9 @@ void cv::viz::Viz3d::VizImpl::setRepresentation(int representation) } } - ////////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setFullScreen(bool mode) -{ - if (window_) - window_->SetFullScreen(mode); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -cv::String cv::viz::Viz3d::VizImpl::getWindowName() const -{ - return (window_ ? window_->GetWindowName() : ""); -} - -////////////////////////////////////////////////////////////////////////////////////////////// -void cv::viz::Viz3d::VizImpl::setWindowPosition(int x, int y) { window_->SetPosition(x, y); } -void cv::viz::Viz3d::VizImpl::setWindowSize(int xw, int yw) { window_->SetSize(xw, yw); } -cv::Size cv::viz::Viz3d::VizImpl::getWindowSize() const { return Size(window_->GetSize()[0], window_->GetSize()[1]); } +cv::String cv::viz::Viz3d::VizImpl::getWindowName() const { return window_name_; } +void cv::viz::Viz3d::VizImpl::setFullScreen(bool mode) { window_->SetFullScreen(mode); } +void cv::viz::Viz3d::VizImpl::setWindowPosition(const Point& position) { window_position_ = position; window_->SetPosition(position.x, position.y); } +void cv::viz::Viz3d::VizImpl::setWindowSize(const Size& window_size) { window_->SetSize(window_size.width, window_size.height); } +cv::Size cv::viz::Viz3d::VizImpl::getWindowSize() const { return Size(Point(Vec2i(window_->GetSize()))); } diff --git a/modules/viz/src/vizimpl.hpp b/modules/viz/src/vizimpl.hpp new file mode 100644 index 000000000..9eb918af6 --- /dev/null +++ b/modules/viz/src/vizimpl.hpp @@ -0,0 +1,138 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Ozan Tonkal, ozantonkal@gmail.com +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __OPENCV_VIZ_VIZ3D_IMPL_HPP__ +#define __OPENCV_VIZ_VIZ3D_IMPL_HPP__ + +struct cv::viz::Viz3d::VizImpl +{ +public: + typedef Viz3d::KeyboardCallback KeyboardCallback; + typedef Viz3d::MouseCallback MouseCallback; + + int ref_counter; + + VizImpl(const String &name); + virtual ~VizImpl() {}; + + bool wasStopped() const; + void close(); + + void spin(); + void spinOnce(int time = 1, bool force_redraw = false); + + void showWidget(const String &id, const Widget &widget, const Affine3d &pose = Affine3d::Identity()); + void removeWidget(const String &id); + Widget getWidget(const String &id) const; + void removeAllWidgets(); + + void showImage(InputArray image, const Size& window_size); + + void setWidgetPose(const String &id, const Affine3d &pose); + void updateWidgetPose(const String &id, const Affine3d &pose); + Affine3d getWidgetPose(const String &id) const; + + void setRepresentation(int representation); + + void setCamera(const Camera &camera); + Camera getCamera() const; + + /** \brief Reset the camera to a given widget */ + void resetCameraViewpoint(const String& id); + void resetCamera(); + + void setViewerPose(const Affine3d &pose); + Affine3d getViewerPose(); + + void convertToWindowCoordinates(const Point3d &pt, Point3d &window_coord); + void converTo3DRay(const Point3d &window_coord, Point3d &origin, Vec3d &direction); + + void saveScreenshot(const String &file); + void setWindowPosition(const Point& position); + Size getWindowSize() const; + void setWindowSize(const Size& window_size); + void setFullScreen(bool mode); + String getWindowName() const; + void setBackgroundColor(const Color& color, const Color& color2); + void setBackgroundTexture(InputArray image); + void setBackgroundMeshLab(); + + void registerKeyboardCallback(KeyboardCallback callback, void* cookie = 0); + void registerMouseCallback(MouseCallback callback, void* cookie = 0); + +private: + struct TimerCallback : public vtkCommand + { + static TimerCallback* New() { return new TimerCallback; } + virtual void Execute(vtkObject* caller, unsigned long event_id, void* cookie); + int timer_id; + }; + + struct ExitCallback : public vtkCommand + { + static ExitCallback* New() { return new ExitCallback; } + virtual void Execute(vtkObject*, unsigned long event_id, void*); + VizImpl* viz; + }; + + mutable bool spin_once_state_; + vtkSmartPointer interactor_; + + vtkSmartPointer window_; + String window_name_; + Vec2i window_position_; + + vtkSmartPointer timer_callback_; + vtkSmartPointer exit_callback_; + + vtkSmartPointer renderer_; + vtkSmartPointer style_; + Ptr widget_actor_map_; + + bool removeActorFromRenderer(vtkSmartPointer actor); + void recreateRenderWindow(); +}; + +#endif diff --git a/modules/viz/src/vtk/vtkCloudMatSink.cpp b/modules/viz/src/vtk/vtkCloudMatSink.cpp new file mode 100644 index 000000000..09ef0cca9 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSink.cpp @@ -0,0 +1,158 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkCloudMatSink); +}} + +cv::viz::vtkCloudMatSink::vtkCloudMatSink() {} +cv::viz::vtkCloudMatSink::~vtkCloudMatSink() {} + +void cv::viz::vtkCloudMatSink::SetOutput(OutputArray _cloud, OutputArray _colors, OutputArray _normals, OutputArray _tcoords) +{ + cloud = _cloud; + colors = _colors; + normals = _normals; + tcoords = _tcoords; +} + +void cv::viz::vtkCloudMatSink::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + vtkSmartPointer points_Data = input->GetPoints(); + + if (cloud.needed() && points_Data) + { + int vtktype = points_Data->GetDataType(); + CV_Assert(vtktype == VTK_FLOAT || vtktype == VTK_DOUBLE); + + cloud.create(1, points_Data->GetNumberOfPoints(), vtktype == VTK_FLOAT ? CV_32FC3 : CV_64FC3); + Vec3d *ddata = cloud.getMat().ptr(); + Vec3f *fdata = cloud.getMat().ptr(); + + if (cloud.depth() == CV_32F) + for(size_t i = 0; i < cloud.total(); ++i) + *fdata++ = Vec3d(points_Data->GetPoint(i)); + + if (cloud.depth() == CV_64F) + for(size_t i = 0; i < cloud.total(); ++i) + *ddata++ = Vec3d(points_Data->GetPoint(i)); + } + else + cloud.release(); + + vtkSmartPointer scalars_data = input->GetPointData() ? input->GetPointData()->GetScalars() : 0; + + if (colors.needed() && scalars_data) + { + int channels = scalars_data->GetNumberOfComponents(); + int vtktype = scalars_data->GetDataType(); + + CV_Assert((channels == 3 || channels == 4) && "Only 3- or 4-channel color data support is implemented"); + CV_Assert(cloud.total() == (size_t)scalars_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC(channels)); + Vec3d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec3d(scalars_data->GetTuple(i)); + + buffer.convertTo(colors, CV_8U, vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE ? 255.0 : 1.0); + } + else + colors.release(); + + vtkSmartPointer normals_data = input->GetPointData() ? input->GetPointData()->GetNormals() : 0; + + if (normals.needed() && normals_data) + { + int channels = normals_data->GetNumberOfComponents(); + int vtktype = normals_data->GetDataType(); + + CV_Assert((vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE) && (channels == 3 || channels == 4)); + CV_Assert(cloud.total() == (size_t)normals_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC(channels)); + Vec3d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec3d(normals_data->GetTuple(i)); + + buffer.convertTo(normals, vtktype == VTK_FLOAT ? CV_32F : CV_64F); + } + else + normals.release(); + + vtkSmartPointer coords_data = input->GetPointData() ? input->GetPointData()->GetTCoords() : 0; + + if (tcoords.needed() && coords_data) + { + int vtktype = coords_data->GetDataType(); + + CV_Assert(vtktype == VTK_FLOAT || VTK_FLOAT == VTK_DOUBLE); + CV_Assert(cloud.total() == (size_t)coords_data->GetNumberOfTuples()); + + Mat buffer(cloud.size(), CV_64FC2); + Vec2d *cptr = buffer.ptr(); + for(size_t i = 0; i < buffer.total(); ++i) + *cptr++ = Vec2d(coords_data->GetTuple(i)); + + buffer.convertTo(tcoords, vtktype == VTK_FLOAT ? CV_32F : CV_64F); + + } + else + tcoords.release(); +} + +void cv::viz::vtkCloudMatSink::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); + os << indent << "Cloud: " << cloud.needed() << "\n"; + os << indent << "Colors: " << colors.needed() << "\n"; + os << indent << "Normals: " << normals.needed() << "\n"; +} diff --git a/modules/viz/src/vtk/vtkCloudMatSink.h b/modules/viz/src/vtk/vtkCloudMatSink.h new file mode 100644 index 000000000..3af9e6544 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSink.h @@ -0,0 +1,79 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkCloudMatSink_h +#define __vtkCloudMatSink_h + +#include +#include + +namespace cv +{ + namespace viz + { + class vtkCloudMatSink : public vtkPolyDataWriter + { + public: + static vtkCloudMatSink *New(); + vtkTypeMacro(vtkCloudMatSink,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + void SetOutput(OutputArray cloud, OutputArray colors = noArray(), OutputArray normals = noArray(), OutputArray tcoords = noArray()); + + protected: + vtkCloudMatSink(); + ~vtkCloudMatSink(); + + void WriteData(); + + _OutputArray cloud, colors, normals, tcoords; + + private: + vtkCloudMatSink(const vtkCloudMatSink&); // Not implemented. + void operator=(const vtkCloudMatSink&); // Not implemented. + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkCloudMatSource.cpp b/modules/viz/src/vtk/vtkCloudMatSource.cpp new file mode 100644 index 000000000..74d01bbd0 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSource.cpp @@ -0,0 +1,286 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkCloudMatSource); + + template struct VtkDepthTraits; + + template<> struct VtkDepthTraits + { + const static int data_type = VTK_FLOAT; + typedef vtkFloatArray array_type; + }; + + template<> struct VtkDepthTraits + { + const static int data_type = VTK_DOUBLE; + typedef vtkDoubleArray array_type; + }; +}} + +cv::viz::vtkCloudMatSource::vtkCloudMatSource() { SetNumberOfInputPorts(0); } +cv::viz::vtkCloudMatSource::~vtkCloudMatSource() {} + +int cv::viz::vtkCloudMatSource::SetCloud(InputArray _cloud) +{ + CV_Assert(_cloud.depth() == CV_32F || _cloud.depth() == CV_64F); + CV_Assert(_cloud.channels() == 3 || _cloud.channels() == 4); + + Mat cloud = _cloud.getMat(); + + int total = _cloud.depth() == CV_32F ? filterNanCopy(cloud) : filterNanCopy(cloud); + + vertices = vtkSmartPointer::New(); + vertices->Allocate(vertices->EstimateSize(1, total)); + vertices->InsertNextCell(total); + for(int i = 0; i < total; ++i) + vertices->InsertCellPoint(i); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloud(InputArray _cloud, InputArray _colors) +{ + int total = SetCloud(_cloud); + + if (_colors.empty()) + return total; + + CV_Assert(_colors.depth() == CV_8U && _colors.channels() <= 4 && _colors.channels() != 2); + CV_Assert(_colors.size() == _cloud.size()); + + Mat cloud = _cloud.getMat(); + Mat colors = _colors.getMat(); + + if (cloud.depth() == CV_32F) + filterNanColorsCopy(colors, cloud, total); + else if (cloud.depth() == CV_64F) + filterNanColorsCopy(colors, cloud, total); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloudNormals(InputArray _cloud, InputArray _colors, InputArray _normals) +{ + int total = SetColorCloud(_cloud, _colors); + + if (_normals.empty()) + return total; + + CV_Assert(_normals.depth() == CV_32F || _normals.depth() == CV_64F); + CV_Assert(_normals.channels() == 3 || _normals.channels() == 4); + CV_Assert(_normals.size() == _cloud.size()); + + Mat c = _cloud.getMat(); + Mat n = _normals.getMat(); + + if (n.depth() == CV_32F && c.depth() == CV_32F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_32F && c.depth() == CV_64F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_64F && c.depth() == CV_32F) + filterNanNormalsCopy(n, c, total); + else if (n.depth() == CV_64F && c.depth() == CV_64F) + filterNanNormalsCopy(n, c, total); + else + CV_Assert(!"Unsupported normals/cloud type"); + + return total; +} + +int cv::viz::vtkCloudMatSource::SetColorCloudNormalsTCoords(InputArray _cloud, InputArray _colors, InputArray _normals, InputArray _tcoords) +{ + int total = SetColorCloudNormals(_cloud, _colors, _normals); + + if (_tcoords.empty()) + return total; + + CV_Assert(_tcoords.depth() == CV_32F || _tcoords.depth() == CV_64F); + CV_Assert(_tcoords.channels() == 2 && _tcoords.size() == _cloud.size()); + + Mat cl = _cloud.getMat(); + Mat tc = _tcoords.getMat(); + + if (tc.depth() == CV_32F && cl.depth() == CV_32F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_32F && cl.depth() == CV_64F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_64F && cl.depth() == CV_32F) + filterNanTCoordsCopy(tc, cl, total); + else if (tc.depth() == CV_64F && cl.depth() == CV_64F) + filterNanTCoordsCopy(tc, cl, total); + else + CV_Assert(!"Unsupported tcoords/cloud type"); + + return total; +} + +int cv::viz::vtkCloudMatSource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + + output->SetPoints(points); + output->SetVerts(vertices); + if (scalars) + output->GetPointData()->SetScalars(scalars); + + if (normals) + output->GetPointData()->SetNormals(normals); + + if (tcoords) + output->GetPointData()->SetTCoords(tcoords); + + return 1; +} + +template +int cv::viz::vtkCloudMatSource::filterNanCopy(const Mat& cloud) +{ + CV_DbgAssert(DataType<_Tp>::depth == cloud.depth()); + points = vtkSmartPointer::New(); + points->SetDataType(VtkDepthTraits<_Tp>::data_type); + points->Allocate(cloud.total()); + points->SetNumberOfPoints(cloud.total()); + + int s_chs = cloud.channels(); + int total = 0; + for (int y = 0; y < cloud.rows; ++y) + { + const _Tp* srow = cloud.ptr<_Tp>(y); + const _Tp* send = srow + cloud.cols * s_chs; + + for (; srow != send; srow += s_chs) + if (!isNan(srow)) + points->SetPoint(total++, srow); + } + points->SetNumberOfPoints(total); + points->Squeeze(); + return total; +} + +template +void cv::viz::vtkCloudMatSource::filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total) +{ + Vec3b* array = new Vec3b[total]; + Vec3b* pos = array; + + int s_chs = cloud_colors.channels(); + int m_chs = mask.channels(); + for (int y = 0; y < cloud_colors.rows; ++y) + { + const unsigned char* srow = cloud_colors.ptr(y); + const unsigned char* send = srow + cloud_colors.cols * s_chs; + const _Msk* mrow = mask.ptr<_Msk>(y); + + if (cloud_colors.channels() == 1) + { + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + *pos++ = Vec3b(srow[0], srow[0], srow[0]); + } + else + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + *pos++ = Vec3b(srow[2], srow[1], srow[0]); + + } + + scalars = vtkSmartPointer::New(); + scalars->SetName("Colors"); + scalars->SetNumberOfComponents(3); + scalars->SetNumberOfTuples(total); + scalars->SetArray(array->val, total * 3, 0); +} + +template +void cv::viz::vtkCloudMatSource::filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total) +{ + normals = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New(); + normals->SetName("Normals"); + normals->SetNumberOfComponents(3); + normals->SetNumberOfTuples(total); + + int s_chs = cloud_normals.channels(); + int m_chs = mask.channels(); + + int pos = 0; + for (int y = 0; y < cloud_normals.rows; ++y) + { + const _Tn* srow = cloud_normals.ptr<_Tn>(y); + const _Tn* send = srow + cloud_normals.cols * s_chs; + + const _Msk* mrow = mask.ptr<_Msk>(y); + + for (; srow != send; srow += s_chs, mrow += m_chs) + if (!isNan(mrow)) + normals->SetTuple(pos++, srow); + } +} + +template +void cv::viz::vtkCloudMatSource::filterNanTCoordsCopy(const Mat& _tcoords, const Mat& mask, int total) +{ + typedef Vec<_Tn, 2> Vec2; + tcoords = vtkSmartPointer< typename VtkDepthTraits<_Tn>::array_type >::New(); + tcoords->SetName("TextureCoordinates"); + tcoords->SetNumberOfComponents(2); + tcoords->SetNumberOfTuples(total); + + int pos = 0; + for (int y = 0; y < mask.rows; ++y) + { + const Vec2* srow = _tcoords.ptr(y); + const Vec2* send = srow + _tcoords.cols; + const _Msk* mrow = mask.ptr<_Msk>(y); + + for (; srow != send; ++srow, mrow += mask.channels()) + if (!isNan(mrow)) + tcoords->SetTuple(pos++, srow->val); + } +} diff --git a/modules/viz/src/vtk/vtkCloudMatSource.h b/modules/viz/src/vtk/vtkCloudMatSource.h new file mode 100644 index 000000000..56bd93e06 --- /dev/null +++ b/modules/viz/src/vtk/vtkCloudMatSource.h @@ -0,0 +1,96 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkCloudMatSource_h +#define __vtkCloudMatSource_h + +#include +#include +#include +#include +#include + +namespace cv +{ + namespace viz + { + class vtkCloudMatSource : public vtkPolyDataAlgorithm + { + public: + static vtkCloudMatSource *New(); + vtkTypeMacro(vtkCloudMatSource,vtkPolyDataAlgorithm) + + virtual int SetCloud(InputArray cloud); + virtual int SetColorCloud(InputArray cloud, InputArray colors); + virtual int SetColorCloudNormals(InputArray cloud, InputArray colors, InputArray normals); + virtual int SetColorCloudNormalsTCoords(InputArray cloud, InputArray colors, InputArray normals, InputArray tcoords); + + protected: + vtkCloudMatSource(); + ~vtkCloudMatSource(); + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + + vtkSmartPointer points; + vtkSmartPointer vertices; + vtkSmartPointer scalars; + vtkSmartPointer normals; + vtkSmartPointer tcoords; + private: + vtkCloudMatSource(const vtkCloudMatSource&); // Not implemented. + void operator=(const vtkCloudMatSource&); // Not implemented. + + template int filterNanCopy(const Mat& cloud); + template void filterNanColorsCopy(const Mat& cloud_colors, const Mat& mask, int total); + + template + void filterNanNormalsCopy(const Mat& cloud_normals, const Mat& mask, int total); + + template + void filterNanTCoordsCopy(const Mat& tcoords, const Mat& mask, int total); + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkImageMatSource.cpp b/modules/viz/src/vtk/vtkImageMatSource.cpp new file mode 100644 index 000000000..58a5642d4 --- /dev/null +++ b/modules/viz/src/vtk/vtkImageMatSource.cpp @@ -0,0 +1,143 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkImageMatSource); +}} + +cv::viz::vtkImageMatSource::vtkImageMatSource() +{ + this->SetNumberOfInputPorts(0); + this->ImageData = vtkImageData::New(); +} + +int cv::viz::vtkImageMatSource::RequestInformation(vtkInformation *, vtkInformationVector**, vtkInformationVector *outputVector) +{ + vtkInformation* outInfo = outputVector->GetInformationObject(0); + + outInfo->Set(vtkStreamingDemandDrivenPipeline::WHOLE_EXTENT(), this->ImageData->GetExtent(), 6); + outInfo->Set(vtkDataObject::SPACING(), 1.0, 1.0, 1.0); + outInfo->Set(vtkDataObject::ORIGIN(), 0.0, 0.0, 0.0); + + vtkDataObject::SetPointDataActiveScalarInfo(outInfo, this->ImageData->GetScalarType(), this->ImageData->GetNumberOfScalarComponents()); + return 1; +} + +int cv::viz::vtkImageMatSource::RequestData(vtkInformation*, vtkInformationVector**, vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + + vtkImageData *output = vtkImageData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT()) ); + output->ShallowCopy(this->ImageData); + return 1; +} + +void cv::viz::vtkImageMatSource::SetImage(InputArray _image) +{ + CV_Assert(_image.depth() == CV_8U && (_image.channels() == 1 || _image.channels() == 3 || _image.channels() == 4)); + + Mat image = _image.getMat(); + + this->ImageData->SetDimensions(image.cols, image.rows, 1); +#if VTK_MAJOR_VERSION <= 5 + this->ImageData->SetNumberOfScalarComponents(image.channels()); + this->ImageData->SetScalarTypeToUnsignedChar(); + this->ImageData->AllocateScalars(); +#else + this->ImageData->AllocateScalars(VTK_UNSIGNED_CHAR, image.channels()); +#endif + + switch(image.channels()) + { + case 1: copyGrayImage(image, this->ImageData); break; + case 3: copyRGBImage (image, this->ImageData); break; + case 4: copyRGBAImage(image, this->ImageData); break; + } + this->ImageData->Modified(); +} + +void cv::viz::vtkImageMatSource::copyGrayImage(const Mat &source, vtkSmartPointer output) +{ + unsigned char* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(unsigned char); + + for (int y = 0; y < source.rows; ++y) + { + unsigned char* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x) + drow[x] = *srow++; + } +} + +void cv::viz::vtkImageMatSource::copyRGBImage(const Mat &source, vtkSmartPointer output) +{ + Vec3b* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(Vec3b); + + for (int y = 0; y < source.rows; ++y) + { + Vec3b* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x, srow += source.channels()) + drow[x] = Vec3b(srow[2], srow[1], srow[0]); + } +} + +void cv::viz::vtkImageMatSource::copyRGBAImage(const Mat &source, vtkSmartPointer output) +{ + Vec4b* dptr = reinterpret_cast(output->GetScalarPointer()); + size_t elem_step = output->GetIncrements()[1]/sizeof(Vec4b); + + for (int y = 0; y < source.rows; ++y) + { + Vec4b* drow = dptr + elem_step * y; + const unsigned char *srow = source.ptr(y); + for (int x = 0; x < source.cols; ++x, srow += source.channels()) + drow[x] = Vec4b(srow[2], srow[1], srow[0], srow[3]); + } +} diff --git a/modules/viz/src/vtk/vtkImageMatSource.h b/modules/viz/src/vtk/vtkImageMatSource.h new file mode 100644 index 000000000..db0c093ed --- /dev/null +++ b/modules/viz/src/vtk/vtkImageMatSource.h @@ -0,0 +1,82 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +#ifndef __vtkImageMatSource_h +#define __vtkImageMatSource_h + +namespace cv +{ + namespace viz + { + class vtkImageMatSource : public vtkImageAlgorithm + { + public: + static vtkImageMatSource *New(); + vtkTypeMacro(vtkImageMatSource,vtkImageAlgorithm); + + void SetImage(InputArray image); + + protected: + vtkImageMatSource(); + ~vtkImageMatSource() {} + + vtkSmartPointer ImageData; + + int RequestInformation(vtkInformation*, vtkInformationVector**, vtkInformationVector*); + int RequestData (vtkInformation*, vtkInformationVector**, vtkInformationVector*); + private: + vtkImageMatSource(const vtkImageMatSource&); // Not implemented. + void operator=(const vtkImageMatSource&); // Not implemented. + + static void copyGrayImage(const Mat &source, vtkSmartPointer output); + static void copyRGBImage (const Mat &source, vtkSmartPointer output); + static void copyRGBAImage(const Mat &source, vtkSmartPointer output); + }; + } +} + + +#endif diff --git a/modules/viz/src/vtk/vtkOBJWriter.cpp b/modules/viz/src/vtk/vtkOBJWriter.cpp new file mode 100644 index 000000000..452ad19a7 --- /dev/null +++ b/modules/viz/src/vtk/vtkOBJWriter.cpp @@ -0,0 +1,241 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkOBJWriter); +}} + +cv::viz::vtkOBJWriter::vtkOBJWriter() +{ + std::ofstream fout; // only used to extract the default precision + this->DecimalPrecision = fout.precision(); + this->FileName = NULL; + this->FileType = VTK_ASCII; +} + +cv::viz::vtkOBJWriter::~vtkOBJWriter(){} + +void cv::viz::vtkOBJWriter::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + std::ostream *outfilep = this->OpenVTKFile(); + if (!outfilep) + return; + + std::ostream& outfile = *outfilep; + + //write header + outfile << "# wavefront obj file written by the visualization toolkit" << std::endl << std::endl; + outfile << "mtllib NONE" << std::endl << std::endl; + + // write out the points + for (int i = 0; i < input->GetNumberOfPoints(); i++) + { + Vec3d p; + input->GetPoint(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "v " << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + + const int idStart = 1; + + // write out the point data + vtkSmartPointer normals = input->GetPointData()->GetNormals(); + if(normals) + { + for (int i = 0; i < normals->GetNumberOfTuples(); i++) + { + Vec3d p; + normals->GetTuple(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "vn " << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + } + + vtkSmartPointer tcoords = input->GetPointData()->GetTCoords(); + if (tcoords) + { + for (int i = 0; i < tcoords->GetNumberOfTuples(); i++) + { + Vec2d p; + tcoords->GetTuple(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << "vt " << p[0] << " " << p[1] << std::endl; + } + } + + // write out a group name and material + outfile << std::endl << "g grp" << idStart << std::endl; + outfile << "usemtl mtlNONE" << std::endl; + + // write out verts if any + if (input->GetNumberOfVerts() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetVerts(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "p "; + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << " "; + outfile << std::endl; + } + } + + // write out lines if any + if (input->GetNumberOfLines() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetLines(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "l "; + if (tcoords) + { + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << "/" << index[i] + idStart << " "; + } + else + for (int i = 0; i < npts; i++) + outfile << index[i] + idStart << " "; + + outfile << std::endl; + } + } + + // write out polys if any + if (input->GetNumberOfPolys() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetPolys(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + outfile << "f "; + for (int i = 0; i < npts; i++) + { + if (normals) + { + if (tcoords) + outfile << index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << " "; + else + outfile << index[i] + idStart << "//" << index[i] + idStart << " "; + } + else + { + if (tcoords) + outfile << index[i] + idStart << " " << index[i] + idStart << " "; + else + outfile << index[i] + idStart << " "; + } + } + outfile << std::endl; + } + } + + // write out tstrips if any + if (input->GetNumberOfStrips() > 0) + { + vtkIdType npts = 0, *index = 0; + vtkCellArray *cells = input->GetStrips(); + for (cells->InitTraversal(); cells->GetNextCell(npts, index); ) + { + for (int i = 2, i1, i2; i < npts; ++i) + { + if (i % 2) + { + i1 = i - 1; + i2 = i - 2; + } + else + { + i1 = i - 1; + i2 = i - 2; + } + + if(normals) + { + if (tcoords) + { + outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << "/" << index[i1] + idStart << " " + << index[i2]+ idStart << "/" << index[i2] + idStart << "/" << index[i2] + idStart << " " + << index[i] + idStart << "/" << index[i] + idStart << "/" << index[i] + idStart << std::endl; + } + else + { + outfile << "f " << index[i1] + idStart << "//" << index[i1] + idStart << " " << index[i2] + idStart + << "//" << index[i2] + idStart << " " << index[i] + idStart << "//" << index[i] + idStart << std::endl; + } + } + else + { + if (tcoords) + { + outfile << "f " << index[i1] + idStart << "/" << index[i1] + idStart << " " << index[i2] + idStart + << "/" << index[i2] + idStart << " " << index[i] + idStart << "/" << index[i] + idStart << std::endl; + } + else + outfile << "f " << index[i1] + idStart << " " << index[i2] + idStart << " " << index[i] + idStart << std::endl; + } + } /* for (int i = 2; i < npts; ++i) */ + } + } /* if (input->GetNumberOfStrips() > 0) */ + + this->CloseVTKFile(outfilep); + + // Delete the file if an error occurred + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName); + unlink(this->FileName); + } +} + +void cv::viz::vtkOBJWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + Superclass::PrintSelf(os, indent); + os << indent << "DecimalPrecision: " << DecimalPrecision << "\n"; +} diff --git a/modules/viz/src/precomp.cpp b/modules/viz/src/vtk/vtkOBJWriter.h similarity index 74% rename from modules/viz/src/precomp.cpp rename to modules/viz/src/vtk/vtkOBJWriter.h index 834648577..f8889884d 100644 --- a/modules/viz/src/precomp.cpp +++ b/modules/viz/src/vtk/vtkOBJWriter.h @@ -38,12 +38,42 @@ // the use of this software, even if advised of the possibility of such damage. // // Authors: -// * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ -#include "precomp.hpp" +#ifndef __vtkOBJWriter_h +#define __vtkOBJWriter_h + +#include + +namespace cv +{ + namespace viz + { + class vtkOBJWriter : public vtkPolyDataWriter + { + public: + static vtkOBJWriter *New(); + vtkTypeMacro(vtkOBJWriter,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(DecimalPrecision, int); + vtkSetMacro(DecimalPrecision, int); + + protected: + vtkOBJWriter(); + ~vtkOBJWriter(); + + void WriteData(); + + int DecimalPrecision; + + private: + vtkOBJWriter(const vtkOBJWriter&); // Not implemented. + void operator=(const vtkOBJWriter&); // Not implemented. + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkTrajectorySource.cpp b/modules/viz/src/vtk/vtkTrajectorySource.cpp new file mode 100644 index 000000000..e098a1d55 --- /dev/null +++ b/modules/viz/src/vtk/vtkTrajectorySource.cpp @@ -0,0 +1,110 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkTrajectorySource); +}} + +cv::viz::vtkTrajectorySource::vtkTrajectorySource() { SetNumberOfInputPorts(0); } +cv::viz::vtkTrajectorySource::~vtkTrajectorySource() {} + +void cv::viz::vtkTrajectorySource::SetTrajectory(InputArray _traj) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat traj; + _traj.getMat().convertTo(traj, CV_64F); + const Affine3d* dpath = traj.ptr(); + size_t total = traj.total(); + + points = vtkSmartPointer::New(); + points->SetDataType(VTK_DOUBLE); + points->SetNumberOfPoints(total); + + tensors = vtkSmartPointer::New(); + tensors->SetNumberOfComponents(9); + tensors->SetNumberOfTuples(total); + + for(size_t i = 0; i < total; ++i, ++dpath) + { + Matx33d R = dpath->rotation().t(); // transposed because of + tensors->SetTuple(i, R.val); // column major order + + Vec3d p = dpath->translation(); + points->SetPoint(i, p.val); + } +} + +cv::Mat cv::viz::vtkTrajectorySource::ExtractPoints(InputArray _traj) +{ + CV_Assert(_traj.kind() == _InputArray::STD_VECTOR || _traj.kind() == _InputArray::MAT); + CV_Assert(_traj.type() == CV_32FC(16) || _traj.type() == CV_64FC(16)); + + Mat points(1, _traj.total(), CV_MAKETYPE(_traj.depth(), 3)); + const Affine3d* dpath = _traj.getMat().ptr(); + const Affine3f* fpath = _traj.getMat().ptr(); + + if (_traj.depth() == CV_32F) + for(int i = 0; i < points.cols; ++i) + points.at(i) = fpath[i].translation(); + + if (_traj.depth() == CV_64F) + for(int i = 0; i < points.cols; ++i) + points.at(i) = dpath[i].translation(); + + return points; +} + +int cv::viz::vtkTrajectorySource::RequestData(vtkInformation *vtkNotUsed(request), vtkInformationVector **vtkNotUsed(inputVector), vtkInformationVector *outputVector) +{ + vtkInformation *outInfo = outputVector->GetInformationObject(0); + vtkPolyData *output = vtkPolyData::SafeDownCast(outInfo->Get(vtkDataObject::DATA_OBJECT())); + output->SetPoints(points); + output->GetPointData()->SetTensors(tensors); + return 1; +} diff --git a/modules/viz/src/vtk/vtkTrajectorySource.h b/modules/viz/src/vtk/vtkTrajectorySource.h new file mode 100644 index 000000000..f6c9c77b9 --- /dev/null +++ b/modules/viz/src/vtk/vtkTrajectorySource.h @@ -0,0 +1,84 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkTrajectorySource_h +#define __vtkTrajectorySource_h + +#include +#include +#include +#include +#include + +namespace cv +{ + namespace viz + { + class vtkTrajectorySource : public vtkPolyDataAlgorithm + { + public: + static vtkTrajectorySource *New(); + vtkTypeMacro(vtkTrajectorySource,vtkPolyDataAlgorithm) + + virtual void SetTrajectory(InputArray trajectory); + + static Mat ExtractPoints(InputArray trajectory); + + protected: + vtkTrajectorySource(); + ~vtkTrajectorySource(); + + vtkSmartPointer points; + vtkSmartPointer tensors; + + int RequestData(vtkInformation *, vtkInformationVector **, vtkInformationVector *); + private: + vtkTrajectorySource(const vtkTrajectorySource&); // Not implemented. + void operator=(const vtkTrajectorySource&); // Not implemented. + + }; + } +} + +#endif diff --git a/modules/viz/src/vtk/vtkXYZWriter.cpp b/modules/viz/src/vtk/vtkXYZWriter.cpp new file mode 100644 index 000000000..4518a0103 --- /dev/null +++ b/modules/viz/src/vtk/vtkXYZWriter.cpp @@ -0,0 +1,93 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#include "precomp.hpp" + +namespace cv { namespace viz +{ + vtkStandardNewMacro(vtkXYZWriter); +}} + +cv::viz::vtkXYZWriter::vtkXYZWriter() +{ + std::ofstream fout; // only used to extract the default precision + this->DecimalPrecision = fout.precision(); +} + +void cv::viz::vtkXYZWriter::WriteData() +{ + vtkPolyData *input = this->GetInput(); + if (!input) + return; + + // OpenVTKFile() will report any errors that happen + ostream *outfilep = this->OpenVTKFile(); + if (!outfilep) + return; + + ostream &outfile = *outfilep; + + for(vtkIdType i = 0; i < input->GetNumberOfPoints(); ++i) + { + Vec3d p; + input->GetPoint(i, p.val); + outfile << std::setprecision(this->DecimalPrecision) << p[0] << " " << p[1] << " " << p[2] << std::endl; + } + + // Close the file + this->CloseVTKFile(outfilep); + + // Delete the file if an error occurred + if (this->ErrorCode == vtkErrorCode::OutOfDiskSpaceError) + { + vtkErrorMacro("Ran out of disk space; deleting file: " << this->FileName); + unlink(this->FileName); + } +} + +void cv::viz::vtkXYZWriter::PrintSelf(ostream& os, vtkIndent indent) +{ + this->Superclass::PrintSelf(os,indent); + os << indent << "DecimalPrecision: " << this->DecimalPrecision << "\n"; +} diff --git a/modules/viz/src/vtk/vtkXYZWriter.h b/modules/viz/src/vtk/vtkXYZWriter.h new file mode 100644 index 000000000..3db18b793 --- /dev/null +++ b/modules/viz/src/vtk/vtkXYZWriter.h @@ -0,0 +1,78 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// +// +// IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. +// +// By downloading, copying, installing or using the software you agree to this license. +// If you do not agree to this license, do not download, install, +// copy or use the software. +// +// +// License Agreement +// For Open Source Computer Vision Library +// +// Copyright (C) 2013, OpenCV Foundation, all rights reserved. +// Third party copyrights are property of their respective owners. +// +// Redistribution and use in source and binary forms, with or without modification, +// are permitted provided that the following conditions are met: +// +// * Redistribution's of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistribution's in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +// * The name of the copyright holders may not be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// This software is provided by the copyright holders and contributors "as is" and +// any express or implied warranties, including, but not limited to, the implied +// warranties of merchantability and fitness for a particular purpose are disclaimed. +// In no event shall the Intel Corporation or contributors be liable for any direct, +// indirect, incidental, special, exemplary, or consequential damages +// (including, but not limited to, procurement of substitute goods or services; +// loss of use, data, or profits; or business interruption) however caused +// and on any theory of liability, whether in contract, strict liability, +// or tort (including negligence or otherwise) arising in any way out of +// the use of this software, even if advised of the possibility of such damage. +// +// Authors: +// * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com +// +//M*/ + +#ifndef __vtkXYZWriter_h +#define __vtkXYZWriter_h + +#include "vtkPolyDataWriter.h" + +namespace cv +{ + namespace viz + { + class vtkXYZWriter : public vtkPolyDataWriter + { + public: + static vtkXYZWriter *New(); + vtkTypeMacro(vtkXYZWriter,vtkPolyDataWriter) + void PrintSelf(ostream& os, vtkIndent indent); + + vtkGetMacro(DecimalPrecision, int) + vtkSetMacro(DecimalPrecision, int) + + protected: + vtkXYZWriter(); + ~vtkXYZWriter(){} + + void WriteData(); + + int DecimalPrecision; + + private: + vtkXYZWriter(const vtkXYZWriter&); // Not implemented. + void operator=(const vtkXYZWriter&); // Not implemented. + }; + } +} +#endif diff --git a/modules/viz/src/widget.cpp b/modules/viz/src/widget.cpp index 04abdcf7a..33b467ebc 100644 --- a/modules/viz/src/widget.cpp +++ b/modules/viz/src/widget.cpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #include "precomp.hpp" @@ -55,7 +52,6 @@ class cv::viz::Widget::Impl { public: vtkSmartPointer prop; - Impl() : prop(0) {} }; @@ -63,13 +59,17 @@ cv::viz::Widget::Widget() : impl_( new Impl() ) { } cv::viz::Widget::Widget(const Widget& other) : impl_( new Impl() ) { - if (other.impl_ && other.impl_->prop) impl_->prop = other.impl_->prop; + if (other.impl_ && other.impl_->prop) + impl_->prop = other.impl_->prop; } cv::viz::Widget& cv::viz::Widget::operator=(const Widget& other) { - if (!impl_) impl_ = new Impl(); - if (other.impl_) impl_->prop = other.impl_->prop; + if (!impl_) + impl_ = new Impl(); + + if (other.impl_) + impl_->prop = other.impl_->prop; return *this; } @@ -84,45 +84,22 @@ cv::viz::Widget::~Widget() cv::viz::Widget cv::viz::Widget::fromPlyFile(const String &file_name) { + CV_Assert(vtkPLYReader::CanReadFile(file_name.c_str())); + vtkSmartPointer reader = vtkSmartPointer::New(); reader->SetFileName(file_name.c_str()); - vtkSmartPointer data = reader->GetOutput(); - CV_Assert("File does not exist or file format is not supported." && data); - - vtkSmartPointer actor = vtkSmartPointer::New(); - vtkSmartPointer mapper = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - mapper->SetInput(data); -#else - mapper->SetInputData(data); -#endif - - vtkSmartPointer scalars = data->GetPointData()->GetScalars(); - if (scalars) - { - cv::Vec3d minmax(scalars->GetRange()); - mapper->SetScalarRange(minmax.val); - mapper->SetScalarModeToUsePointData(); - - // interpolation OFF, if data is a vtkPolyData that contains only vertices, ON for anything else. - vtkPolyData* polyData = vtkPolyData::SafeDownCast(data); - bool interpolation = (polyData && polyData->GetNumberOfCells() != polyData->GetNumberOfVerts()); - - mapper->SetInterpolateScalarsBeforeMapping(interpolation); - mapper->ScalarVisibilityOn(); - } + mapper->SetInputConnection( reader->GetOutputPort() ); mapper->ImmediateModeRenderingOff(); - actor->SetNumberOfCloudPoints(int(std::max(1, data->GetNumberOfPoints() / 10))); + vtkSmartPointer actor = vtkSmartPointer::New(); actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->BackfaceCullingOn(); - actor->SetMapper(mapper); Widget widget; - widget.impl_->prop = actor; + WidgetAccessor::setProp(widget, actor); return widget; } @@ -133,37 +110,15 @@ void cv::viz::Widget::setRenderingProperty(int property, double value) switch (property) { - case POINT_SIZE: - { - actor->GetProperty()->SetPointSize(float(value)); - actor->Modified(); - break; - } - case OPACITY: - { - actor->GetProperty()->SetOpacity(value); - actor->Modified(); - break; - } - case IMMEDIATE_RENDERING: - { - actor->GetMapper()->SetImmediateModeRendering(int(value)); - actor->Modified(); - break; - } - case LINE_WIDTH: - { - actor->GetProperty()->SetLineWidth(float(value)); - actor->Modified(); - break; - } + case POINT_SIZE: actor->GetProperty()->SetPointSize(float(value)); break; + case OPACITY: actor->GetProperty()->SetOpacity(value); break; + case LINE_WIDTH: actor->GetProperty()->SetLineWidth(float(value)); break; + case IMMEDIATE_RENDERING: actor->GetMapper()->SetImmediateModeRendering(int(value)); break; case FONT_SIZE: { vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor); CV_Assert("Widget does not have text content." && text_actor); - vtkSmartPointer tprop = text_actor->GetTextProperty(); - tprop->SetFontSize(int(value)); - text_actor->Modified(); + text_actor->GetTextProperty()->SetFontSize(int(value)); break; } case REPRESENTATION: @@ -174,7 +129,6 @@ void cv::viz::Widget::setRenderingProperty(int property, double value) case REPRESENTATION_WIREFRAME: actor->GetProperty()->SetRepresentationToWireframe(); break; case REPRESENTATION_SURFACE: actor->GetProperty()->SetRepresentationToSurface(); break; } - actor->Modified(); break; } case SHADING: @@ -186,14 +140,11 @@ void cv::viz::Widget::setRenderingProperty(int property, double value) { if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals()) { - vtkSmartPointer normals = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - normals->SetInput(actor->GetMapper()->GetInput()); -#else - normals->SetInputData(actor->GetMapper()->GetInput()); -#endif - normals->Update(); - vtkDataSetMapper::SafeDownCast(actor->GetMapper())->SetInputConnection(normals->GetOutputPort()); + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Can't set shading property for such type of widget" && mapper); + + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(mapper->GetInput()); + VtkUtils::SetInputData(mapper, with_normals); } actor->GetProperty()->SetInterpolationToGouraud(); break; @@ -202,27 +153,22 @@ void cv::viz::Widget::setRenderingProperty(int property, double value) { if (!actor->GetMapper()->GetInput()->GetPointData()->GetNormals()) { - vtkSmartPointer normals = vtkSmartPointer::New(); -#if VTK_MAJOR_VERSION <= 5 - normals->SetInput(actor->GetMapper()->GetInput()); -#else - normals->SetInputData(actor->GetMapper()->GetInput()); -#endif - normals->Update(); - vtkDataSetMapper::SafeDownCast(actor->GetMapper())->SetInputConnection(normals->GetOutputPort()); + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Can't set shading property for such type of widget" && mapper); + + vtkSmartPointer with_normals = VtkUtils::ComputeNormals(mapper->GetInput()); + VtkUtils::SetInputData(mapper, with_normals); } actor->GetProperty()->SetInterpolationToPhong(); break; } } - actor->Modified(); break; } - - default: CV_Assert("setPointCloudRenderingProperties: Unknown property"); } + actor->Modified(); } double cv::viz::Widget::getRenderingProperty(int property) const @@ -233,32 +179,16 @@ double cv::viz::Widget::getRenderingProperty(int property) const double value = 0.0; switch (property) { - case POINT_SIZE: - { - value = actor->GetProperty()->GetPointSize(); - break; - } - case OPACITY: - { - value = actor->GetProperty()->GetOpacity(); - break; - } - case IMMEDIATE_RENDERING: - { - value = actor->GetMapper()->GetImmediateModeRendering(); - break; - } - case LINE_WIDTH: - { - value = actor->GetProperty()->GetLineWidth(); - break; - } + case POINT_SIZE: value = actor->GetProperty()->GetPointSize(); break; + case OPACITY: value = actor->GetProperty()->GetOpacity(); break; + case LINE_WIDTH: value = actor->GetProperty()->GetLineWidth(); break; + case IMMEDIATE_RENDERING: value = actor->GetMapper()->GetImmediateModeRendering(); break; + case FONT_SIZE: { vtkTextActor* text_actor = vtkTextActor::SafeDownCast(actor); CV_Assert("Widget does not have text content." && text_actor); - vtkSmartPointer tprop = text_actor->GetTextProperty(); - value = tprop->GetFontSize(); + value = text_actor->GetTextProperty()->GetFontSize();; break; } case REPRESENTATION: @@ -303,38 +233,17 @@ void cv::viz::WidgetAccessor::setProp(Widget& widget, vtkSmartPointer p /////////////////////////////////////////////////////////////////////////////////////////////// /// widget3D implementation -struct cv::viz::Widget3D::MatrixConverter -{ - static Matx44f convertToMatx(const vtkSmartPointer& vtk_matrix) - { - 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 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 cv::viz::Widget3D::setPose(const Affine3f &pose) +void cv::viz::Widget3D::setPose(const Affine3d &pose) { vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Widget is not 3D." && actor); - vtkSmartPointer matrix = convertToVtkMatrix(pose.matrix); + vtkSmartPointer matrix = vtkmatrix(pose.matrix); actor->SetUserMatrix(matrix); actor->Modified(); } -void cv::viz::Widget3D::updatePose(const Affine3f &pose) +void cv::viz::Widget3D::updatePose(const Affine3d &pose) { vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Widget is not 3D." && actor); @@ -343,25 +252,33 @@ void cv::viz::Widget3D::updatePose(const Affine3f &pose) if (!matrix) { setPose(pose); - return ; + return; } - Matx44f matrix_cv = MatrixConverter::convertToMatx(matrix); - Affine3f updated_pose = pose * Affine3f(matrix_cv); - matrix = MatrixConverter::convertToVtkMatrix(updated_pose.matrix); + Affine3d updated_pose = pose * Affine3d(*matrix->Element); + matrix = vtkmatrix(updated_pose.matrix); actor->SetUserMatrix(matrix); actor->Modified(); } -cv::Affine3f cv::viz::Widget3D::getPose() const +cv::Affine3d cv::viz::Widget3D::getPose() const { vtkProp3D *actor = vtkProp3D::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Widget is not 3D." && actor); + return Affine3d(*actor->GetUserMatrix()->Element); +} - vtkSmartPointer matrix = actor->GetUserMatrix(); - Matx44f matrix_cv = MatrixConverter::convertToMatx(matrix); - return Affine3f(matrix_cv); +void cv::viz::Widget3D::applyTransform(const Affine3d &transform) +{ + vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this)); + CV_Assert("Widget is not 3D actor." && actor); + + vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); + CV_Assert("Widget doesn't have a polydata mapper" && mapper); + mapper->Update(); + + VtkUtils::SetInputData(mapper, VtkUtils::TransformPolydata(mapper->GetInput(), transform)); } void cv::viz::Widget3D::setColor(const Color &color) diff --git a/modules/viz/test/test_main.cpp b/modules/viz/test/test_main.cpp index 6b2499344..e737d2db3 100644 --- a/modules/viz/test/test_main.cpp +++ b/modules/viz/test/test_main.cpp @@ -1,3 +1,3 @@ #include "test_precomp.hpp" -CV_TEST_MAIN("cv") +CV_TEST_MAIN("viz") diff --git a/modules/viz/test/test_precomp.cpp b/modules/viz/test/test_precomp.cpp index 5956e13e3..c2673fee6 100644 --- a/modules/viz/test/test_precomp.cpp +++ b/modules/viz/test/test_precomp.cpp @@ -1 +1,24 @@ #include "test_precomp.hpp" + +cv::String cv::Path::combine(const String& item1, const String& item2) +{ + if (item1.empty()) + return item2; + + if (item2.empty()) + return item1; + + char last = item1[item1.size()-1]; + + bool need_append = last != '/' && last != '\\'; + return item1 + (need_append ? "/" : "") + item2; +} + +cv::String cv::Path::combine(const String& item1, const String& item2, const String& item3) +{ return combine(combine(item1, item2), item3); } + +cv::String cv::Path::change_extension(const String& file, const String& ext) +{ + String::size_type pos = file.find_last_of('.'); + return pos == String::npos ? file : file.substr(0, pos+1) + ext; +} diff --git a/modules/viz/test/test_precomp.hpp b/modules/viz/test/test_precomp.hpp index 9b98f206b..1a5c4fe1c 100644 --- a/modules/viz/test/test_precomp.hpp +++ b/modules/viz/test/test_precomp.hpp @@ -41,9 +41,6 @@ // * Ozan Tonkal, ozantonkal@gmail.com // * Anatoly Baksheev, Itseez Inc. myname.mysurname <> mycompany.com // -// OpenCV Viz module is complete rewrite of -// PCL visualization module (www.pointclouds.org) -// //M*/ #ifdef __GNUC__ @@ -66,5 +63,42 @@ #include #include #include +#include + +namespace cv +{ + struct Path + { + static String combine(const String& item1, const String& item2); + static String combine(const String& item1, const String& item2, const String& item3); + static String change_extension(const String& file, const String& ext); + }; + + inline cv::String get_dragon_ply_file_path() + { + return Path::combine(cvtest::TS::ptr()->get_data_path(), "dragon.ply"); + } + + template + inline std::vector< Affine3<_Tp> > generate_test_trajectory() + { + std::vector< Affine3<_Tp> > result; + + for (int i = 0, j = 0; i <= 270; i += 3, j += 10) + { + double x = 2 * cos(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * 1.2 * CV_PI/180.0)); + double y = 0.25 + i/270.0 + sin(j * CV_PI/180.0) * 0.2 * sin(0.6 + j * 1.5 * CV_PI/180.0); + double z = 2 * sin(i * 3 * CV_PI/180.0) * (1.0 + 0.5 * cos(1.2 + i * CV_PI/180.0)); + result.push_back(viz::makeCameraPose(Vec3d(x, y, z), Vec3d::all(0.0), Vec3d(0.0, 1.0, 0.0))); + } + return result; + } + + inline Mat make_gray(const Mat& image) + { + Mat chs[3]; split(image, chs); + return 0.114 * chs[0] + 0.58 * chs[1] + 0.3 * chs[2]; + } +} #endif diff --git a/modules/viz/test/test_tutorial2.cpp b/modules/viz/test/test_tutorial2.cpp index 6e9189b8f..a901adc2c 100644 --- a/modules/viz/test/test_tutorial2.cpp +++ b/modules/viz/test/test_tutorial2.cpp @@ -12,34 +12,34 @@ void tutorial2() myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); /// Add line to represent (1,1,1) axis - viz::WLine axis(Point3f(-1.0f,-1.0f,-1.0f), Point3f(1.0f,1.0f,1.0f)); + viz::WLine axis(Point3f(-1.0, -1.0, -1.0), Point3d(1.0, 1.0, 1.0)); axis.setRenderingProperty(viz::LINE_WIDTH, 4.0); myWindow.showWidget("Line Widget", axis); /// Construct a cube widget - viz::WCube cube_widget(Point3f(0.5,0.5,0.0), Point3f(0.0,0.0,-0.5), true, viz::Color::blue()); + viz::WCube cube_widget(Point3d(0.5, 0.5, 0.0), Point3d(0.0, 0.0, -0.5), true, viz::Color::blue()); cube_widget.setRenderingProperty(viz::LINE_WIDTH, 4.0); /// Display widget (update if already displayed) myWindow.showWidget("Cube Widget", cube_widget); /// Rodrigues vector - Mat rot_vec = Mat::zeros(1,3,CV_32F); - float translation_phase = 0.0, translation = 0.0; + Vec3d rot_vec = Vec3d::all(0); + double translation_phase = 0.0, translation = 0.0; while(!myWindow.wasStopped()) { /* Rotation using rodrigues */ /// Rotate around (1,1,1) - rot_vec.at(0,0) += CV_PI * 0.01f; - rot_vec.at(0,1) += CV_PI * 0.01f; - rot_vec.at(0,2) += CV_PI * 0.01f; + rot_vec[0] += CV_PI * 0.01; + rot_vec[1] += CV_PI * 0.01; + rot_vec[2] += CV_PI * 0.01; /// Shift on (1,1,1) - translation_phase += CV_PI * 0.01f; + translation_phase += CV_PI * 0.01; translation = sin(translation_phase); /// Construct pose - Affine3f pose(rot_vec, Vec3f(translation, translation, translation)); + Affine3d pose(rot_vec, Vec3d(translation, translation, translation)); myWindow.setWidgetPose("Cube Widget", pose); @@ -48,7 +48,7 @@ void tutorial2() } -TEST(Viz_viz3d, DISABLED_tutorial2_pose_of_widget) +TEST(Viz, DISABLED_tutorial2_pose_of_widget) { tutorial2(); } diff --git a/modules/viz/test/test_tutorial3.cpp b/modules/viz/test/test_tutorial3.cpp index 6c63763df..590e29ebf 100644 --- a/modules/viz/test/test_tutorial3.cpp +++ b/modules/viz/test/test_tutorial3.cpp @@ -3,28 +3,6 @@ using namespace cv; using namespace std; -/** - * @function cvcloud_load - * @brief load bunny.ply - */ -Mat cvcloud_load() -{ - Mat cloud(1, 20000, CV_32FC3); - ifstream ifs("d:/cloud_dragon.ply"); - - string str; - for(size_t i = 0; i < 12; ++i) - getline(ifs, str); - - Point3f* data = cloud.ptr(); - //float dummy1, dummy2; - for(size_t i = 0; i < 20000; ++i) - ifs >> data[i].x >> data[i].y >> data[i].z;// >> dummy1 >> dummy2; - - //cloud *= 5.0f; - return cloud; -} - /** * @function main */ @@ -37,29 +15,29 @@ void tutorial3(bool camera_pov) myWindow.showWidget("Coordinate Widget", viz::WCoordinateSystem()); /// Let's assume camera has the following properties - Point3f cam_pos(3.0f,3.0f,3.0f), cam_focal_point(3.0f,3.0f,2.0f), cam_y_dir(-1.0f,0.0f,0.0f); + Point3d cam_pos(3.0, 3.0, 3.0), cam_focal_point(3.0, 3.0, 2.0), cam_y_dir(-1.0, 0.0, 0.0); /// We can get the pose of the cam using makeCameraPose - Affine3f cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); + Affine3d cam_pose = viz::makeCameraPose(cam_pos, cam_focal_point, cam_y_dir); /// We can get the transformation matrix from camera coordinate system to global using /// - makeTransformToGlobal. We need the axes of the camera - Affine3f transform = viz::makeTransformToGlobal(Vec3f(0.0f,-1.0f,0.0f), Vec3f(-1.0f,0.0f,0.0f), Vec3f(0.0f,0.0f,-1.0f), cam_pos); + Affine3d transform = viz::makeTransformToGlobal(Vec3d(0.0, -1.0, 0.0), Vec3d(-1.0, 0.0, 0.0), Vec3d(0.0, 0.0, -1.0), cam_pos); /// Create a cloud widget. - Mat bunny_cloud = cvcloud_load(); - viz::WCloud cloud_widget(bunny_cloud, viz::Color::green()); + Mat dragon_cloud = viz::readCloud(get_dragon_ply_file_path()); + viz::WCloud cloud_widget(dragon_cloud, viz::Color::green()); /// Pose of the widget in camera frame - Affine3f cloud_pose = Affine3f().translate(Vec3f(0.0f,0.0f,3.0f)); + Affine3d cloud_pose = Affine3d().translate(Vec3d(0.0, 0.0, 3.0)); /// Pose of the widget in global frame - Affine3f cloud_pose_global = transform * cloud_pose; + Affine3d cloud_pose_global = transform * cloud_pose; /// Visualize camera frame if (!camera_pov) { viz::WCameraPosition cpw(0.5); // Coordinate axes - viz::WCameraPosition cpw_frustum(Vec2f(0.889484, 0.523599)); // Camera frustum + viz::WCameraPosition cpw_frustum(Vec2f(0.889484f, 0.523599f)); // Camera frustum myWindow.showWidget("CPW", cpw, cam_pose); myWindow.showWidget("CPW_FRUSTUM", cpw_frustum, cam_pose); } @@ -75,12 +53,12 @@ void tutorial3(bool camera_pov) myWindow.spin(); } -TEST(Viz_viz3d, DISABLED_tutorial3_global_view) +TEST(Viz, DISABLED_tutorial3_global_view) { tutorial3(false); } -TEST(Viz_viz3d, DISABLED_tutorial3_camera_view) +TEST(Viz, DISABLED_tutorial3_camera_view) { tutorial3(true); } diff --git a/modules/viz/test/test_viz3d.cpp b/modules/viz/test/test_viz3d.cpp index 98811165a..45d3cdc3c 100644 --- a/modules/viz/test/test_viz3d.cpp +++ b/modules/viz/test/test_viz3d.cpp @@ -41,141 +41,24 @@ //M*/ #include "test_precomp.hpp" - using namespace cv; -static cv::Mat cvcloud_load() +TEST(Viz_viz3d, DISABLED_develop) { - cv::Mat cloud(1, 20000, CV_32FC3); - std::ifstream ifs("/Users/nerei/cloud_dragon.ply"); + cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path()); - std::string str; - for(size_t i = 0; i < 11; ++i) - std::getline(ifs, str); - - cv::Point3f* data = cloud.ptr(); - for(size_t i = 0; i < 20000; ++i) - ifs >> data[i].x >> data[i].y >> data[i].z; - - return cloud; -} - -bool constant_cam = true; -cv::viz::Widget cam_1, cam_coordinates; - -void keyboard_callback(const viz::KeyboardEvent & event, void * cookie) -{ - if (event.keyDown()) - { - if (event.getKeySym() == "space") - { - viz::Viz3d &viz = *((viz::Viz3d *) cookie); - constant_cam = !constant_cam; - if (constant_cam) - { - viz.showWidget("cam_1", cam_1); - viz.showWidget("cam_coordinate", cam_coordinates); - viz.showWidget("cam_text", viz::WText("Global View", Point2i(5,5), 28)); - viz.resetCamera(); - } - else - { - viz.showWidget("cam_text", viz::WText("Cam View", Point2i(5,5), 28)); - viz.removeWidget("cam_1"); - viz.removeWidget("cam_coordinate"); - } - } - } -} - -TEST(Viz_viz3d, develop) -{ cv::viz::Viz3d viz("abc"); + viz.setBackgroundMeshLab(); + viz.showWidget("coo", cv::viz::WCoordinateSystem(1)); + viz.showWidget("cloud", cv::viz::WPaintedCloud(cloud)); - cv::viz::Mesh3d bunny_mesh = cv::viz::Mesh3d::loadMesh("bunny.ply"); - cv::viz::WMesh bunny_widget(bunny_mesh); - bunny_widget.setColor(cv::viz::Color::cyan()); + //---->>>>> + //std::vector gt, es; + //cv::viz::readTrajectory(gt, "d:/Datasets/trajs/gt%05d.xml"); + //cv::viz::readTrajectory(es, "d:/Datasets/trajs/es%05d.xml"); + //cv::Mat cloud = cv::viz::readCloud(get_dragon_ply_file_path()); + //---->>>>> - cam_1 = cv::viz::WCameraPosition(cv::Vec2f(0.6f, 0.4f), 0.2, cv::viz::Color::green()); - cam_coordinates = cv::viz::WCameraPosition(0.2); - viz.showWidget("bunny", bunny_widget); - viz.showWidget("cam_1", cam_1, viz::makeCameraPose(Point3f(1.f,0.f,0.f), Point3f(0.f,0.f,0.f), Point3f(0.f,1.f,0.f))); - viz.showWidget("cam_coordinate", cam_coordinates, viz::makeCameraPose(Point3f(1.f,0.f,0.f), Point3f(0.f,0.f,0.f), Point3f(0.f,1.f,0.f))); - - std::vector cam_path; - - for (int i = 0, j = 0; i <= 360; ++i, j+=5) - { - cam_path.push_back(viz::makeCameraPose(Vec3d(0.5*cos(i*CV_PI/180.0), 0.5*sin(j*CV_PI/180.0), 0.5*sin(i*CV_PI/180.0)), Vec3f(0.f, 0.f, 0.f), Vec3f(0.f, 1.f, 0.f))); - } - - int path_counter = 0; - int cam_path_size = cam_path.size(); - - // OTHER WIDGETS - cv::Mat img = imread("opencv.png"); - - int downSample = 4; - - int row_max = img.rows/downSample; - int col_max = img.cols/downSample; - - cv::Mat *clouds = new cv::Mat[img.cols/downSample]; - cv::Mat *colors = new cv::Mat[img.cols/downSample]; - - for (int col = 0; col < col_max; ++col) - { - clouds[col] = Mat::zeros(img.rows/downSample, 1, CV_32FC3); - colors[col] = Mat::zeros(img.rows/downSample, 1, CV_8UC3); - for (int row = 0; row < row_max; ++row) - { - clouds[col].at(row) = Vec3f(downSample * float(col) / img.cols, 1.f-(downSample * float(row) / img.rows), 0.f); - colors[col].at(row) = img.at(row*downSample,col*downSample); - } - } - - for (int col = 0; col < col_max; ++col) - { - std::stringstream strstrm; - strstrm << "cloud_" << col; - viz.showWidget(strstrm.str(), viz::WCloud(clouds[col], colors[col])); - viz.getWidget(strstrm.str()).setRenderingProperty(viz::POINT_SIZE, 3.0); - viz.getWidget(strstrm.str()).setRenderingProperty(viz::OPACITY, 0.45); - } - - viz.showWidget("trajectory", viz::WTrajectory(cam_path, viz::WTrajectory::DISPLAY_PATH, viz::Color::yellow())); - viz.showWidget("cam_text", viz::WText("Global View", Point2i(5,5), 28)); - viz.registerKeyboardCallback(keyboard_callback, (void *) &viz); - - int angle = 0; - - while(!viz.wasStopped()) - { - if (path_counter == cam_path_size) - { - path_counter = 0; - } - - if (!constant_cam) - { - viz.setViewerPose(cam_path[path_counter]); - } - - if (angle == 360) angle = 0; - - cam_1.cast().setPose(cam_path[path_counter]); - cam_coordinates.cast().setPose(cam_path[path_counter++]); - - for (int i = 0; i < col_max; ++i) - { - std::stringstream strstrm; - strstrm << "cloud_" << i; - viz.setWidgetPose(strstrm.str(), Affine3f().translate(Vec3f(-0.5f, 0.f, (float)(-0.7 + 0.2*sin((angle+i*10)*CV_PI / 180.0))))); - } - angle += 10; - viz.spinOnce(42, true); - } - - volatile void* a = (void*)&cvcloud_load; (void)a; //fixing warnings + viz.spin(); } diff --git a/modules/viz/test/tests_simple.cpp b/modules/viz/test/tests_simple.cpp new file mode 100644 index 000000000..aae468ed9 --- /dev/null +++ b/modules/viz/test/tests_simple.cpp @@ -0,0 +1,407 @@ +/*M/////////////////////////////////////////////////////////////////////////////////////// + // + // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. + // + // By downloading, copying, installing or using the software you agree to this license. + // If you do not agree to this license, do not download, install, + // copy or use the software. + // + // + // License Agreement + // For Open Source Computer Vision Library + // + // Copyright (C) 2000-2008, Intel Corporation, all rights reserved. + // Copyright (C) 2008-2013, Willow Garage Inc., all rights reserved. + // Third party copyrights are property of their respective owners. + // + // Redistribution and use in source and binary forms, with or without modification, + // are permitted provided that the following conditions are met: + // + // * Redistribution's of source code must retain the above copyright notice, + // this list of conditions and the following disclaimer. + // + // * Redistribution's in binary form must reproduce the above copyright notice, + // this list of conditions and the following disclaimer in the documentation + // and / or other materials provided with the distribution. + // + // * The name of the copyright holders may not be used to endorse or promote products + // derived from this software without specific prior written permission. + // + // This software is provided by the copyright holders and contributors "as is" and + // any express or implied warranties, including, but not limited to, the implied + // warranties of merchantability and fitness for a particular purpose are disclaimed. + // In no event shall the Intel Corporation or contributors be liable for any direct, + // indirect, incidental, special, exemplary, or consequential damages + // (including, but not limited to, procurement of substitute goods or services; + // loss of use, data, or profits; or business interruption) however caused + // and on any theory of liability, whether in contract, strict liability, + // or tort (including negligence or otherwise) arising in any way out of + // the use of this software, even if advised of the possibility of such damage. + // + //M*/ + +#include "test_precomp.hpp" + +using namespace cv; +using namespace cv::viz; + +TEST(Viz, show_cloud_bluberry) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_bluberry"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud, Color::bluberry()), pose); + + viz.showWidget("text2d", WText("Bluberry cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_cloud_random_color) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Mat colors(dragon_cloud.size(), CV_8UC3); + theRNG().fill(colors, RNG::UNIFORM, 0, 255); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_random_color"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud, colors), pose); + viz.showWidget("text2d", WText("Random color cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_cloud_masked) +{ + Mat dragon_cloud = readCloud(get_dragon_ply_file_path()); + + Vec3f qnan = Vec3f::all(std::numeric_limits::quiet_NaN()); + for(size_t i = 0; i < dragon_cloud.total(); ++i) + if (i % 15 != 0) + dragon_cloud.at(i) = qnan; + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_cloud_masked"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("dragon", WCloud(dragon_cloud), pose); + viz.showWidget("text2d", WText("Nan masked cloud", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +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(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))); + + Viz3d viz("show_cloud_collection"); + viz.setBackgroundColor(Color::mlab()); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("ccol", ccol); + viz.showWidget("text2d", WText("Cloud collection", Point(20, 20), 20, Color::green())); + 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.75, -1.0), Vec3d(0.0, 0.75, 0.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.showWidget("text2d", WText("Painted clouds", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_mesh) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_mesh"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.showWidget("text2d", WText("Just mesh", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_mesh_random_colors) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + theRNG().fill(mesh.colors, RNG::UNIFORM, 0, 255); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_mesh_random_color"); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG); + viz.showWidget("text2d", WText("Random color mesh", 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")); + + std::vector points; + std::vector tcoords; + std::vector polygons; + for(size_t i = 0; i < 64; ++i) + { + double angle = CV_PI/2 * i/64.0; + points.push_back(Vec3d(0.00, cos(angle), sin(angle))*0.75); + points.push_back(Vec3d(1.57, cos(angle), sin(angle))*0.75); + tcoords.push_back(Vec2d(0.0, i/64.0)); + tcoords.push_back(Vec2d(1.0, i/64.0)); + } + + for(size_t i = 0; i < points.size()/2-1; ++i) + { + int polys[] = {3, 2*i, 2*i+1, 2*i+2, 3, 2*i+1, 2*i+2, 2*i+3}; + polygons.insert(polygons.end(), polys, polys + sizeof(polys)/sizeof(polys[0])); + } + + cv::viz::Mesh mesh; + mesh.cloud = Mat(points, true).reshape(3, 1); + mesh.tcoords = Mat(tcoords, true).reshape(2, 1); + mesh.polygons = Mat(polygons, true).reshape(1, 1); + mesh.texture = lena; + + Viz3d viz("show_textured_mesh"); + viz.setBackgroundMeshLab(); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("mesh", WMesh(mesh)); + viz.setRenderingProperty("mesh", SHADING, SHADING_PHONG); + viz.showWidget("text2d", WText("Textured mesh", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_polyline) +{ + Mat polyline(1, 32, CV_64FC3); + for(size_t i = 0; i < polyline.total(); ++i) + polyline.at(i) = Vec3d(i/16.0, cos(i * CV_PI/6), sin(i * CV_PI/6)); + + Viz3d viz("show_polyline"); + viz.showWidget("polyline", WPolyLine(Mat(polyline), Color::apricot())); + viz.showWidget("coosys", WCoordinateSystem()); + viz.showWidget("text2d", WText("Polyline", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_sampled_normals) +{ + Mesh mesh = Mesh::load(get_dragon_ply_file_path()); + computeNormals(mesh, mesh.normals); + + Affine3d pose = Affine3d().rotate(Vec3d(0, 0.8, 0)); + + Viz3d viz("show_sampled_normals"); + viz.showWidget("mesh", WMesh(mesh), pose); + viz.showWidget("normals", WCloudNormals(mesh.cloud, mesh.normals, 30, 0.1f, Color::green()), pose); + viz.setRenderingProperty("normals", LINE_WIDTH, 2.0); + viz.showWidget("text2d", WText("Cloud or mesh normals", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_trajectories) +{ + std::vector path = generate_test_trajectory(), sub0, sub1, sub2, sub3, sub4, sub5; + + Mat(path).rowRange(0, path.size()/10+1).copyTo(sub0); + Mat(path).rowRange(path.size()/10, path.size()/5+1).copyTo(sub1); + Mat(path).rowRange(path.size()/5, 11*path.size()/12).copyTo(sub2); + Mat(path).rowRange(11*path.size()/12, path.size()).copyTo(sub3); + Mat(path).rowRange(3*path.size()/4, 33*path.size()/40).copyTo(sub4); + Mat(path).rowRange(33*path.size()/40, 9*path.size()/10).copyTo(sub5); + Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0); + + Viz3d viz("show_trajectories"); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("sub0", WTrajectorySpheres(sub0, 0.25, 0.07)); + viz.showWidget("sub1", WTrajectory(sub1, WTrajectory::PATH, 0.2, Color::brown())); + viz.showWidget("sub2", WTrajectory(sub2, WTrajectory::FRAMES, 0.2)); + viz.showWidget("sub3", WTrajectory(sub3, WTrajectory::BOTH, 0.2, Color::green())); + viz.showWidget("sub4", WTrajectoryFrustums(sub4, K, 0.3, Color::yellow())); + viz.showWidget("sub5", WTrajectoryFrustums(sub5, Vec2d(0.78, 0.78), 0.15)); + viz.showWidget("text2d", WText("Different kinds of supported trajectories", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + double a = --i % 360; + Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180)); + viz.setViewerPose(makeCameraPose(pose * 7.5, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0))); + viz.spinOnce(20, true); + } + viz.resetCamera(); + viz.spin(); +} + +TEST(Viz, show_trajectory_reposition) +{ + std::vector path = generate_test_trajectory(); + + Viz3d viz("show_trajectory_reposition_to_origin"); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("sub3", WTrajectory(Mat(path).rowRange(0, path.size()/3), WTrajectory::BOTH, 0.2, Color::brown()), path.front().inv()); + viz.showWidget("text2d", WText("Trajectory resposition to origin", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_camera_positions) +{ + Matx33d K(1024.0, 0.0, 320.0, 0.0, 1024.0, 240.0, 0.0, 0.0, 1.0); + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Affine3d poses[2]; + for(int i = 0; i < 2; ++i) + { + Vec3d pose = 5 * Vec3d(sin(3.14 + 2.7 + i*60 * CV_PI/180), 0.4 - i*0.3, cos(3.14 + 2.7 + i*60 * CV_PI/180)); + poses[i] = makeCameraPose(pose, Vec3d(0.0, 0.0, 0.0), Vec3d(0.0, -0.1, 0.0)); + } + + Viz3d viz("show_camera_positions"); + viz.showWidget("sphe", WSphere(Point3d(0,0,0), 1.0, 10, Color::orange_red())); + viz.showWidget("coos", WCoordinateSystem(1.5)); + viz.showWidget("pos1", WCameraPosition(0.75), poses[0]); + viz.showWidget("pos2", WCameraPosition(Vec2d(0.78, 0.78), lena, 2.2, Color::green()), poses[0]); + viz.showWidget("pos3", WCameraPosition(0.75), poses[1]); + viz.showWidget("pos4", WCameraPosition(K, gray, 3, Color::indigo()), poses[1]); + viz.showWidget("text2d", WText("Camera positions with images", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_overlay_image) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Size2d half_lsize = Size2d(lena.size()) * 0.5; + + Viz3d viz("show_overlay_image"); + viz.setBackgroundMeshLab(); + Size vsz = viz.getWindowSize(); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("img1", WImageOverlay(lena, Rect(Point(10, 10), half_lsize))); + viz.showWidget("img2", WImageOverlay(gray, Rect(Point(vsz.width-10-lena.cols/2, 10), half_lsize))); + viz.showWidget("img3", WImageOverlay(gray, Rect(Point(10, vsz.height-10-lena.rows/2), half_lsize))); + viz.showWidget("img5", WImageOverlay(lena, Rect(Point(vsz.width-10-lena.cols/2, vsz.height-10-lena.rows/2), half_lsize))); + viz.showWidget("text2d", WText("Overlay images", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + double a = ++i % 360; + Vec3d pose(sin(a * CV_PI/180), 0.7, cos(a * CV_PI/180)); + viz.setViewerPose(makeCameraPose(pose * 3, Vec3d(0.0, 0.5, 0.0), Vec3d(0.0, 0.1, 0.0))); + viz.getWidget("img1").cast().setImage(lena * pow(sin(i*10*CV_PI/180) * 0.5 + 0.5, 1.0)); + viz.spinOnce(1, true); + } + viz.showWidget("text2d", WText("Overlay images (stopped)", Point(20, 20), 20, Color::green())); + viz.spin(); +} + + +TEST(Viz, show_image_method) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + + Viz3d viz("show_image_method"); + viz.showImage(lena); + viz.spinOnce(1500, true); + viz.showImage(lena, lena.size()); + viz.spinOnce(1500, true); + + cv::viz::imshow("show_image_method", make_gray(lena)).spin(); +} + +TEST(Viz, show_image_3d) +{ + Mat lena = imread(Path::combine(cvtest::TS::ptr()->get_data_path(), "lena.png")); + Mat gray = make_gray(lena); + + Viz3d viz("show_image_3d"); + viz.setBackgroundMeshLab(); + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("arr0", WArrow(Vec3d(0.5, 0.0, 0.0), Vec3d(1.5, 0.0, 0.0), 0.009, Color::raspberry())); + viz.showWidget("img0", WImage3D(lena, Size2d(1.0, 1.0)), Affine3d(Vec3d(0.0, CV_PI/2, 0.0), Vec3d(.5, 0.0, 0.0))); + viz.showWidget("arr1", WArrow(Vec3d(-0.5, -0.5, 0.0), Vec3d(0.2, 0.2, 0.0), 0.009, Color::raspberry())); + viz.showWidget("img1", WImage3D(gray, Size2d(1.0, 1.0), Vec3d(-0.5, -0.5, 0.0), Vec3d(1.0, 1.0, 0.0), Vec3d(0.0, 1.0, 0.0))); + + viz.showWidget("arr3", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry())); + + viz.showWidget("text2d", WText("Images in 3D", Point(20, 20), 20, Color::green())); + + int i = 0; + while(!viz.wasStopped()) + { + viz.getWidget("img0").cast().setImage(lena * pow(sin(i++*7.5*CV_PI/180) * 0.5 + 0.5, 1.0)); + viz.spinOnce(1, true); + } + viz.showWidget("text2d", WText("Images in 3D (stopped)", Point(20, 20), 20, Color::green())); + viz.spin(); +} + +TEST(Viz, show_simple_widgets) +{ + Viz3d viz("show_simple_widgets"); + viz.setBackgroundMeshLab(); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("cub0", WCube(Vec3d::all(-1.0), Vec3d::all(-0.5), false, Color::indigo())); + viz.showWidget("arro", WArrow(Vec3d::all(-0.5), Vec3d::all(0.5), 0.009, Color::raspberry())); + viz.showWidget("cir1", WCircle(0.5, 0.01, Color::bluberry())); + viz.showWidget("cir2", WCircle(0.5, Point3d(0.5, 0.0, 0.0), Vec3d(1.0, 0.0, 0.0), 0.01, Color::apricot())); + + viz.showWidget("cyl0", WCylinder(Vec3d(-0.5, 0.5, -0.5), Vec3d(0.5, 0.5, -0.5), 0.125, 30, Color::brown())); + viz.showWidget("con0", WCone(0.25, 0.125, 6, Color::azure())); + viz.showWidget("con1", WCone(0.125, Point3d(0.5, -0.5, 0.5), Point3d(0.5, -1.0, 0.5), 6, Color::turquoise())); + + viz.showWidget("text2d", WText("Different simple widgets", Point(20, 20), 20, Color::green())); + viz.showWidget("text3d", WText3D("Simple 3D text", Point3d( 0.5, 0.5, 0.5), 0.125, false, Color::green())); + + viz.showWidget("plane1", WPlane(Size2d(0.25, 0.75))); + viz.showWidget("plane2", WPlane(Vec3d(0.5, -0.5, -0.5), Vec3d(0.0, 1.0, 1.0), Vec3d(1.0, 1.0, 0.0), Size2d(1.0, 0.5), Color::gold())); + + viz.showWidget("grid1", WGrid(Vec2i(7,7), Vec2d::all(0.75), Color::gray()), Affine3d().translate(Vec3d(0.0, 0.0, -1.0))); + + viz.spin(); + viz.getWidget("text2d").cast().setText("Different simple widgets (updated)"); + viz.getWidget("text3d").cast().setText("Updated text 3D"); + viz.spin(); +} + +TEST(Viz, show_follower) +{ + Viz3d viz("show_follower"); + + viz.showWidget("coos", WCoordinateSystem()); + viz.showWidget("cube", WCube()); + viz.showWidget("t3d_2", WText3D("Simple 3D follower", Point3d(-0.5, -0.5, 0.5), 0.125, true, Color::green())); + viz.showWidget("text2d", WText("Follower: text always facing camera", Point(20, 20), 20, Color::green())); + viz.setBackgroundMeshLab(); + viz.spin(); + viz.getWidget("t3d_2").cast().setText("Updated follower 3D"); + viz.spin(); +}