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 /// line widget implementation
     50 cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color)
     51 {
     52     vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
     53     line->SetPoint1(pt1.x, pt1.y, pt1.z);
     54     line->SetPoint2(pt2.x, pt2.y, pt2.z);
     55     line->Update();
     56 
     57     vtkSmartPointer<vtkPolyData> polydata = line->GetOutput();
     58     VtkUtils::FillScalars(polydata, color);
     59 
     60     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     61     VtkUtils::SetInputData(mapper, polydata);
     62 
     63     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     64     actor->SetMapper(mapper);
     65 
     66     WidgetAccessor::setProp(*this, actor);
     67 }
     68 
     69 template<> cv::viz::WLine cv::viz::Widget::cast<cv::viz::WLine>()
     70 {
     71     Widget3D widget = this->cast<Widget3D>();
     72     return static_cast<WLine&>(widget);
     73 }
     74 
     75 ///////////////////////////////////////////////////////////////////////////////////////////////
     76 /// sphere widget implementation
     77 
     78 cv::viz::WSphere::WSphere(const Point3d &center, double radius, int sphere_resolution, const Color &color)
     79 {
     80     vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
     81     sphere->SetRadius(radius);
     82     sphere->SetCenter(center.x, center.y, center.z);
     83     sphere->SetPhiResolution(sphere_resolution);
     84     sphere->SetThetaResolution(sphere_resolution);
     85     sphere->LatLongTessellationOff();
     86     sphere->Update();
     87 
     88     vtkSmartPointer<vtkPolyData> polydata = sphere->GetOutput();
     89     VtkUtils::FillScalars(polydata, color);
     90 
     91     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
     92     VtkUtils::SetInputData(mapper, polydata);
     93 
     94     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
     95     actor->SetMapper(mapper);
     96 
     97     WidgetAccessor::setProp(*this, actor);
     98 }
     99 
    100 template<> cv::viz::WSphere cv::viz::Widget::cast<cv::viz::WSphere>()
    101 {
    102     Widget3D widget = this->cast<Widget3D>();
    103     return static_cast<WSphere&>(widget);
    104 }
    105 
    106 ///////////////////////////////////////////////////////////////////////////////////////////////
    107 /// plane widget implementation
    108 
    109 cv::viz::WPlane::WPlane(const Size2d& size, const Color &color)
    110 {
    111     vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    112     plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
    113     plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
    114     plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
    115     plane->Update();
    116 
    117     vtkSmartPointer<vtkPolyData> polydata = plane->GetOutput();
    118     VtkUtils::FillScalars(polydata, color);
    119 
    120     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    121     VtkUtils::SetInputData(mapper, polydata);
    122 
    123     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    124     actor->SetMapper(mapper);
    125     actor->GetProperty()->LightingOff();
    126 
    127     WidgetAccessor::setProp(*this, actor);
    128 }
    129 
    130 cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color)
    131 {
    132     Vec3d zvec = normalize(normal);
    133     Vec3d xvec = normalize(new_yaxis.cross(zvec));
    134     Vec3d yvec = zvec.cross(xvec);
    135 
    136     WPlane plane(size, color);
    137     plane.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    138     *this = plane;
    139 }
    140 
    141 template<> cv::viz::WPlane cv::viz::Widget::cast<cv::viz::WPlane>()
    142 {
    143     Widget3D widget = this->cast<Widget3D>();
    144     return static_cast<WPlane&>(widget);
    145 }
    146 
    147 ///////////////////////////////////////////////////////////////////////////////////////////////
    148 /// arrow widget implementation
    149 
    150 cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color)
    151 {
    152     vtkSmartPointer<vtkArrowSource> arrow_source = vtkSmartPointer<vtkArrowSource>::New();
    153     arrow_source->SetShaftRadius(thickness);
    154     arrow_source->SetTipRadius(thickness * 3.0);
    155     arrow_source->SetTipLength(thickness * 10.0);
    156 
    157     Vec3d arbitrary = get_random_vec();
    158     Vec3d start_point(pt1.x, pt1.y, pt1.z), end_point(pt2.x, pt2.y, pt2.z);
    159 
    160     double length = norm(end_point - start_point);
    161 
    162     Vec3d xvec = normalized(end_point - start_point);
    163     Vec3d zvec = normalized(xvec.cross(arbitrary));
    164     Vec3d yvec = zvec.cross(xvec);
    165 
    166     Matx33d R = makeTransformToGlobal(xvec, yvec, zvec).rotation();
    167     Affine3d transform_with_scale(R * length, start_point);
    168 
    169     vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale);
    170     VtkUtils::FillScalars(polydata, color);
    171 
    172     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    173     VtkUtils::SetInputData(mapper, polydata);
    174 
    175     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    176     actor->SetMapper(mapper);
    177 
    178     WidgetAccessor::setProp(*this, actor);
    179 }
    180 
    181 template<> cv::viz::WArrow cv::viz::Widget::cast<cv::viz::WArrow>()
    182 {
    183     Widget3D widget = this->cast<Widget3D>();
    184     return static_cast<WArrow&>(widget);
    185 }
    186 
    187 ///////////////////////////////////////////////////////////////////////////////////////////////
    188 /// circle widget implementation
    189 
    190 cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color)
    191 {
    192     vtkSmartPointer<vtkDiskSource> disk = vtkSmartPointer<vtkDiskSource>::New();
    193     disk->SetCircumferentialResolution(30);
    194     disk->SetInnerRadius(radius - thickness);
    195     disk->SetOuterRadius(radius + thickness);
    196     disk->Update();
    197 
    198     vtkSmartPointer<vtkPolyData> polydata = disk->GetOutput();
    199     VtkUtils::FillScalars(polydata, color);
    200 
    201     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    202     VtkUtils::SetInputData(mapper, polydata);
    203 
    204     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    205     actor->GetProperty()->LightingOff();
    206     actor->SetMapper(mapper);
    207 
    208     WidgetAccessor::setProp(*this, actor);
    209 }
    210 
    211 cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color)
    212 {
    213     Vec3d arbitrary = get_random_vec();
    214     Vec3d zvec = normalized(normal);
    215     Vec3d xvec = normalized(zvec.cross(arbitrary));
    216     Vec3d yvec = zvec.cross(xvec);
    217 
    218     WCircle circle(radius, thickness, color);
    219     circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    220     *this = circle;
    221 }
    222 
    223 template<> cv::viz::WCircle cv::viz::Widget::cast<cv::viz::WCircle>()
    224 {
    225     Widget3D widget = this->cast<Widget3D>();
    226     return static_cast<WCircle&>(widget);
    227 }
    228 
    229 ///////////////////////////////////////////////////////////////////////////////////////////////
    230 /// WCone widget implementation
    231 
    232 cv::viz::WCone::WCone(double length, double radius, int resolution, const Color &color)
    233 {
    234     vtkSmartPointer<vtkConeSource> cone_source = vtkSmartPointer<vtkConeSource>::New();
    235     cone_source->SetCenter(length*0.5, 0.0, 0.0);
    236     cone_source->SetHeight(length);
    237     cone_source->SetRadius(radius);
    238     cone_source->SetResolution(resolution);
    239     cone_source->Update();
    240 
    241     vtkSmartPointer<vtkPolyData> polydata = cone_source->GetOutput();
    242     VtkUtils::FillScalars(polydata, color);
    243 
    244     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    245     VtkUtils::SetInputData(mapper, polydata);
    246 
    247     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    248     actor->SetMapper(mapper);
    249 
    250     WidgetAccessor::setProp(*this, actor);
    251 }
    252 
    253 cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color)
    254 {
    255     Vec3d arbitrary = get_random_vec();
    256     Vec3d xvec = normalized(Vec3d(tip - center));
    257     Vec3d zvec = normalized(xvec.cross(arbitrary));
    258     Vec3d yvec = zvec.cross(xvec);
    259 
    260     WCone circle(norm(tip - center), radius, resolution, color);
    261     circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    262     *this = circle;
    263 }
    264 
    265 template<> cv::viz::WCone cv::viz::Widget::cast<cv::viz::WCone>()
    266 {
    267     Widget3D widget = this->cast<Widget3D>();
    268     return static_cast<WCone&>(widget);
    269 }
    270 
    271 ///////////////////////////////////////////////////////////////////////////////////////////////
    272 /// cylinder widget implementation
    273 
    274 cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides, const Color &color)
    275 {
    276     vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
    277     line->SetPoint1(axis_point1.x, axis_point1.y, axis_point1.z);
    278     line->SetPoint2(axis_point2.x, axis_point2.y, axis_point2.z);
    279 
    280     vtkSmartPointer<vtkTubeFilter> tuber = vtkSmartPointer<vtkTubeFilter>::New();
    281     tuber->SetInputConnection(line->GetOutputPort());
    282     tuber->SetNumberOfSides(numsides);
    283     tuber->SetRadius(radius);
    284     tuber->Update();
    285 
    286     vtkSmartPointer<vtkPolyData> polydata = tuber->GetOutput();
    287     VtkUtils::FillScalars(polydata, color);
    288 
    289     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    290     VtkUtils::SetInputData(mapper, polydata);
    291 
    292     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    293     actor->SetMapper(mapper);
    294 
    295     WidgetAccessor::setProp(*this, actor);
    296 }
    297 
    298 template<> cv::viz::WCylinder cv::viz::Widget::cast<cv::viz::WCylinder>()
    299 {
    300     Widget3D widget = this->cast<Widget3D>();
    301     return static_cast<WCylinder&>(widget);
    302 }
    303 
    304 ///////////////////////////////////////////////////////////////////////////////////////////////
    305 /// cylinder widget implementation
    306 
    307 cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool wire_frame, const Color &color)
    308 {
    309     double bounds[6];
    310     bounds[0] = std::min(min_point.x, max_point.x);
    311     bounds[1] = std::max(min_point.x, max_point.x);
    312     bounds[2] = std::min(min_point.y, max_point.y);
    313     bounds[3] = std::max(min_point.y, max_point.y);
    314     bounds[4] = std::min(min_point.z, max_point.z);
    315     bounds[5] = std::max(min_point.z, max_point.z);
    316 
    317     vtkSmartPointer<vtkPolyDataAlgorithm> cube;
    318     if (wire_frame)
    319     {
    320         cube = vtkSmartPointer<vtkOutlineSource>::New();
    321         vtkOutlineSource::SafeDownCast(cube)->SetBounds(bounds);
    322     }
    323     else
    324     {
    325         cube = vtkSmartPointer<vtkCubeSource>::New();
    326         vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds);
    327     }
    328     cube->Update();
    329     vtkSmartPointer<vtkPolyData> polydata =cube->GetOutput();
    330     VtkUtils::FillScalars(polydata, color);
    331 
    332     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    333     VtkUtils::SetInputData(mapper, polydata);
    334 
    335     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    336     actor->SetMapper(mapper);
    337 
    338     WidgetAccessor::setProp(*this, actor);
    339 }
    340 
    341 template<> cv::viz::WCube cv::viz::Widget::cast<cv::viz::WCube>()
    342 {
    343     Widget3D widget = this->cast<Widget3D>();
    344     return static_cast<WCube&>(widget);
    345 }
    346 
    347 ///////////////////////////////////////////////////////////////////////////////////////////////
    348 /// coordinate system widget implementation
    349 
    350 cv::viz::WCoordinateSystem::WCoordinateSystem(double scale)
    351 {
    352     vtkSmartPointer<vtkAxes> axes = vtkSmartPointer<vtkAxes>::New();
    353     axes->SetOrigin(0, 0, 0);
    354     axes->SetScaleFactor(scale);
    355     axes->Update();
    356 
    357     vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    358     colors->SetNumberOfComponents(3);
    359     colors->InsertNextTuple3(255, 0, 0);
    360     colors->InsertNextTuple3(255, 0, 0);
    361     colors->InsertNextTuple3(0, 255, 0);
    362     colors->InsertNextTuple3(0, 255, 0);
    363     colors->InsertNextTuple3(0, 0, 255);
    364     colors->InsertNextTuple3(0, 0, 255);
    365 
    366     vtkSmartPointer<vtkPolyData> polydata = axes->GetOutput();
    367     polydata->GetPointData()->SetScalars(colors);
    368 
    369     vtkSmartPointer<vtkTubeFilter> tube_filter = vtkSmartPointer<vtkTubeFilter>::New();
    370     VtkUtils::SetInputData(tube_filter, polydata);
    371     tube_filter->SetRadius(axes->GetScaleFactor() / 50.0);
    372     tube_filter->SetNumberOfSides(6);
    373     tube_filter->Update();
    374 
    375     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    376     mapper->SetScalarModeToUsePointData();
    377     VtkUtils::SetInputData(mapper, tube_filter->GetOutput());
    378 
    379     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    380     actor->SetMapper(mapper);
    381 
    382     WidgetAccessor::setProp(*this, actor);
    383 }
    384 
    385 template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast<cv::viz::WCoordinateSystem>()
    386 {
    387     Widget3D widget = this->cast<Widget3D>();
    388     return static_cast<WCoordinateSystem&>(widget);
    389 }
    390 
    391 ///////////////////////////////////////////////////////////////////////////////////////////////
    392 /// polyline widget implementation
    393 
    394 cv::viz::WPolyLine::WPolyLine(InputArray points, InputArray colors)
    395 {
    396     vtkSmartPointer<vtkCloudMatSource> cloud_source = vtkSmartPointer<vtkCloudMatSource>::New();
    397     cloud_source->SetColorCloud(points, colors);
    398     cloud_source->Update();
    399 
    400     vtkSmartPointer<vtkPolyData> polydata = cloud_source->GetOutput();
    401 
    402     vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
    403     cell_array->Allocate(cell_array->EstimateSize(1, polydata->GetNumberOfPoints()));
    404     cell_array->InsertNextCell(polydata->GetNumberOfPoints());
    405     for(vtkIdType i = 0; i < polydata->GetNumberOfPoints(); ++i)
    406         cell_array->InsertCellPoint(i);
    407 
    408     polydata->SetLines(cell_array);
    409     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    410     VtkUtils::SetInputData(mapper, polydata);
    411     mapper->SetScalarRange(0, 255);
    412 
    413     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    414     actor->SetMapper(mapper);
    415 
    416     WidgetAccessor::setProp(*this, actor);
    417 }
    418 
    419 cv::viz::WPolyLine::WPolyLine(InputArray points, const Color &color)
    420 {
    421     WPolyLine polyline(points, Mat(points.size(), CV_8UC3, color));
    422     *this = polyline;
    423 }
    424 
    425 template<> cv::viz::WPolyLine cv::viz::Widget::cast<cv::viz::WPolyLine>()
    426 {
    427     Widget3D widget = this->cast<Widget3D>();
    428     return static_cast<WPolyLine&>(widget);
    429 }
    430 
    431 ///////////////////////////////////////////////////////////////////////////////////////////////
    432 /// grid widget implementation
    433 
    434 
    435 cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
    436 {
    437     vtkSmartPointer<vtkImageData> grid_data = vtkSmartPointer<vtkImageData>::New();
    438 
    439     // Add 1 to dimensions because in ImageData dimensions is the number of lines
    440     // - however here it means number of cells
    441     grid_data->SetDimensions(cells[0]+1, cells[1]+1, 1);
    442     grid_data->SetSpacing(cells_spacing[0], cells_spacing[1], 0.);
    443 
    444     // Set origin of the grid to be the middle of the grid
    445     grid_data->SetOrigin(cells[0] * cells_spacing[0] * (-0.5), cells[1] * cells_spacing[1] * (-0.5), 0);
    446 
    447     // Extract the edges so we have the grid
    448     vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
    449     VtkUtils::SetInputData(extract_edges, grid_data);
    450     extract_edges->Update();
    451 
    452     vtkSmartPointer<vtkPolyData> polydata = extract_edges->GetOutput();
    453     VtkUtils::FillScalars(polydata, color);
    454 
    455     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    456     VtkUtils::SetInputData(mapper, polydata);
    457 
    458     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    459     actor->SetMapper(mapper);
    460 
    461     WidgetAccessor::setProp(*this, actor);
    462 }
    463 
    464 cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
    465 {
    466     Vec3d zvec = normalize(normal);
    467     Vec3d xvec = normalize(new_yaxis.cross(zvec));
    468     Vec3d yvec = zvec.cross(xvec);
    469 
    470     WGrid grid(cells, cells_spacing, color);
    471     grid.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    472     *this = grid;
    473 }
    474 
    475 template<> cv::viz::WGrid cv::viz::Widget::cast<cv::viz::WGrid>()
    476 {
    477     Widget3D widget = this->cast<Widget3D>();
    478     return static_cast<WGrid&>(widget);
    479 }
    480 
    481 ///////////////////////////////////////////////////////////////////////////////////////////////
    482 /// text3D widget implementation
    483 
    484 cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color)
    485 {
    486     vtkSmartPointer<vtkVectorText> textSource = vtkSmartPointer<vtkVectorText>::New();
    487     textSource->SetText(text.c_str());
    488     textSource->Update();
    489 
    490     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    491     mapper->SetInputConnection(textSource->GetOutputPort());
    492 
    493     if (face_camera)
    494     {
    495         vtkSmartPointer<vtkFollower> actor = vtkSmartPointer<vtkFollower>::New();
    496         actor->SetMapper(mapper);
    497         actor->SetPosition(position.x, position.y, position.z);
    498         actor->SetScale(text_scale);
    499         WidgetAccessor::setProp(*this, actor);
    500     }
    501     else
    502     {
    503         vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    504         actor->SetMapper(mapper);
    505         actor->SetPosition(position.x, position.y, position.z);
    506         actor->SetScale(text_scale);
    507         actor->GetProperty()->LightingOff();
    508         WidgetAccessor::setProp(*this, actor);
    509     }
    510 
    511     setColor(color);
    512 }
    513 
    514 void cv::viz::WText3D::setText(const String &text)
    515 {
    516     vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
    517     CV_Assert("This widget does not support text." && actor);
    518 
    519     // Update text source
    520     vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    521     vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
    522     CV_Assert("This widget does not support text." && textSource);
    523 
    524     textSource->SetText(text.c_str());
    525     textSource->Modified();
    526     textSource->Update();
    527 }
    528 
    529 cv::String cv::viz::WText3D::getText() const
    530 {
    531     vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this));
    532     CV_Assert("This widget does not support text." && actor);
    533 
    534     vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    535     vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
    536     CV_Assert("This widget does not support text." && textSource);
    537 
    538     return textSource->GetText();
    539 }
    540 
    541 template<> cv::viz::WText3D cv::viz::Widget::cast<cv::viz::WText3D>()
    542 {
    543     Widget3D widget = this->cast<Widget3D>();
    544     return static_cast<WText3D&>(widget);
    545 }
    546 
    547 ///////////////////////////////////////////////////////////////////////////////////////////////
    548 /// text widget implementation
    549 
    550 cv::viz::WText::WText(const String &text, const Point &pos, int font_size, const Color &color)
    551 {
    552     vtkSmartPointer<vtkTextActor> actor = vtkSmartPointer<vtkTextActor>::New();
    553     actor->SetDisplayPosition(pos.x, pos.y);
    554     actor->SetInput(text.c_str());
    555 
    556     actor->GetProperty()->SetDisplayLocationToForeground();
    557 
    558     vtkSmartPointer<vtkTextProperty> tprop = actor->GetTextProperty();
    559     tprop->SetFontSize(font_size);
    560     tprop->SetFontFamilyToCourier();
    561     tprop->SetJustificationToLeft();
    562     tprop->BoldOn();
    563 
    564     Color c = vtkcolor(color);
    565     tprop->SetColor(c.val);
    566 
    567     WidgetAccessor::setProp(*this, actor);
    568 }
    569 
    570 template<> cv::viz::WText cv::viz::Widget::cast<cv::viz::WText>()
    571 {
    572     Widget2D widget = this->cast<Widget2D>();
    573     return static_cast<WText&>(widget);
    574 }
    575 
    576 void cv::viz::WText::setText(const String &text)
    577 {
    578     vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
    579     CV_Assert("This widget does not support text." && actor);
    580     actor->SetInput(text.c_str());
    581 }
    582 
    583 cv::String cv::viz::WText::getText() const
    584 {
    585     vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
    586     CV_Assert("This widget does not support text." && actor);
    587     return actor->GetInput();
    588 }
    589 
    590 ///////////////////////////////////////////////////////////////////////////////////////////////
    591 /// image overlay widget implementation
    592 
    593 cv::viz::WImageOverlay::WImageOverlay(InputArray image, const Rect &rect)
    594 {
    595     CV_Assert(!image.empty() && image.depth() == CV_8U);
    596     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    597     source->SetImage(image);
    598     Size sz = image.size();
    599 
    600     // Scale the image based on the Rect, and flip to match y-ais orientation
    601     vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    602     transform->Scale(sz.width/(double)rect.width, sz.height/(double)rect.height, 1.0);
    603     transform->RotateX(180);
    604 
    605     vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
    606     image_reslice->SetResliceTransform(transform);
    607     image_reslice->SetInputConnection(source->GetOutputPort());
    608     image_reslice->SetOutputDimensionality(2);
    609     image_reslice->InterpolateOn();
    610     image_reslice->AutoCropOutputOn();
    611     image_reslice->Update();
    612 
    613     vtkSmartPointer<vtkImageMapper> image_mapper = vtkSmartPointer<vtkImageMapper>::New();
    614     image_mapper->SetInputConnection(image_reslice->GetOutputPort());
    615     image_mapper->SetColorWindow(255); // OpenCV color
    616     image_mapper->SetColorLevel(127.5);
    617 
    618     vtkSmartPointer<vtkActor2D> actor = vtkSmartPointer<vtkActor2D>::New();
    619     actor->SetMapper(image_mapper);
    620     actor->SetPosition(rect.x, rect.y);
    621     actor->GetProperty()->SetDisplayLocationToForeground();
    622 
    623     WidgetAccessor::setProp(*this, actor);
    624 }
    625 
    626 void cv::viz::WImageOverlay::setImage(InputArray image)
    627 {
    628     CV_Assert(!image.empty() && image.depth() == CV_8U);
    629 
    630     vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
    631     CV_Assert("This widget does not support overlay image." && actor);
    632 
    633     vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper());
    634     CV_Assert("This widget does not support overlay image." && mapper);
    635     \
    636     Vec6i extent;
    637     mapper->GetInput()->GetExtent(extent.val);
    638     Size size(extent[1], extent[3]);
    639 
    640     // Create the vtk image and set its parameters based on input image
    641     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    642     source->SetImage(image);
    643     Size sz = image.size();
    644 
    645     // Scale the image based on the Rect, and flip to match y-ais orientation
    646     vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
    647     transform->Scale(sz.width/(double)size.width, sz.height/(double)size.height, 1.0);
    648     transform->RotateX(180);
    649 
    650     vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
    651     image_reslice->SetResliceTransform(transform);
    652     image_reslice->SetInputConnection(source->GetOutputPort());
    653     image_reslice->SetOutputDimensionality(2);
    654     image_reslice->InterpolateOn();
    655     image_reslice->AutoCropOutputOn();
    656     image_reslice->Update();
    657 
    658     mapper->SetInputConnection(image_reslice->GetOutputPort());
    659 }
    660 
    661 template<> cv::viz::WImageOverlay cv::viz::Widget::cast<cv::viz::WImageOverlay>()
    662 {
    663     Widget2D widget = this->cast<Widget2D>();
    664     return static_cast<WImageOverlay&>(widget);
    665 }
    666 
    667 ///////////////////////////////////////////////////////////////////////////////////////////////
    668 /// image 3D widget implementation
    669 
    670 cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size)
    671 {
    672     CV_Assert(!image.empty() && image.depth() == CV_8U);
    673 
    674     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    675     source->SetImage(image);
    676 
    677     vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    678     texture->SetInputConnection(source->GetOutputPort());
    679 
    680     vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    681     plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
    682     plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
    683     plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
    684 
    685     vtkSmartPointer<vtkTextureMapToPlane> textured_plane = vtkSmartPointer<vtkTextureMapToPlane>::New();
    686     textured_plane->SetInputConnection(plane->GetOutputPort());
    687 
    688     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    689     mapper->SetInputConnection(textured_plane->GetOutputPort());
    690 
    691     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    692     actor->SetMapper(mapper);
    693     actor->SetTexture(texture);
    694     actor->GetProperty()->ShadingOff();
    695     actor->GetProperty()->LightingOff();
    696 
    697     WidgetAccessor::setProp(*this, actor);
    698 }
    699 
    700 cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d &center, const Vec3d &normal, const Vec3d &up_vector)
    701 {
    702     CV_Assert(!image.empty() && image.depth() == CV_8U);
    703 
    704     // Compute the transformation matrix for drawing the camera frame in a scene
    705     Vec3d n = normalize(normal);
    706     Vec3d u = normalize(up_vector.cross(n));
    707     Vec3d v = n.cross(u);
    708     Affine3d pose = makeTransformToGlobal(u, v, n, center);
    709 
    710     WImage3D image3d(image, size);
    711     image3d.applyTransform(pose);
    712     *this = image3d;
    713 }
    714 
    715 void cv::viz::WImage3D::setImage(InputArray image)
    716 {
    717     CV_Assert(!image.empty() && image.depth() == CV_8U);
    718 
    719     vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
    720     CV_Assert("This widget does not support 3D image." && actor);
    721 
    722     vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    723     source->SetImage(image);
    724 
    725     vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    726     texture->SetInputConnection(source->GetOutputPort());
    727 
    728     actor->SetTexture(texture);
    729 }
    730 
    731 template<> cv::viz::WImage3D cv::viz::Widget::cast<cv::viz::WImage3D>()
    732 {
    733     Widget3D widget = this->cast<Widget3D>();
    734     return static_cast<WImage3D&>(widget);
    735 }
    736 
    737 ///////////////////////////////////////////////////////////////////////////////////////////////
    738 /// camera position widget implementation
    739 
    740 namespace  cv  { namespace viz { namespace
    741 {
    742     struct CameraPositionUtils
    743     {
    744         static vtkSmartPointer<vtkPolyData> createFrustum(double aspect_ratio, double fovy, double scale)
    745         {
    746             vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
    747             camera->SetViewAngle(fovy);
    748             camera->SetPosition(0.0, 0.0, 0.0);
    749             camera->SetViewUp(0.0, 1.0, 0.0);
    750             camera->SetFocalPoint(0.0, 0.0, 1.0);
    751             camera->SetClippingRange(1e-9, scale);
    752 
    753             double planes_array[24];
    754             camera->GetFrustumPlanes(aspect_ratio, planes_array);
    755 
    756             vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
    757             planes->SetFrustumPlanes(planes_array);
    758 
    759             vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
    760             frustumSource->SetPlanes(planes);
    761 
    762             vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
    763             extract_edges->SetInputConnection(frustumSource->GetOutputPort());
    764             extract_edges->Update();
    765 
    766             return extract_edges->GetOutput();
    767         }
    768 
    769         static Mat ensureColorImage(InputArray image)
    770         {
    771             Mat color(image.size(), CV_8UC3);
    772             if (image.channels() == 1)
    773             {
    774                 Vec3b *drow = color.ptr<Vec3b>();
    775                 for(int y = 0; y < color.rows; ++y)
    776                 {
    777                     const unsigned char *srow = image.getMat().ptr<unsigned char>(y);
    778                     const unsigned char *send = srow + color.cols;
    779                     for(;srow < send;)
    780                         *drow++ = Vec3b::all(*srow++);
    781                 }
    782             }
    783             else
    784                 image.copyTo(color);
    785             return color;
    786         }
    787     };
    788 }}}
    789 
    790 cv::viz::WCameraPosition::WCameraPosition(double scale)
    791 {
    792     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    793     VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale)));
    794     mapper->SetScalarModeToUsePointData();
    795 
    796     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    797     actor->SetMapper(mapper);
    798 
    799     WidgetAccessor::setProp(*this, actor);
    800 }
    801 
    802 cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color)
    803 {
    804     double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2);
    805 
    806     // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
    807     double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI;
    808     double aspect_ratio = f_y / f_x;
    809 
    810     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
    811     VtkUtils::FillScalars(polydata, color);
    812 
    813     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    814     VtkUtils::SetInputData(mapper, polydata);
    815 
    816     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    817     actor->SetMapper(mapper);
    818 
    819     WidgetAccessor::setProp(*this, actor);
    820 }
    821 
    822 cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color)
    823 {
    824     double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5);
    825     double fovy = fov[1] * 180 / CV_PI;
    826 
    827     vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
    828     VtkUtils::FillScalars(polydata, color);
    829 
    830     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    831     VtkUtils::SetInputData(mapper, polydata);
    832 
    833     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    834     actor->SetMapper(mapper);
    835 
    836     WidgetAccessor::setProp(*this, actor);
    837 }
    838 
    839 cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color)
    840 {
    841     CV_Assert(!_image.empty() && _image.depth() == CV_8U);
    842     Mat image = CameraPositionUtils::ensureColorImage(_image);
    843     image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation
    844 
    845     double f_y = K(1,1), c_y = K(1,2);
    846     // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
    847     double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI;
    848     double far_end_height = 2.00 * c_y * scale / f_y;
    849     double aspect_ratio = image.cols/(double)image.rows;
    850     double image_scale = far_end_height/image.rows;
    851 
    852     WImage3D image_widget(image, Size2d(image.size()) * image_scale);
    853     image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
    854     vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
    855 
    856     vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
    857 
    858     // Frustum needs to be textured or else it can't be combined with image
    859     vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
    860     VtkUtils::SetInputData(frustum_texture, frustum);
    861     frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
    862     frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color
    863 
    864     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    865     append_filter->AddInputConnection(frustum_texture->GetOutputPort());
    866     VtkUtils::AddInputData(append_filter, plane);
    867 
    868     vtkSmartPointer<vtkActor> actor = getActor(image_widget);
    869     actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
    870     WidgetAccessor::setProp(*this, actor);
    871 }
    872 
    873 cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, InputArray _image, double scale, const Color &color)
    874 {
    875     CV_Assert(!_image.empty() && _image.depth() == CV_8U);
    876     Mat image = CameraPositionUtils::ensureColorImage(_image);
    877     image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation
    878 
    879     double fovy = fov[1] * 180.0 / CV_PI;
    880     double far_end_height = 2.0 * scale * tan(fov[1] * 0.5);
    881     double aspect_ratio = image.cols/(double)image.rows;
    882     double image_scale = far_end_height/image.rows;
    883 
    884     WImage3D image_widget(image, Size2d(image.size()) * image_scale);
    885     image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
    886     vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
    887 
    888     vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
    889 
    890     // Frustum needs to be textured or else it can't be combined with image
    891     vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
    892     VtkUtils::SetInputData(frustum_texture, frustum);
    893     frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
    894     frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color
    895 
    896     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    897     append_filter->AddInputConnection(frustum_texture->GetOutputPort());
    898     VtkUtils::AddInputData(append_filter, plane);
    899 
    900     vtkSmartPointer<vtkActor> actor = getActor(image_widget);
    901     actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
    902     WidgetAccessor::setProp(*this, actor);
    903 }
    904 
    905 template<> cv::viz::WCameraPosition cv::viz::Widget::cast<cv::viz::WCameraPosition>()
    906 {
    907     Widget3D widget = this->cast<Widget3D>();
    908     return static_cast<WCameraPosition&>(widget);
    909 }
    910 
    911 ///////////////////////////////////////////////////////////////////////////////////////////////
    912 /// trajectory widget implementation
    913 
    914 cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color)
    915 {
    916     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    917 
    918     // Bitwise and with 3 in order to limit the domain to 2 bits
    919     if (display_mode & WTrajectory::PATH)
    920     {
    921         Mat points = vtkTrajectorySource::ExtractPoints(_path);
    922         vtkSmartPointer<vtkPolyData> polydata = getPolyData(WPolyLine(points, color));
    923         VtkUtils::AddInputData(append_filter, polydata);
    924     }
    925 
    926     if (display_mode & WTrajectory::FRAMES)
    927     {
    928         vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
    929         source->SetTrajectory(_path);
    930 
    931         vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCoordinateSystem(scale));
    932 
    933         vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
    934         tensor_glyph->SetInputConnection(source->GetOutputPort());
    935         VtkUtils::SetSourceData(tensor_glyph, glyph);
    936         tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
    937         tensor_glyph->ThreeGlyphsOff();
    938         tensor_glyph->SymmetricOff();
    939         tensor_glyph->ColorGlyphsOff();
    940 
    941         append_filter->AddInputConnection(tensor_glyph->GetOutputPort());
    942     }
    943     append_filter->Update();
    944 
    945     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    946     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
    947     mapper->SetScalarModeToUsePointData();
    948     mapper->SetScalarRange(0, 255);
    949 
    950     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    951     actor->SetMapper(mapper);
    952 
    953     WidgetAccessor::setProp(*this, actor);
    954 }
    955 
    956 template<> cv::viz::WTrajectory cv::viz::Widget::cast<cv::viz::WTrajectory>()
    957 {
    958     Widget3D widget = this->cast<Widget3D>();
    959     return static_cast<WTrajectory&>(widget);
    960 }
    961 
    962 ///////////////////////////////////////////////////////////////////////////////////////////////
    963 /// WTrajectoryFrustums widget implementation
    964 
    965 cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33d &K, double scale, const Color &color)
    966 {
    967     vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
    968     source->SetTrajectory(_path);
    969 
    970     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(K, scale));
    971     VtkUtils::FillScalars(glyph, color);
    972 
    973     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
    974     tensor_glyph->SetInputConnection(source->GetOutputPort());
    975     VtkUtils::SetSourceData(tensor_glyph, glyph);
    976     tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
    977     tensor_glyph->ThreeGlyphsOff();
    978     tensor_glyph->SymmetricOff();
    979     tensor_glyph->ColorGlyphsOff();
    980     tensor_glyph->Update();
    981 
    982     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    983     VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
    984 
    985     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    986     actor->SetMapper(mapper);
    987 
    988     WidgetAccessor::setProp(*this, actor);
    989 }
    990 
    991 cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color)
    992 {
    993     vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
    994     source->SetTrajectory(_path);
    995 
    996     vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(fov, scale));
    997     VtkUtils::FillScalars(glyph, color);
    998 
    999     vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
   1000     tensor_glyph->SetInputConnection(source->GetOutputPort());
   1001     VtkUtils::SetSourceData(tensor_glyph, glyph);
   1002     tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
   1003     tensor_glyph->ThreeGlyphsOff();
   1004     tensor_glyph->SymmetricOff();
   1005     tensor_glyph->ColorGlyphsOff();
   1006     tensor_glyph->Update();
   1007 
   1008     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
   1009     VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
   1010 
   1011     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
   1012     actor->SetMapper(mapper);
   1013 
   1014     WidgetAccessor::setProp(*this, actor);
   1015 }
   1016 
   1017 template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast<cv::viz::WTrajectoryFrustums>()
   1018 {
   1019     Widget3D widget = this->cast<Widget3D>();
   1020     return static_cast<WTrajectoryFrustums&>(widget);
   1021 }
   1022 
   1023 ///////////////////////////////////////////////////////////////////////////////////////////////
   1024 /// WTrajectorySpheres widget implementation
   1025 
   1026 cv::viz::WTrajectorySpheres::WTrajectorySpheres(InputArray _path, double line_length, double radius, const Color &from, const Color &to)
   1027 {
   1028     CV_Assert(_path.kind() == _InputArray::STD_VECTOR || _path.kind() == _InputArray::MAT);
   1029     CV_Assert(_path.type() == CV_32FC(16) || _path.type() == CV_64FC(16));
   1030 
   1031     Mat path64;
   1032     _path.getMat().convertTo(path64, CV_64F);
   1033     Affine3d *traj = path64.ptr<Affine3d>();
   1034     size_t total = path64.total();
   1035 
   1036     vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
   1037 
   1038     for(size_t i = 0; i < total; ++i)
   1039     {
   1040         Vec3d curr = traj[i].translation();
   1041 
   1042         vtkSmartPointer<vtkSphereSource> sphere_source = vtkSmartPointer<vtkSphereSource>::New();
   1043         sphere_source->SetCenter(curr.val);
   1044         sphere_source->SetRadius( (i == 0) ? 2 * radius : radius );
   1045         sphere_source->Update();
   1046 
   1047         double alpha = static_cast<double>(i)/total;
   1048         Color c = from * (1 - alpha) + to * alpha;
   1049 
   1050         vtkSmartPointer<vtkPolyData> polydata = sphere_source->GetOutput();
   1051         polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c));
   1052         VtkUtils::AddInputData(append_filter, polydata);
   1053 
   1054         if (i > 0)
   1055         {
   1056             Vec3d prev = traj[i-1].translation();
   1057             Vec3d lvec = prev - curr;
   1058 
   1059             if(norm(lvec) > line_length)
   1060                 lvec = normalize(lvec) * line_length;
   1061 
   1062             Vec3d lend = curr + lvec;
   1063 
   1064             vtkSmartPointer<vtkLineSource> line_source = vtkSmartPointer<vtkLineSource>::New();
   1065             line_source->SetPoint1(curr.val);
   1066             line_source->SetPoint2(lend.val);
   1067             line_source->Update();
   1068             vtkSmartPointer<vtkPolyData> polydata_ = line_source->GetOutput();
   1069             polydata_->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata_->GetNumberOfCells(), c));
   1070             VtkUtils::AddInputData(append_filter, polydata_);
   1071         }
   1072     }
   1073     append_filter->Update();
   1074 
   1075     vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
   1076     mapper->SetScalarModeToUseCellData();
   1077     VtkUtils::SetInputData(mapper, append_filter->GetOutput());
   1078 
   1079     vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
   1080     actor->SetMapper(mapper);
   1081 
   1082     WidgetAccessor::setProp(*this, actor);
   1083 }
   1084 
   1085 template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast<cv::viz::WTrajectorySpheres>()
   1086 {
   1087     Widget3D widget = this->cast<Widget3D>();
   1088     return static_cast<WTrajectorySpheres&>(widget);
   1089 }
   1090