Image widgets implementation, GridWidget: vtkExtractEdges instead of Wireframe
This commit is contained in:
parent
769eba7535
commit
40e47e6f3f
@ -140,6 +140,28 @@ namespace cv
|
|||||||
void setText(const String &text);
|
void setText(const String &text);
|
||||||
String getText() const;
|
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
|
class CV_EXPORTS CloudWidget : public Widget3D
|
||||||
{
|
{
|
||||||
@ -183,6 +205,8 @@ namespace cv
|
|||||||
template<> CV_EXPORTS GridWidget Widget::cast<GridWidget>();
|
template<> CV_EXPORTS GridWidget Widget::cast<GridWidget>();
|
||||||
template<> CV_EXPORTS Text3DWidget Widget::cast<Text3DWidget>();
|
template<> CV_EXPORTS Text3DWidget Widget::cast<Text3DWidget>();
|
||||||
template<> CV_EXPORTS TextWidget Widget::cast<TextWidget>();
|
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 CloudWidget Widget::cast<CloudWidget>();
|
||||||
template<> CV_EXPORTS CloudNormalsWidget Widget::cast<CloudNormalsWidget>();
|
template<> CV_EXPORTS CloudNormalsWidget Widget::cast<CloudNormalsWidget>();
|
||||||
template<> CV_EXPORTS MeshWidget Widget::cast<MeshWidget>();
|
template<> CV_EXPORTS MeshWidget Widget::cast<MeshWidget>();
|
||||||
|
@ -108,6 +108,7 @@
|
|||||||
#include <vtkImageCanvasSource2D.h>
|
#include <vtkImageCanvasSource2D.h>
|
||||||
#include <vtkImageBlend.h>
|
#include <vtkImageBlend.h>
|
||||||
#include <vtkImageStencilData.h>
|
#include <vtkImageStencilData.h>
|
||||||
|
#include <vtkImageActor.h>
|
||||||
|
|
||||||
#include <vtkRenderWindowInteractor.h>
|
#include <vtkRenderWindowInteractor.h>
|
||||||
#include <vtkChartXY.h>
|
#include <vtkChartXY.h>
|
||||||
@ -132,7 +133,7 @@
|
|||||||
#include <vtkImageReader2Factory.h>
|
#include <vtkImageReader2Factory.h>
|
||||||
#include <vtkImageReader2.h>
|
#include <vtkImageReader2.h>
|
||||||
#include <vtkImageData.h>
|
#include <vtkImageData.h>
|
||||||
|
#include <vtkExtractEdges.h>
|
||||||
|
|
||||||
#include <vtkPolyDataNormals.h>
|
#include <vtkPolyDataNormals.h>
|
||||||
#include <vtkMapper.h>
|
#include <vtkMapper.h>
|
||||||
|
@ -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
|
// 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);
|
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();
|
vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
|
||||||
mapper->SetInput(grid);
|
mapper->SetInput(filter->GetOutput());
|
||||||
|
|
||||||
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
|
||||||
actor->SetMapper(mapper);
|
actor->SetMapper(mapper);
|
||||||
|
|
||||||
// Show it as wireframe
|
|
||||||
actor->GetProperty ()->SetRepresentationToWireframe ();
|
|
||||||
WidgetAccessor::setProp(*this, actor);
|
WidgetAccessor::setProp(*this, actor);
|
||||||
setColor(color);
|
setColor(color);
|
||||||
}
|
}
|
||||||
@ -542,3 +546,232 @@ cv::String cv::viz::TextWidget::getText() const
|
|||||||
CV_Assert(actor);
|
CV_Assert(actor);
|
||||||
return actor->GetInput();
|
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);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user