Home | History | Annotate | Download | only in src
      1 /*M///////////////////////////////////////////////////////////////////////////////////////
      2 //
      3 //  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
      4 //
      5 //  By downloading, copying, installing or using the software you agree to this license.
      6 //  If you do not agree to this license, do not download, install,
      7 //  copy or use the software.
      8 //
      9 //
     10 //                           License Agreement
     11 //                For Open Source Computer Vision Library
     12 //
     13 // Copyright (C) 2013, OpenCV Foundation, all rights reserved.
     14 // Third party copyrights are property of their respective owners.
     15 //
     16 // Redistribution and use in source and binary forms, with or without modification,
     17 // are permitted provided that the following conditions are met:
     18 //
     19 //   * Redistribution's of source code must retain the above copyright notice,
     20 //     this list of conditions and the following disclaimer.
     21 //
     22 //   * Redistribution's in binary form must reproduce the above copyright notice,
     23 //     this list of conditions and the following disclaimer in the documentation
     24 //     and/or other materials provided with the distribution.
     25 //
     26 //   * The name of the copyright holders may not be used to endorse or promote products
     27 //     derived from this software without specific prior written permission.
     28 //
     29 // This software is provided by the copyright holders and contributors "as is" and
     30 // any express or implied warranties, including, but not limited to, the implied
     31 // warranties of merchantability and fitness for a particular purpose are disclaimed.
     32 // In no event shall the Intel Corporation or contributors be liable for any direct,
     33 // indirect, incidental, special, exemplary, or consequential damages
     34 // (including, but not limited to, procurement of substitute goods or services;
     35 // loss of use, data, or profits; or business interruption) however caused
     36 // and on any theory of liability, whether in contract, strict liability,
     37 // or tort (including negligence or otherwise) arising in any way out of
     38 // the use of this software, even if advised of the possibility of such damage.
     39 //
     40 // Authors:
     41 //  * Ozan Tonkal, ozantonkal (at) gmail.com
     42 //  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
     43 //
     44 //M*/
     45 
     46 #include "precomp.hpp"
     47 
     48 ///////////////////////////////////////////////////////////////////////////////////////////////
     49 /// Point Cloud Widget implementation
     50 
     51 cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors)
     52 {
     53     WCloud cloud_widget(cloud, colors, cv::noArray());
     54     *this = cloud_widget;
     55 }
     56 
     57 cv::viz::WCloud::WCloud(InputArray cloud, const Color &color)
     58 {
     59     WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color));
     60     *this = cloud_widget;
     61 }
     62 
     63 cv::viz::WCloud::WCloud(InputArray cloud, const Color &color, InputArray normals)
     64 {
     65     WCloud cloud_widget(cloud, Mat(cloud.size(), CV_8UC3, color), normals);
     66     *this = cloud_widget;
     67 }
     68 
     69 cv::viz::WCloud::WCloud(cv::InputArray cloud, cv::InputArray colors, cv::InputArray normals)
     70 {
     71     CV_Assert(!cloud.empty() && !colors.empty());
     72 
     73     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
     74     cloud_source->SetColorCloudNormals(cloud, colors, normals);
     75     cloud_source->Update();
     76 
     77     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     78     VtkUtils::SetInputData(mapper, cloud_source->GetOutput());
     79     mapper->SetScalarModeToUsePointData();
     80     mapper->ImmediateModeRenderingOff();
     81     mapper->SetScalarRange(0, 255);
     82     mapper->ScalarVisibilityOn();
     83 
     84     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     85     actor->GetProperty()->SetInterpolationToFlat();
     86     actor->GetProperty()->BackfaceCullingOn();
     87     actor->SetMapper(mapper);
     88 
     89     WidgetAccessor::setProp(*this, actor);
     90 
     91 }
     92 
     93 
     94 template<> cv::viz::WCloud cv::viz::Widget::cast<cv::viz::WCloud>()
     95 {
     96     Widget3D widget = this->cast<Widget3D>();
     97     return static_cast<WCloud&>(widget);
     98 }
     99 
    100 ///////////////////////////////////////////////////////////////////////////////////////////////
    101 /// Painted Cloud Widget implementation
    102 
    103 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud)
    104 {
    105     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
    106     cloud_source->SetCloud(cloud);
    107     cloud_source->Update();
    108 
    109     Vec6d bounds(cloud_source->GetOutput()->GetPoints()->GetBounds());
    110 
    111     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
    112     elevation->SetInputConnection(cloud_source->GetOutputPort());
    113     elevation->SetLowPoint(bounds[0], bounds[2], bounds[4]);
    114     elevation->SetHighPoint(bounds[1], bounds[3], bounds[5]);
    115     elevation->SetScalarRange(0.0, 1.0);
    116     elevation->Update();
    117 
    118     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    119     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
    120     mapper->ImmediateModeRenderingOff();
    121     mapper->ScalarVisibilityOn();
    122     mapper->SetColorModeToMapScalars();
    123 
    124     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    125     actor->GetProperty()->SetInterpolationToFlat();
    126     actor->GetProperty()->BackfaceCullingOn();
    127     actor->SetMapper(mapper);
    128 
    129     WidgetAccessor::setProp(*this, actor);
    130 }
    131 
    132 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2)
    133 {
    134     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
    135     cloud_source->SetCloud(cloud);
    136 
    137     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
    138     elevation->SetInputConnection(cloud_source->GetOutputPort());
    139     elevation->SetLowPoint(p1.x, p1.y, p1.z);
    140     elevation->SetHighPoint(p2.x, p2.y, p2.z);
    141     elevation->SetScalarRange(0.0, 1.0);
    142     elevation->Update();
    143 
    144     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    145     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
    146     mapper->ImmediateModeRenderingOff();
    147     mapper->ScalarVisibilityOn();
    148     mapper->SetColorModeToMapScalars();
    149 
    150     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    151     actor->GetProperty()->SetInterpolationToFlat();
    152     actor->GetProperty()->BackfaceCullingOn();
    153     actor->SetMapper(mapper);
    154 
    155     WidgetAccessor::setProp(*this, actor);
    156 }
    157 
    158 cv::viz::WPaintedCloud::WPaintedCloud(InputArray cloud, const Point3d& p1, const Point3d& p2, const Color& c1, const Color c2)
    159 {
    160     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
    161     cloud_source->SetCloud(cloud);
    162 
    163     vtkSmartPointer<vtkElevationFilter> elevation = vtkSmartPointer<vtkElevationFilter>::New();
    164     elevation->SetInputConnection(cloud_source->GetOutputPort());
    165     elevation->SetLowPoint(p1.x, p1.y, p1.z);
    166     elevation->SetHighPoint(p2.x, p2.y, p2.z);
    167     elevation->SetScalarRange(0.0, 1.0);
    168     elevation->Update();
    169 
    170     Color vc1 = vtkcolor(c1), vc2 = vtkcolor(c2);
    171     vtkSmartPointer<vtkColorTransferFunction> color_transfer = vtkSmartPointer<vtkColorTransferFunction>::New();
    172     color_transfer->SetColorSpaceToRGB();
    173     color_transfer->AddRGBPoint(0.0, vc1[0], vc1[1], vc1[2]);
    174     color_transfer->AddRGBPoint(1.0, vc2[0], vc2[1], vc2[2]);
    175     color_transfer->SetScaleToLinear();
    176     color_transfer->Build();
    177 
    178     //if in future some need to replace color table with real scalars, then this can be done usine next calls:
    179     //vtkDataArray *float_scalars = vtkPolyData::SafeDownCast(elevation->GetOutput())->GetPointData()->GetArray("Elevation");
    180     //vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
    181     //polydata->GetPointData()->SetScalars(color_transfer->MapScalars(float_scalars, VTK_COLOR_MODE_DEFAULT, 0));
    182 
    183     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    184     VtkUtils::SetInputData(mapper, vtkPolyData::SafeDownCast(elevation->GetOutput()));
    185     mapper->ImmediateModeRenderingOff();
    186     mapper->ScalarVisibilityOn();
    187     mapper->SetColorModeToMapScalars();
    188     mapper->SetLookupTable(color_transfer);
    189 
    190     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    191     actor->GetProperty()->SetInterpolationToFlat();
    192     actor->GetProperty()->BackfaceCullingOn();
    193     actor->SetMapper(mapper);
    194 
    195     WidgetAccessor::setProp(*this, actor);
    196 }
    197 
    198 template<> cv::viz::WPaintedCloud cv::viz::Widget::cast<cv::viz::WPaintedCloud>()
    199 {
    200     Widget3D widget = this->cast<Widget3D>();
    201     return static_cast<WPaintedCloud&>(widget);
    202 }
    203 
    204 ///////////////////////////////////////////////////////////////////////////////////////////////
    205 /// Cloud Collection Widget implementation
    206 
    207 cv::viz::WCloudCollection::WCloudCollection()
    208 {
    209     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    210 
    211     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    212     mapper->SetInputConnection(append_filter->GetOutputPort());
    213     mapper->SetScalarModeToUsePointData();
    214     mapper->ImmediateModeRenderingOff();
    215     mapper->SetScalarRange(0, 255);
    216     mapper->ScalarVisibilityOn();
    217 
    218     vtkSmartPointer<vtkLODActor> actor = vtkSmartPointer<vtkLODActor>::New();
    219     actor->SetNumberOfCloudPoints(1);
    220     actor->GetProperty()->SetInterpolationToFlat();
    221     actor->GetProperty()->BackfaceCullingOn();
    222     actor->SetMapper(mapper);
    223 
    224     WidgetAccessor::setProp(*this, actor);
    225 }
    226 
    227 void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose)
    228 {
    229     vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
    230     source->SetColorCloud(cloud, colors);
    231 
    232     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(source->GetOutputPort(), pose);
    233 
    234     vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
    235     CV_Assert("Correctness check." && actor);
    236 
    237     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
    238     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
    239     VtkUtils::AddInputData(append_filter, polydata);
    240 
    241     actor->SetNumberOfCloudPoints(std::max<vtkIdType>(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10));
    242 }
    243 
    244 void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose)
    245 {
    246     addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose);
    247 }
    248 
    249 void cv::viz::WCloudCollection::finalize()
    250 {
    251     vtkSmartPointer<vtkLODActor> actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this));
    252     CV_Assert("Incompatible widget type." && actor);
    253 
    254     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    255     CV_Assert("Need to add at least one cloud." && mapper);
    256 
    257     vtkSmartPointer<vtkAlgorithm> producer = mapper->GetInputConnection(0, 0)->GetProducer();
    258     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
    259     append_filter->Update();
    260 
    261     vtkSmartPointer<vtkPolyData> polydata = append_filter->GetOutput();
    262     mapper->RemoveInputConnection(0, 0);
    263     VtkUtils::SetInputData(mapper, polydata);
    264 }
    265 
    266 template<> cv::viz::WCloudCollection cv::viz::Widget::cast<cv::viz::WCloudCollection>()
    267 {
    268     Widget3D widget = this->cast<Widget3D>();
    269     return static_cast<WCloudCollection&>(widget);
    270 }
    271 
    272 ///////////////////////////////////////////////////////////////////////////////////////////////
    273 /// Cloud Normals Widget implementation
    274 
    275 cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color)
    276 {
    277     Mat cloud = _cloud.getMat();
    278     Mat normals = _normals.getMat();
    279 
    280     CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4);
    281     CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type());
    282 
    283     int sqlevel = (int)std::sqrt((double)level);
    284     int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1;
    285     int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level;
    286 
    287     vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
    288     points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
    289 
    290     vtkSmartPointer<vtkCellArray> lines = vtkSmartPointer<vtkCellArray>::New();
    291 
    292     int s_chs = cloud.channels();
    293     int n_chs = normals.channels();
    294     int total = 0;
    295 
    296     for(int y = 0; y < cloud.rows; y += ystep)
    297     {
    298         if (cloud.depth() == CV_32F)
    299         {
    300             const float *srow = cloud.ptr<float>(y);
    301             const float *send = srow + cloud.cols * s_chs;
    302             const float *nrow = normals.ptr<float>(y);
    303 
    304             for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
    305                 if (!isNan(srow) && !isNan(nrow))
    306                 {
    307                     Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale;
    308 
    309                     points->InsertNextPoint(srow);
    310                     points->InsertNextPoint(endp.val);
    311 
    312                     lines->InsertNextCell(2);
    313                     lines->InsertCellPoint(total++);
    314                     lines->InsertCellPoint(total++);
    315                 }
    316         }
    317         else
    318         {
    319             const double *srow = cloud.ptr<double>(y);
    320             const double *send = srow + cloud.cols * s_chs;
    321             const double *nrow = normals.ptr<double>(y);
    322 
    323             for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs)
    324                 if (!isNan(srow) && !isNan(nrow))
    325                 {
    326                     Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale;
    327 
    328                     points->InsertNextPoint(srow);
    329                     points->InsertNextPoint(endp.val);
    330 
    331                     lines->InsertNextCell(2);
    332                     lines->InsertCellPoint(total++);
    333                     lines->InsertCellPoint(total++);
    334                 }
    335         }
    336     }
    337 
    338     vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
    339     polydata->SetPoints(points);
    340     polydata->SetLines(lines);
    341     VtkUtils::FillScalars(polydata, color);
    342 
    343     vtkSmartPointer<vtkDataSetMapper> mapper = vtkSmartPointer<vtkDataSetMapper>::New();
    344     VtkUtils::SetInputData(mapper, polydata);
    345 
    346     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    347     actor->SetMapper(mapper);
    348 
    349     WidgetAccessor::setProp(*this, actor);
    350 }
    351 
    352 template<> cv::viz::WCloudNormals cv::viz::Widget::cast<cv::viz::WCloudNormals>()
    353 {
    354     Widget3D widget = this->cast<Widget3D>();
    355     return static_cast<WCloudNormals&>(widget);
    356 }
    357 
    358 ///////////////////////////////////////////////////////////////////////////////////////////////
    359 /// Mesh Widget implementation
    360 
    361 cv::viz::WMesh::WMesh(const Mesh &mesh)
    362 {
    363     CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1);
    364 
    365     vtkSmartPointer<vtkCloudMatSource> source = vtkSmartPointer<vtkCloudMatSource>::New();
    366     source->SetColorCloudNormalsTCoords(mesh.cloud, mesh.colors, mesh.normals, mesh.tcoords);
    367     source->Update();
    368 
    369     Mat lookup_buffer(1, (int)mesh.cloud.total(), CV_32SC1);
    370     int *lookup = lookup_buffer.ptr<int>();
    371     for(int y = 0, index = 0; y < mesh.cloud.rows; ++y)
    372     {
    373         int s_chs = mesh.cloud.channels();
    374 
    375         if (mesh.cloud.depth() == CV_32F)
    376         {
    377             const float* srow = mesh.cloud.ptr<float>(y);
    378             const float* send = srow + mesh.cloud.cols * s_chs;
    379 
    380             for (; srow != send; srow += s_chs, ++lookup)
    381                 if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
    382                     *lookup = index++;
    383         }
    384 
    385         if (mesh.cloud.depth() == CV_64F)
    386         {
    387             const double* srow = mesh.cloud.ptr<double>(y);
    388             const double* send = srow + mesh.cloud.cols * s_chs;
    389 
    390             for (; srow != send; srow += s_chs, ++lookup)
    391                 if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2]))
    392                     *lookup = index++;
    393         }
    394     }
    395     lookup = lookup_buffer.ptr<int>();
    396 
    397     vtkSmartPointer<vtkPolyData> polydata = source->GetOutput();
    398     polydata->SetVerts(0);
    399 
    400     const int * polygons = mesh.polygons.ptr<int>();
    401     vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
    402 
    403     int idx = 0;
    404     size_t polygons_size = mesh.polygons.total();
    405     for (size_t i = 0; i < polygons_size; ++idx)
    406     {
    407         int n_points = polygons[i++];
    408 
    409         cell_array->InsertNextCell(n_points);
    410         for (int j = 0; j < n_points; ++j, ++idx)
    411             cell_array->InsertCellPoint(lookup[polygons[i++]]);
    412     }
    413     cell_array->GetData()->SetNumberOfValues(idx);
    414     cell_array->Squeeze();
    415     polydata->SetStrips(cell_array);
    416 
    417     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    418     mapper->SetScalarModeToUsePointData();
    419     mapper->ImmediateModeRenderingOff();
    420     VtkUtils::SetInputData(mapper, polydata);
    421 
    422     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    423     //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10));
    424     actor->GetProperty()->SetRepresentationToSurface();
    425     actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency
    426     actor->GetProperty()->SetInterpolationToFlat();
    427     actor->GetProperty()->EdgeVisibilityOff();
    428     actor->GetProperty()->ShadingOff();
    429     actor->SetMapper(mapper);
    430 
    431     if (!mesh.texture.empty())
    432     {
    433         vtkSmartPointer<vtkImageMatSource> image_source = vtkSmartPointer<vtkImageMatSource>::New();
    434         image_source->SetImage(mesh.texture);
    435 
    436         vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    437         texture->SetInputConnection(image_source->GetOutputPort());
    438         actor->SetTexture(texture);
    439     }
    440 
    441     WidgetAccessor::setProp(*this, actor);
    442 }
    443 
    444 cv::viz::WMesh::WMesh(InputArray cloud, InputArray polygons, InputArray colors, InputArray normals)
    445 {
    446     Mesh mesh;
    447     mesh.cloud = cloud.getMat();
    448     mesh.colors = colors.getMat();
    449     mesh.normals = normals.getMat();
    450     mesh.polygons = polygons.getMat();
    451     *this = WMesh(mesh);
    452 }
    453 
    454 template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast<cv::viz::WMesh>()
    455 {
    456     Widget3D widget = this->cast<Widget3D>();
    457     return static_cast<WMesh&>(widget);
    458 }
    459 
    460 
    461 ///////////////////////////////////////////////////////////////////////////////////////////////
    462 /// Widget Merger implementation
    463 
    464 cv::viz::WWidgetMerger::WWidgetMerger()
    465 {
    466     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    467 
    468     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    469     mapper->SetInputConnection(append_filter->GetOutputPort());
    470     mapper->SetScalarModeToUsePointData();
    471     mapper->ImmediateModeRenderingOff();
    472     mapper->SetScalarRange(0, 255);
    473     mapper->ScalarVisibilityOn();
    474 
    475     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    476     actor->GetProperty()->SetInterpolationToFlat();
    477     actor->GetProperty()->BackfaceCullingOn();
    478     actor->SetMapper(mapper);
    479 
    480     WidgetAccessor::setProp(*this, actor);
    481 }
    482 
    483 void cv::viz::WWidgetMerger::addWidget(const Widget3D& widget, const Affine3d &pose)
    484 {
    485     vtkActor *widget_actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(widget));
    486     CV_Assert("Widget is not 3D actor." && widget_actor);
    487 
    488     vtkSmartPointer<vtkPolyDataMapper> widget_mapper = vtkPolyDataMapper::SafeDownCast(widget_actor->GetMapper());
    489     CV_Assert("Widget doesn't have a polydata mapper" && widget_mapper);
    490     widget_mapper->Update();
    491 
    492     vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
    493     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
    494     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
    495     CV_Assert("Correctness check" && append_filter);
    496 
    497     VtkUtils::AddInputData(append_filter, VtkUtils::TransformPolydata(widget_mapper->GetInput(), pose));
    498 }
    499 
    500 void cv::viz::WWidgetMerger::finalize()
    501 {
    502     vtkSmartPointer<vtkActor> actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
    503     vtkSmartPointer<vtkAlgorithm> producer = actor->GetMapper()->GetInputConnection(0, 0)->GetProducer();
    504     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkAppendPolyData::SafeDownCast(producer);
    505     CV_Assert("Correctness check" && append_filter);
    506     append_filter->Update();
    507 
    508     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    509     mapper->RemoveInputConnection(0, 0);
    510     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
    511     mapper->Modified();
    512 }
    513 
    514 template<> CV_EXPORTS cv::viz::WWidgetMerger cv::viz::Widget::cast<cv::viz::WWidgetMerger>()
    515 {
    516     Widget3D widget = this->cast<Widget3D>();
    517     return static_cast<WWidgetMerger&>(widget);
    518 }
    519