From 40e47e6f3f2f272fd8eda12ce4cabf1644c64f39 Mon Sep 17 00:00:00 2001 From: ozantonkal Date: Wed, 17 Jul 2013 11:35:14 +0200 Subject: [PATCH] Image widgets implementation, GridWidget: vtkExtractEdges instead of Wireframe --- modules/viz/include/opencv2/viz/widgets.hpp | 24 +++ modules/viz/src/precomp.hpp | 3 +- modules/viz/src/shape_widgets.cpp | 239 +++++++++++++++++++++++++++- 3 files changed, 262 insertions(+), 4 deletions(-) diff --git a/modules/viz/include/opencv2/viz/widgets.hpp b/modules/viz/include/opencv2/viz/widgets.hpp index 56ecde7..4ed47e1 100644 --- a/modules/viz/include/opencv2/viz/widgets.hpp +++ b/modules/viz/include/opencv2/viz/widgets.hpp @@ -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(); template<> CV_EXPORTS Text3DWidget Widget::cast(); template<> CV_EXPORTS TextWidget Widget::cast(); + template<> CV_EXPORTS ImageOverlayWidget Widget::cast(); + template<> CV_EXPORTS Image3DWidget Widget::cast(); template<> CV_EXPORTS CloudWidget Widget::cast(); template<> CV_EXPORTS CloudNormalsWidget Widget::cast(); template<> CV_EXPORTS MeshWidget Widget::cast(); diff --git a/modules/viz/src/precomp.hpp b/modules/viz/src/precomp.hpp index 73a1a85..0974dc5 100644 --- a/modules/viz/src/precomp.hpp +++ b/modules/viz/src/precomp.hpp @@ -108,6 +108,7 @@ #include #include #include +#include #include #include @@ -132,7 +133,7 @@ #include #include #include - +#include #include #include diff --git a/modules/viz/src/shape_widgets.cpp b/modules/viz/src/shape_widgets.cpp index 8981806..cca8b33 100644 --- a/modules/viz/src/shape_widgets.cpp +++ b/modules/viz/src/shape_widgets.cpp @@ -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 filter = vtkSmartPointer::New(); + filter->SetInputConnection(grid->GetProducerPort()); + filter->Update(); + vtkSmartPointer mapper = vtkSmartPointer::New(); - mapper->SetInput(grid); + mapper->SetInput(filter->GetOutput()); + vtkSmartPointer actor = vtkSmartPointer::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 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 copyImage(const Mat &image, vtkSmartPointer 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 vtk_image = vtkSmartPointer::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 flipFilter = vtkSmartPointer::New(); + flipFilter->SetFilteredAxis(1); // Vertical flip + flipFilter->SetInputConnection(vtk_image->GetProducerPort()); + flipFilter->Update(); + + vtkSmartPointer imageMapper = vtkSmartPointer::New(); + imageMapper->SetInputConnection(flipFilter->GetOutputPort()); + imageMapper->SetColorWindow(255); // OpenCV color + imageMapper->SetColorLevel(127.5); + + vtkSmartPointer actor = vtkSmartPointer::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 vtk_image = vtkSmartPointer::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 flipFilter = vtkSmartPointer::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() +{ + Widget2D widget = this->cast(); + return static_cast(widget); +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/// image 3D widget implementation + +struct cv::viz::Image3DWidget::CopyImpl +{ + 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 copyImage(const Mat &image, vtkSmartPointer 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 vtk_image = vtkSmartPointer::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 flipFilter = vtkSmartPointer::New(); + flipFilter->SetFilteredAxis(1); // Vertical flip + flipFilter->SetInputConnection(vtk_image->GetProducerPort()); + flipFilter->Update(); + + vtkSmartPointer actor = vtkSmartPointer::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 vtk_image = vtkSmartPointer::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 flipFilter = vtkSmartPointer::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() +{ + Widget3D widget = this->cast(); + return static_cast(widget); +} \ No newline at end of file -- 2.7.4