Image widgets implementation, GridWidget: vtkExtractEdges instead of Wireframe
authorozantonkal <ozantonkal@gmail.com>
Wed, 17 Jul 2013 09:35:14 +0000 (11:35 +0200)
committerozantonkal <ozantonkal@gmail.com>
Wed, 17 Jul 2013 09:35:14 +0000 (11:35 +0200)
modules/viz/include/opencv2/viz/widgets.hpp
modules/viz/src/precomp.hpp
modules/viz/src/shape_widgets.cpp

index 56ecde7..4ed47e1 100644 (file)
@@ -140,6 +140,28 @@ namespace cv
             void setText(const String &text);
             String getText() const;
         };
+        
+        class CV_EXPORTS ImageOverlayWidget : public Widget2D
+        {
+        public:
+            ImageOverlayWidget(const Mat &image, const Point2i &pos);
+            
+            void setImage(const Mat &image);
+            
+        private:
+            struct CopyImpl;
+        };
+        
+        class CV_EXPORTS Image3DWidget : public Widget3D
+        {
+        public:
+            Image3DWidget(const Mat &image);
+            
+            void setImage(const Mat &image);
+        
+        private:
+            struct CopyImpl;
+        };
 
         class CV_EXPORTS CloudWidget : public Widget3D
         {
@@ -183,6 +205,8 @@ namespace cv
         template<> CV_EXPORTS GridWidget Widget::cast<GridWidget>();
         template<> CV_EXPORTS Text3DWidget Widget::cast<Text3DWidget>();
         template<> CV_EXPORTS TextWidget Widget::cast<TextWidget>();
+        template<> CV_EXPORTS ImageOverlayWidget Widget::cast<ImageOverlayWidget>();
+        template<> CV_EXPORTS Image3DWidget Widget::cast<Image3DWidget>();
         template<> CV_EXPORTS CloudWidget Widget::cast<CloudWidget>();
         template<> CV_EXPORTS CloudNormalsWidget Widget::cast<CloudNormalsWidget>();
         template<> CV_EXPORTS MeshWidget Widget::cast<MeshWidget>();
index 73a1a85..0974dc5 100644 (file)
 #include <vtkImageCanvasSource2D.h>
 #include <vtkImageBlend.h>
 #include <vtkImageStencilData.h>
+#include <vtkImageActor.h>
 
 #include <vtkRenderWindowInteractor.h>
 #include <vtkChartXY.h>
 #include <vtkImageReader2Factory.h>
 #include <vtkImageReader2.h>
 #include <vtkImageData.h>
-
+#include <vtkExtractEdges.h>
 
 #include <vtkPolyDataNormals.h>
 #include <vtkMapper.h>
index 8981806..cca8b33 100644 (file)
@@ -432,13 +432,17 @@ cv::viz::GridWidget::GridWidget(Vec2i dimensions, Vec2d spacing, const Color &co
     // 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<vtkExtractEdges> filter = vtkSmartPointer<vtkExtractEdges>::New();
+    filter->SetInputConnection(grid->GetProducerPort());
+    filter->Update();
+    
     vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
-    mapper->SetInput(grid);
+    mapper->SetInput(filter->GetOutput());
+    
     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     actor->SetMapper(mapper);
     
-    // Show it as wireframe
-    actor->GetProperty ()->SetRepresentationToWireframe ();
     WidgetAccessor::setProp(*this, actor);
     setColor(color);
 }
@@ -542,3 +546,232 @@ cv::String cv::viz::TextWidget::getText() const
     CV_Assert(actor);
     return actor->GetInput();
 }
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/// image overlay widget implementation
+
+struct cv::viz::ImageOverlayWidget::CopyImpl
+{
+    struct Impl
+    {
+        static void copyImageMultiChannel(const Mat &image, vtkSmartPointer<vtkImageData> output)
+        {
+            int i_chs = image.channels();
+    
+            for (int i = 0; i < image.rows; ++i)
+            {
+                const unsigned char * irows = image.ptr<unsigned char>(i);
+                for (int j = 0; j < image.cols; ++j, irows += i_chs)
+                {
+                    unsigned char * vrows = static_cast<unsigned char *>(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<vtkImageData> output)
+        {
+            for (int i = 0; i < image.rows; ++i)
+            {
+                const unsigned char * irows = image.ptr<unsigned char>(i);
+                for (int j = 0; j < image.cols; ++j, ++irows)
+                {
+                    unsigned char * vrows = static_cast<unsigned char *>(output->GetScalarPointer(j,i,0));
+                    *vrows = *irows;
+                }
+            }
+            output->Modified();
+        }
+    };
+    
+    static void copyImage(const Mat &image, vtkSmartPointer<vtkImageData> output)
+    {
+        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);
+        }
+    }
+};
+
+cv::viz::ImageOverlayWidget::ImageOverlayWidget(const Mat &image, const Point2i &pos)
+{
+    CV_Assert(!image.empty() && image.depth() == CV_8U);
+    
+    // Create the vtk image and set its parameters based on input image
+    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
+    vtk_image->SetDimensions(image.cols, image.rows, 1);
+    vtk_image->SetNumberOfScalarComponents(image.channels());
+    vtk_image->SetScalarTypeToUnsignedChar();
+    vtk_image->AllocateScalars();
+    
+    CopyImpl::copyImage(image, vtk_image);
+    
+    // Need to flip the image as the coordinates are different in OpenCV and VTK
+    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
+    flipFilter->SetFilteredAxis(1); // Vertical flip
+    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
+    flipFilter->Update();
+    
+    vtkSmartPointer<vtkImageMapper> imageMapper = vtkSmartPointer<vtkImageMapper>::New();
+    imageMapper->SetInputConnection(flipFilter->GetOutputPort());
+    imageMapper->SetColorWindow(255); // OpenCV color
+    imageMapper->SetColorLevel(127.5);  
+    
+    vtkSmartPointer<vtkActor2D> actor = vtkSmartPointer<vtkActor2D>::New();
+    actor->SetMapper(imageMapper);
+    actor->SetPosition(pos.x, pos.y);
+    
+    WidgetAccessor::setProp(*this, actor);
+}
+
+void cv::viz::ImageOverlayWidget::setImage(const Mat &image)
+{
+    CV_Assert(!image.empty() && image.depth() == CV_8U);
+    
+    vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
+    CV_Assert(actor);
+    
+    vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper());
+    CV_Assert(mapper);
+    
+    // Create the vtk image and set its parameters based on input image
+    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
+    vtk_image->SetDimensions(image.cols, image.rows, 1);
+    vtk_image->SetNumberOfScalarComponents(image.channels());
+    vtk_image->SetScalarTypeToUnsignedChar();
+    vtk_image->AllocateScalars();
+    
+    CopyImpl::copyImage(image, vtk_image);
+    
+    // Need to flip the image as the coordinates are different in OpenCV and VTK
+    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
+    flipFilter->SetFilteredAxis(1); // Vertical flip
+    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
+    flipFilter->Update();
+    
+    mapper->SetInputConnection(flipFilter->GetOutputPort());
+}
+
+template<> cv::viz::ImageOverlayWidget cv::viz::Widget::cast<cv::viz::ImageOverlayWidget>()
+{
+    Widget2D widget = this->cast<Widget2D>();
+    return static_cast<ImageOverlayWidget&>(widget);
+}
+
+///////////////////////////////////////////////////////////////////////////////////////////////
+/// image 3D widget implementation
+
+struct cv::viz::Image3DWidget::CopyImpl
+{
+    struct Impl
+    {
+        static void copyImageMultiChannel(const Mat &image, vtkSmartPointer<vtkImageData> output)
+        {
+            int i_chs = image.channels();
+    
+            for (int i = 0; i < image.rows; ++i)
+            {
+                const unsigned char * irows = image.ptr<unsigned char>(i);
+                for (int j = 0; j < image.cols; ++j, irows += i_chs)
+                {
+                    unsigned char * vrows = static_cast<unsigned char *>(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<vtkImageData> output)
+        {
+            for (int i = 0; i < image.rows; ++i)
+            {
+                const unsigned char * irows = image.ptr<unsigned char>(i);
+                for (int j = 0; j < image.cols; ++j, ++irows)
+                {
+                    unsigned char * vrows = static_cast<unsigned char *>(output->GetScalarPointer(j,i,0));
+                    *vrows = *irows;
+                }
+            }
+            output->Modified();
+        }
+    };
+    
+    static void copyImage(const Mat &image, vtkSmartPointer<vtkImageData> output)
+    {
+        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);
+        }
+    }
+};
+
+cv::viz::Image3DWidget::Image3DWidget(const Mat &image)
+{
+    CV_Assert(!image.empty() && image.depth() == CV_8U);
+    
+    // Create the vtk image and set its parameters based on input image
+    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
+    vtk_image->SetDimensions(image.cols, image.rows, 1);
+    vtk_image->SetNumberOfScalarComponents(image.channels());
+    vtk_image->SetScalarTypeToUnsignedChar();
+    vtk_image->AllocateScalars();
+    
+    CopyImpl::copyImage(image, vtk_image);
+    
+    // Need to flip the image as the coordinates are different in OpenCV and VTK
+    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
+    flipFilter->SetFilteredAxis(1); // Vertical flip
+    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
+    flipFilter->Update();
+    
+    vtkSmartPointer<vtkImageActor> actor = vtkSmartPointer<vtkImageActor>::New();
+    actor->SetInput(flipFilter->GetOutput());
+    
+    WidgetAccessor::setProp(*this, actor);
+}
+
+void cv::viz::Image3DWidget::setImage(const Mat &image)
+{
+    CV_Assert(!image.empty() && image.depth() == CV_8U);
+    
+    vtkImageActor *actor = vtkImageActor::SafeDownCast(WidgetAccessor::getProp(*this));
+    CV_Assert(actor);
+    
+    // Create the vtk image and set its parameters based on input image
+    vtkSmartPointer<vtkImageData> vtk_image = vtkSmartPointer<vtkImageData>::New();
+    vtk_image->SetDimensions(image.cols, image.rows, 1);
+    vtk_image->SetNumberOfScalarComponents(image.channels());
+    vtk_image->SetScalarTypeToUnsignedChar();
+    vtk_image->AllocateScalars();
+    
+    CopyImpl::copyImage(image, vtk_image);
+    
+    // Need to flip the image as the coordinates are different in OpenCV and VTK
+    vtkSmartPointer<vtkImageFlip> flipFilter = vtkSmartPointer<vtkImageFlip>::New();
+    flipFilter->SetFilteredAxis(1); // Vertical flip
+    flipFilter->SetInputConnection(vtk_image->GetProducerPort());
+    flipFilter->Update();
+    
+    actor->SetInput(flipFilter->GetOutput());
+}
+
+template<> cv::viz::Image3DWidget cv::viz::Widget::cast<cv::viz::Image3DWidget>()
+{
+    Widget3D widget = this->cast<Widget3D>();
+    return static_cast<Image3DWidget&>(widget);
+}
\ No newline at end of file