shapes.cpp 41.6 KB
Newer Older
Ozan Tonkal's avatar
Ozan Tonkal committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
/*M///////////////////////////////////////////////////////////////////////////////////////
//
//  IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING.
//
//  By downloading, copying, installing or using the software you agree to this license.
//  If you do not agree to this license, do not download, install,
//  copy or use the software.
//
//
//                           License Agreement
//                For Open Source Computer Vision Library
//
// Copyright (C) 2013, OpenCV Foundation, all rights reserved.
// Third party copyrights are property of their respective owners.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
//   * Redistribution's of source code must retain the above copyright notice,
//     this list of conditions and the following disclaimer.
//
//   * Redistribution's in binary form must reproduce the above copyright notice,
//     this list of conditions and the following disclaimer in the documentation
//     and/or other materials provided with the distribution.
//
//   * The name of the copyright holders may not be used to endorse or promote products
//     derived from this software without specific prior written permission.
//
// This software is provided by the copyright holders and contributors "as is" and
// any express or implied warranties, including, but not limited to, the implied
// warranties of merchantability and fitness for a particular purpose are disclaimed.
// In no event shall the Intel Corporation or contributors be liable for any direct,
// indirect, incidental, special, exemplary, or consequential damages
// (including, but not limited to, procurement of substitute goods or services;
// loss of use, data, or profits; or business interruption) however caused
// and on any theory of liability, whether in contract, strict liability,
// or tort (including negligence or otherwise) arising in any way out of
// the use of this software, even if advised of the possibility of such damage.
//
// Authors:
//  * Ozan Tonkal, ozantonkal@gmail.com
//  * Anatoly Baksheev, Itseez Inc.  myname.mysurname <> mycompany.com
//
//M*/

46 47
#include "precomp.hpp"

ozantonkal's avatar
ozantonkal committed
48 49
///////////////////////////////////////////////////////////////////////////////////////////////
/// line widget implementation
50
cv::viz::WLine::WLine(const Point3d &pt1, const Point3d &pt2, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
51
{
52
    vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
53 54
    line->SetPoint1(pt1.x, pt1.y, pt1.z);
    line->SetPoint2(pt2.x, pt2.y, pt2.z);
55
    line->Update();
56

57
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
58
    VtkUtils::SetInputData(mapper, line->GetOutput());
59

60
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
61 62
    actor->SetMapper(mapper);

63
    WidgetAccessor::setProp(*this, actor);
64 65
    setColor(color);
}
66

67
template<> cv::viz::WLine cv::viz::Widget::cast<cv::viz::WLine>()
68 69
{
    Widget3D widget = this->cast<Widget3D>();
70
    return static_cast<WLine&>(widget);
71 72
}

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
///////////////////////////////////////////////////////////////////////////////////////////////
/// sphere widget implementation

cv::viz::WSphere::WSphere(const Point3d &center, double radius, int sphere_resolution, const Color &color)
{
    vtkSmartPointer<vtkSphereSource> sphere = vtkSmartPointer<vtkSphereSource>::New();
    sphere->SetRadius(radius);
    sphere->SetCenter(center.x, center.y, center.z);
    sphere->SetPhiResolution(sphere_resolution);
    sphere->SetThetaResolution(sphere_resolution);
    sphere->LatLongTessellationOff();
    sphere->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    VtkUtils::SetInputData(mapper, sphere->GetOutput());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

template<> cv::viz::WSphere cv::viz::Widget::cast<cv::viz::WSphere>()
{
    Widget3D widget = this->cast<Widget3D>();
    return static_cast<WSphere&>(widget);
}

ozantonkal's avatar
ozantonkal committed
102 103 104
///////////////////////////////////////////////////////////////////////////////////////////////
/// plane widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
cv::viz::WPlane::WPlane(const Size2d& size, const Color &color)
{
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
    plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
    plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
    plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
    plane->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    VtkUtils::SetInputData(mapper, plane->GetOutput());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->LightingOff();

    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

Anatoly Baksheev's avatar
Anatoly Baksheev committed
124
cv::viz::WPlane::WPlane(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Size2d& size, const Color &color)
Anatoly Baksheev's avatar
Anatoly Baksheev committed
125 126
{
    Vec3d zvec = normalize(normal);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
127
    Vec3d xvec = normalize(new_yaxis.cross(zvec));
Anatoly Baksheev's avatar
Anatoly Baksheev committed
128 129 130 131 132 133 134
    Vec3d yvec = zvec.cross(xvec);

    WPlane plane(size, color);
    plane.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    *this = plane;
}

135
template<> cv::viz::WPlane cv::viz::Widget::cast<cv::viz::WPlane>()
136
{
137
    Widget3D widget = this->cast<Widget3D>();
138
    return static_cast<WPlane&>(widget);
139 140
}

141 142 143
///////////////////////////////////////////////////////////////////////////////////////////////
/// arrow widget implementation

144
cv::viz::WArrow::WArrow(const Point3d& pt1, const Point3d& pt2, double thickness, const Color &color)
145
{
146 147 148 149
    vtkSmartPointer<vtkArrowSource> arrow_source = vtkSmartPointer<vtkArrowSource>::New();
    arrow_source->SetShaftRadius(thickness);
    arrow_source->SetTipRadius(thickness * 3.0);
    arrow_source->SetTipLength(thickness * 10.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
150

Anatoly Baksheev's avatar
Anatoly Baksheev committed
151 152
    Vec3d arbitrary = get_random_vec();
    Vec3d start_point(pt1.x, pt1.y, pt1.z), end_point(pt2.x, pt2.y, pt2.z);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
153

Anatoly Baksheev's avatar
Anatoly Baksheev committed
154
    double length = norm(end_point - start_point);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
155

Anatoly Baksheev's avatar
Anatoly Baksheev committed
156
    Vec3d xvec = normalized(end_point - start_point);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
157 158
    Vec3d zvec = normalized(xvec.cross(arbitrary));
    Vec3d yvec = zvec.cross(xvec);
159

Anatoly Baksheev's avatar
Anatoly Baksheev committed
160
    Matx33d R = makeTransformToGlobal(xvec, yvec, zvec).rotation();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
161
    Affine3d transform_with_scale(R * length, start_point);
162

Anatoly Baksheev's avatar
Anatoly Baksheev committed
163
    vtkSmartPointer<vtkPolyData> polydata = VtkUtils::TransformPolydata(arrow_source->GetOutputPort(), transform_with_scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
164

165
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
166
    VtkUtils::SetInputData(mapper, polydata);
167

168
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
169
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
170

171
    WidgetAccessor::setProp(*this, actor);
172 173 174
    setColor(color);
}

175
template<> cv::viz::WArrow cv::viz::Widget::cast<cv::viz::WArrow>()
176
{
177
    Widget3D widget = this->cast<Widget3D>();
178
    return static_cast<WArrow&>(widget);
179 180
}

181 182 183
///////////////////////////////////////////////////////////////////////////////////////////////
/// circle widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
184
cv::viz::WCircle::WCircle(double radius, double thickness, const Color &color)
185
{
Ozan Tonkal's avatar
Ozan Tonkal committed
186
    vtkSmartPointer<vtkDiskSource> disk = vtkSmartPointer<vtkDiskSource>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
187
    disk->SetCircumferentialResolution(30);
Ozan Tonkal's avatar
Ozan Tonkal committed
188 189
    disk->SetInnerRadius(radius - thickness);
    disk->SetOuterRadius(radius + thickness);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
190
    disk->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
191

192
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
193
    VtkUtils::SetInputData(mapper, disk->GetOutput());
194

195
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
196
    actor->GetProperty()->LightingOff();
197
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
198

199
    WidgetAccessor::setProp(*this, actor);
200
    setColor(color);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
201 202 203 204 205 206 207 208 209 210 211 212 213

}

cv::viz::WCircle::WCircle(double radius, const Point3d& center, const Vec3d& normal, double thickness, const Color &color)
{
    Vec3d arbitrary = get_random_vec();
    Vec3d zvec = normalized(normal);
    Vec3d xvec = normalized(zvec.cross(arbitrary));
    Vec3d yvec = zvec.cross(xvec);

    WCircle circle(radius, thickness, color);
    circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    *this = circle;
214 215
}

216
template<> cv::viz::WCircle cv::viz::Widget::cast<cv::viz::WCircle>()
217
{
218
    Widget3D widget = this->cast<Widget3D>();
219
    return static_cast<WCircle&>(widget);
220 221
}

222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
///////////////////////////////////////////////////////////////////////////////////////////////
/// WCone widget implementation

cv::viz::WCone::WCone(double length, double radius, int resolution, const Color &color)
{
    vtkSmartPointer<vtkConeSource> cone_source = vtkSmartPointer<vtkConeSource>::New();
    cone_source->SetCenter(length*0.5, 0.0, 0.0);
    cone_source->SetHeight(length);
    cone_source->SetRadius(radius);
    cone_source->SetResolution(resolution);
    cone_source->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    VtkUtils::SetInputData(mapper, cone_source->GetOutput());

    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);

    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

cv::viz::WCone::WCone(double radius, const Point3d& center, const Point3d& tip, int resolution, const Color &color)
{
    Vec3d arbitrary = get_random_vec();
    Vec3d xvec = normalized(Vec3d(tip - center));
    Vec3d zvec = normalized(xvec.cross(arbitrary));
    Vec3d yvec = zvec.cross(xvec);

    WCone circle(norm(tip - center), radius, resolution, color);
    circle.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    *this = circle;
}

template<> cv::viz::WCone cv::viz::Widget::cast<cv::viz::WCone>()
{
    Widget3D widget = this->cast<Widget3D>();
    return static_cast<WCone&>(widget);
}

262 263 264
///////////////////////////////////////////////////////////////////////////////////////////////
/// cylinder widget implementation

265
cv::viz::WCylinder::WCylinder(const Point3d& axis_point1, const Point3d& axis_point2, double radius, int numsides, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
266
{
Ozan Tonkal's avatar
Ozan Tonkal committed
267
    vtkSmartPointer<vtkLineSource> line = vtkSmartPointer<vtkLineSource>::New();
268 269
    line->SetPoint1(axis_point1.x, axis_point1.y, axis_point1.z);
    line->SetPoint2(axis_point2.x, axis_point2.y, axis_point2.z);
Ozan Tonkal's avatar
Ozan Tonkal committed
270

Ozan Tonkal's avatar
Ozan Tonkal committed
271 272 273
    vtkSmartPointer<vtkTubeFilter> tuber = vtkSmartPointer<vtkTubeFilter>::New();
    tuber->SetInputConnection(line->GetOutputPort());
    tuber->SetNumberOfSides(numsides);
274
    tuber->SetRadius(radius);
275
    tuber->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
276

277
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
278
    VtkUtils::SetInputData(mapper, tuber->GetOutput());
279

280
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
281
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
282

283
    WidgetAccessor::setProp(*this, actor);
284 285
    setColor(color);
}
ozantonkal's avatar
ozantonkal committed
286

287
template<> cv::viz::WCylinder cv::viz::Widget::cast<cv::viz::WCylinder>()
288
{
289
    Widget3D widget = this->cast<Widget3D>();
290
    return static_cast<WCylinder&>(widget);
291 292
}

ozantonkal's avatar
ozantonkal committed
293 294 295
///////////////////////////////////////////////////////////////////////////////////////////////
/// cylinder widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
296
cv::viz::WCube::WCube(const Point3d& min_point, const Point3d& max_point, bool wire_frame, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
297
{
298 299 300 301 302 303 304 305
    double bounds[6];
    bounds[0] = std::min(min_point.x, max_point.x);
    bounds[1] = std::max(min_point.x, max_point.x);
    bounds[2] = std::min(min_point.y, max_point.y);
    bounds[3] = std::max(min_point.y, max_point.y);
    bounds[4] = std::min(min_point.z, max_point.z);
    bounds[5] = std::max(min_point.z, max_point.z);

306
    vtkSmartPointer<vtkPolyDataAlgorithm> cube;
307 308
    if (wire_frame)
    {
309
        cube = vtkSmartPointer<vtkOutlineSource>::New();
310
        vtkOutlineSource::SafeDownCast(cube)->SetBounds(bounds);
311 312 313
    }
    else
    {
314
        cube = vtkSmartPointer<vtkCubeSource>::New();
315
        vtkCubeSource::SafeDownCast(cube)->SetBounds(bounds);
316
    }
317 318 319 320
    cube->Update();

    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    VtkUtils::SetInputData(mapper, cube->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
321

322
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
ozantonkal's avatar
ozantonkal committed
323
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
324

325
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
326 327
    setColor(color);
}
328

329
template<> cv::viz::WCube cv::viz::Widget::cast<cv::viz::WCube>()
330
{
331
    Widget3D widget = this->cast<Widget3D>();
332
    return static_cast<WCube&>(widget);
333 334
}

335 336 337
///////////////////////////////////////////////////////////////////////////////////////////////
/// coordinate system widget implementation

338
cv::viz::WCoordinateSystem::WCoordinateSystem(double scale)
339
{
Ozan Tonkal's avatar
Ozan Tonkal committed
340 341 342
    vtkSmartPointer<vtkAxes> axes = vtkSmartPointer<vtkAxes>::New();
    axes->SetOrigin(0, 0, 0);
    axes->SetScaleFactor(scale);
343
    axes->Update();
344 345 346 347 348 349 350 351 352 353 354 355 356 357

    vtkSmartPointer<vtkUnsignedCharArray> colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->InsertNextTuple3(255, 0, 0);
    colors->InsertNextTuple3(255, 0, 0);
    colors->InsertNextTuple3(0, 255, 0);
    colors->InsertNextTuple3(0, 255, 0);
    colors->InsertNextTuple3(0, 0, 255);
    colors->InsertNextTuple3(0, 0, 255);

    vtkSmartPointer<vtkPolyData> polydata = axes->GetOutput();
    polydata->GetPointData()->SetScalars(colors);

    vtkSmartPointer<vtkTubeFilter> tube_filter = vtkSmartPointer<vtkTubeFilter>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
358
    tube_filter->SetInputConnection(polydata->GetProducerPort());
359 360
    tube_filter->SetRadius(axes->GetScaleFactor() / 50.0);
    tube_filter->SetNumberOfSides(6);
361
    tube_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
362

363
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
364
    mapper->SetScalarModeToUsePointData();
365
    VtkUtils::SetInputData(mapper, tube_filter->GetOutput());
366

367
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
368
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
369

370
    WidgetAccessor::setProp(*this, actor);
371
}
ozantonkal's avatar
ozantonkal committed
372

373
template<> cv::viz::WCoordinateSystem cv::viz::Widget::cast<cv::viz::WCoordinateSystem>()
374
{
375
    Widget3D widget = this->cast<Widget3D>();
376
    return static_cast<WCoordinateSystem&>(widget);
377 378
}

379 380 381
///////////////////////////////////////////////////////////////////////////////////////////////
/// polyline widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
382
cv::viz::WPolyLine::WPolyLine(InputArray _points, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
383
{
Anatoly Baksheev's avatar
Anatoly Baksheev committed
384
    CV_Assert(_points.type() == CV_32FC3 || _points.type() == CV_32FC4 || _points.type() == CV_64FC3 || _points.type() == CV_64FC4);
385

Anatoly Baksheev's avatar
Anatoly Baksheev committed
386 387 388 389
    const float *fpoints = _points.getMat().ptr<float>();
    const double *dpoints = _points.getMat().ptr<double>();
    size_t total = _points.total();
    int s_chs = _points.channels();
Ozan Tonkal's avatar
Ozan Tonkal committed
390

Ozan Tonkal's avatar
Ozan Tonkal committed
391
    vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
392 393
    points->SetDataType(_points.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE);
    points->SetNumberOfPoints(total);
Ozan Tonkal's avatar
Ozan Tonkal committed
394

Anatoly Baksheev's avatar
Anatoly Baksheev committed
395 396 397
    if (_points.depth() == CV_32F)
        for(size_t i = 0; i < total; ++i, fpoints += s_chs)
            points->SetPoint(i, fpoints);
Ozan Tonkal's avatar
Ozan Tonkal committed
398

Anatoly Baksheev's avatar
Anatoly Baksheev committed
399 400 401
    if (_points.depth() == CV_64F)
        for(size_t i = 0; i < total; ++i, dpoints += s_chs)
            points->SetPoint(i, dpoints);
Ozan Tonkal's avatar
Ozan Tonkal committed
402

Anatoly Baksheev's avatar
Anatoly Baksheev committed
403 404 405 406 407
    vtkSmartPointer<vtkCellArray> cell_array = vtkSmartPointer<vtkCellArray>::New();
    cell_array->Allocate(cell_array->EstimateSize(1, total));
    cell_array->InsertNextCell(total);
    for(size_t i = 0; i < total; ++i)
        cell_array->InsertCellPoint(i);
Ozan Tonkal's avatar
Ozan Tonkal committed
408

Anatoly Baksheev's avatar
Anatoly Baksheev committed
409
    vtkSmartPointer<vtkUnsignedCharArray> scalars =  VtkUtils::FillScalars(total, color);
410

Anatoly Baksheev's avatar
Anatoly Baksheev committed
411 412 413
    vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
    polydata->SetPoints(points);
    polydata->SetLines(cell_array);
414
    polydata->GetPointData()->SetScalars(scalars);
Ozan Tonkal's avatar
Ozan Tonkal committed
415

416
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
417
    VtkUtils::SetInputData(mapper, polydata);
418
    mapper->SetScalarRange(0, 255);
Ozan Tonkal's avatar
Ozan Tonkal committed
419

420 421
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
422

423 424 425
    WidgetAccessor::setProp(*this, actor);
}

426
template<> cv::viz::WPolyLine cv::viz::Widget::cast<cv::viz::WPolyLine>()
427 428
{
    Widget3D widget = this->cast<Widget3D>();
429
    return static_cast<WPolyLine&>(widget);
430 431
}

ozantonkal's avatar
ozantonkal committed
432 433 434
///////////////////////////////////////////////////////////////////////////////////////////////
/// grid widget implementation

435

Anatoly Baksheev's avatar
Anatoly Baksheev committed
436
cv::viz::WGrid::WGrid(const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
ozantonkal's avatar
ozantonkal committed
437
{
Anatoly Baksheev's avatar
Anatoly Baksheev committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451
    vtkSmartPointer<vtkImageData> grid_data = vtkSmartPointer<vtkImageData>::New();

    // Add 1 to dimensions because in ImageData dimensions is the number of lines
    // - however here it means number of cells
    grid_data->SetDimensions(cells[0]+1, cells[1]+1, 1);
    grid_data->SetSpacing(cells_spacing[0], cells_spacing[1], 0.);

    // Set origin of the grid to be the middle of the grid
    grid_data->SetOrigin(cells[0] * cells_spacing[0] * (-0.5), cells[1] * cells_spacing[1] * (-0.5), 0);

    // Extract the edges so we have the grid
    vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
    extract_edges->SetInputConnection(grid_data->GetProducerPort());
    extract_edges->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
452

453
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
454
    VtkUtils::SetInputData(mapper, extract_edges->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
455

456 457
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
458

459 460 461 462
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

Anatoly Baksheev's avatar
Anatoly Baksheev committed
463
cv::viz::WGrid::WGrid(const Point3d& center, const Vec3d& normal, const Vec3d& new_yaxis, const Vec2i &cells, const Vec2d &cells_spacing, const Color &color)
464
{
Anatoly Baksheev's avatar
Anatoly Baksheev committed
465 466 467
    Vec3d zvec = normalize(normal);
    Vec3d xvec = normalize(new_yaxis.cross(zvec));
    Vec3d yvec = zvec.cross(xvec);
Ozan Tonkal's avatar
Ozan Tonkal committed
468

Anatoly Baksheev's avatar
Anatoly Baksheev committed
469 470 471
    WGrid grid(cells, cells_spacing, color);
    grid.applyTransform(makeTransformToGlobal(xvec, yvec, zvec, center));
    *this = grid;
ozantonkal's avatar
ozantonkal committed
472 473
}

474
template<> cv::viz::WGrid cv::viz::Widget::cast<cv::viz::WGrid>()
ozantonkal's avatar
ozantonkal committed
475 476
{
    Widget3D widget = this->cast<Widget3D>();
477
    return static_cast<WGrid&>(widget);
ozantonkal's avatar
ozantonkal committed
478 479
}

480 481 482
///////////////////////////////////////////////////////////////////////////////////////////////
/// text3D widget implementation

483
cv::viz::WText3D::WText3D(const String &text, const Point3d &position, double text_scale, bool face_camera, const Color &color)
484
{
485 486 487
    vtkSmartPointer<vtkVectorText> textSource = vtkSmartPointer<vtkVectorText>::New();
    textSource->SetText(text.c_str());
    textSource->Update();
488

489
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
490
    mapper->SetInputConnection(textSource->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
491

492 493 494 495 496 497 498 499 500 501 502 503 504 505
    if (face_camera)
    {
        vtkSmartPointer<vtkFollower> actor = vtkSmartPointer<vtkFollower>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(position.x, position.y, position.z);
        actor->SetScale(text_scale);
        WidgetAccessor::setProp(*this, actor);
    }
    else
    {
        vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
        actor->SetMapper(mapper);
        actor->SetPosition(position.x, position.y, position.z);
        actor->SetScale(text_scale);
506
        actor->GetProperty()->LightingOff();
507 508
        WidgetAccessor::setProp(*this, actor);
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
509

510 511 512
    setColor(color);
}

513
void cv::viz::WText3D::setText(const String &text)
514
{
515
    vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
516
    CV_Assert("This widget does not support text." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
517

518 519 520
    // Update text source
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
521
    CV_Assert("This widget does not support text." && textSource);
Ozan Tonkal's avatar
Ozan Tonkal committed
522

523
    textSource->SetText(text.c_str());
524
    textSource->Modified();
525 526 527
    textSource->Update();
}

528
cv::String cv::viz::WText3D::getText() const
529 530
{
    vtkFollower *actor = vtkFollower::SafeDownCast(WidgetAccessor::getProp(*this));
531
    CV_Assert("This widget does not support text." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
532

533 534
    vtkPolyDataMapper *mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper());
    vtkVectorText * textSource = vtkVectorText::SafeDownCast(mapper->GetInputConnection(0,0)->GetProducer());
535
    CV_Assert("This widget does not support text." && textSource);
Ozan Tonkal's avatar
Ozan Tonkal committed
536

537 538 539
    return textSource->GetText();
}

540
template<> cv::viz::WText3D cv::viz::Widget::cast<cv::viz::WText3D>()
541 542
{
    Widget3D widget = this->cast<Widget3D>();
543
    return static_cast<WText3D&>(widget);
544 545
}

546 547 548
///////////////////////////////////////////////////////////////////////////////////////////////
/// text widget implementation

549
cv::viz::WText::WText(const String &text, const Point &pos, int font_size, const Color &color)
ozantonkal's avatar
ozantonkal committed
550
{
551
    vtkSmartPointer<vtkTextActor> actor = vtkSmartPointer<vtkTextActor>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
552 553
    actor->SetPosition(pos.x, pos.y);
    actor->SetInput(text.c_str());
ozantonkal's avatar
ozantonkal committed
554

Ozan Tonkal's avatar
Ozan Tonkal committed
555 556 557 558 559
    vtkSmartPointer<vtkTextProperty> tprop = actor->GetTextProperty();
    tprop->SetFontSize(font_size);
    tprop->SetFontFamilyToArial();
    tprop->SetJustificationToLeft();
    tprop->BoldOn();
ozantonkal's avatar
ozantonkal committed
560 561

    Color c = vtkcolor(color);
Ozan Tonkal's avatar
Ozan Tonkal committed
562
    tprop->SetColor(c.val);
Ozan Tonkal's avatar
Ozan Tonkal committed
563

564
    WidgetAccessor::setProp(*this, actor);
ozantonkal's avatar
ozantonkal committed
565
}
566

567
template<> cv::viz::WText cv::viz::Widget::cast<cv::viz::WText>()
568
{
569
    Widget2D widget = this->cast<Widget2D>();
570
    return static_cast<WText&>(widget);
571 572
}

573
void cv::viz::WText::setText(const String &text)
574 575
{
    vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
576
    CV_Assert("This widget does not support text." && actor);
577 578 579
    actor->SetInput(text.c_str());
}

580
cv::String cv::viz::WText::getText() const
581 582
{
    vtkTextActor *actor = vtkTextActor::SafeDownCast(WidgetAccessor::getProp(*this));
583
    CV_Assert("This widget does not support text." && actor);
584 585
    return actor->GetInput();
}
586 587 588 589

///////////////////////////////////////////////////////////////////////////////////////////////
/// image overlay widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
590
cv::viz::WImageOverlay::WImageOverlay(InputArray image, const Rect &rect)
591 592
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
593 594
    vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    source->SetImage(image);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
595
    Size sz = image.size();
Ozan Tonkal's avatar
Ozan Tonkal committed
596

597
    // Scale the image based on the Rect, and flip to match y-ais orientation
598
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
599
    transform->Scale(sz.width/(double)rect.width, sz.height/(double)rect.height, 1.0);
600
    transform->RotateX(180);
Ozan Tonkal's avatar
Ozan Tonkal committed
601

602 603
    vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
    image_reslice->SetResliceTransform(transform);
604
    image_reslice->SetInputConnection(source->GetOutputPort());
605 606
    image_reslice->SetOutputDimensionality(2);
    image_reslice->InterpolateOn();
Ozan Tonkal's avatar
Ozan Tonkal committed
607
    image_reslice->AutoCropOutputOn();
608
    image_reslice->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
609

610 611 612 613
    vtkSmartPointer<vtkImageMapper> image_mapper = vtkSmartPointer<vtkImageMapper>::New();
    image_mapper->SetInputConnection(image_reslice->GetOutputPort());
    image_mapper->SetColorWindow(255); // OpenCV color
    image_mapper->SetColorLevel(127.5);
Ozan Tonkal's avatar
Ozan Tonkal committed
614

615
    vtkSmartPointer<vtkActor2D> actor = vtkSmartPointer<vtkActor2D>::New();
616
    actor->SetMapper(image_mapper);
617
    actor->SetPosition(rect.x, rect.y);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
618
    actor->GetProperty()->SetDisplayLocationToForeground();
Ozan Tonkal's avatar
Ozan Tonkal committed
619

620 621 622
    WidgetAccessor::setProp(*this, actor);
}

Anatoly Baksheev's avatar
Anatoly Baksheev committed
623
void cv::viz::WImageOverlay::setImage(InputArray image)
624 625
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
626

627
    vtkActor2D *actor = vtkActor2D::SafeDownCast(WidgetAccessor::getProp(*this));
628
    CV_Assert("This widget does not support overlay image." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
629

630
    vtkImageMapper *mapper = vtkImageMapper::SafeDownCast(actor->GetMapper());
631
    CV_Assert("This widget does not support overlay image." && mapper);
632 633 634 635
    \
    Vec6i extent;
    mapper->GetInput()->GetExtent(extent.val);
    Size size(extent[1], extent[3]);
Ozan Tonkal's avatar
Ozan Tonkal committed
636

637
    // Create the vtk image and set its parameters based on input image
638 639
    vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    source->SetImage(image);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
640
    Size sz = image.size();
Ozan Tonkal's avatar
Ozan Tonkal committed
641

642 643
    // Scale the image based on the Rect, and flip to match y-ais orientation
    vtkSmartPointer<vtkTransform> transform = vtkSmartPointer<vtkTransform>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
644
    transform->Scale(sz.width/(double)size.width, sz.height/(double)size.height, 1.0);
645 646 647 648 649 650 651 652 653
    transform->RotateX(180);

    vtkSmartPointer<vtkImageReslice> image_reslice = vtkSmartPointer<vtkImageReslice>::New();
    image_reslice->SetResliceTransform(transform);
    image_reslice->SetInputConnection(source->GetOutputPort());
    image_reslice->SetOutputDimensionality(2);
    image_reslice->InterpolateOn();
    image_reslice->AutoCropOutputOn();
    image_reslice->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
654

655
    mapper->SetInputConnection(image_reslice->GetOutputPort());
656 657
}

658
template<> cv::viz::WImageOverlay cv::viz::Widget::cast<cv::viz::WImageOverlay>()
659 660
{
    Widget2D widget = this->cast<Widget2D>();
661
    return static_cast<WImageOverlay&>(widget);
662 663 664 665 666
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// image 3D widget implementation

Anatoly Baksheev's avatar
Anatoly Baksheev committed
667
cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size)
668 669
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
670

671 672
    vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    source->SetImage(image);
Ozan Tonkal's avatar
Ozan Tonkal committed
673

Anatoly Baksheev's avatar
Anatoly Baksheev committed
674 675
    vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
    texture->SetInputConnection(source->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
676

677
    vtkSmartPointer<vtkPlaneSource> plane = vtkSmartPointer<vtkPlaneSource>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
678 679 680
    plane->SetOrigin(-0.5 * size.width, -0.5 * size.height, 0.0);
    plane->SetPoint1( 0.5 * size.width, -0.5 * size.height, 0.0);
    plane->SetPoint2(-0.5 * size.width,  0.5 * size.height, 0.0);
Ozan Tonkal's avatar
Ozan Tonkal committed
681

Anatoly Baksheev's avatar
Anatoly Baksheev committed
682 683
    vtkSmartPointer<vtkTextureMapToPlane> textured_plane = vtkSmartPointer<vtkTextureMapToPlane>::New();
    textured_plane->SetInputConnection(plane->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
684

Anatoly Baksheev's avatar
Anatoly Baksheev committed
685 686
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetInputConnection(textured_plane->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
687

688
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
689
    actor->SetMapper(mapper);
690
    actor->SetTexture(texture);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
691 692
    actor->GetProperty()->ShadingOff();
    actor->GetProperty()->LightingOff();
Ozan Tonkal's avatar
Ozan Tonkal committed
693

694 695 696
    WidgetAccessor::setProp(*this, actor);
}

Anatoly Baksheev's avatar
Anatoly Baksheev committed
697
cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d &center, const Vec3d &normal, const Vec3d &up_vector)
698 699
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
700

701
    // Compute the transformation matrix for drawing the camera frame in a scene
Anatoly Baksheev's avatar
Anatoly Baksheev committed
702 703 704
    Vec3d n = normalize(normal);
    Vec3d u = normalize(up_vector.cross(n));
    Vec3d v = n.cross(u);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
705
    Affine3d pose = makeTransformToGlobal(u, v, n, center);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
706

Anatoly Baksheev's avatar
Anatoly Baksheev committed
707 708 709
    WImage3D image3d(image, size);
    image3d.applyTransform(pose);
    *this = image3d;
710 711
}

Anatoly Baksheev's avatar
Anatoly Baksheev committed
712
void cv::viz::WImage3D::setImage(InputArray image)
713 714
{
    CV_Assert(!image.empty() && image.depth() == CV_8U);
Ozan Tonkal's avatar
Ozan Tonkal committed
715

716
    vtkActor *actor = vtkActor::SafeDownCast(WidgetAccessor::getProp(*this));
717
    CV_Assert("This widget does not support 3D image." && actor);
Ozan Tonkal's avatar
Ozan Tonkal committed
718

719 720
    vtkSmartPointer<vtkImageMatSource> source = vtkSmartPointer<vtkImageMatSource>::New();
    source->SetImage(image);
Ozan Tonkal's avatar
Ozan Tonkal committed
721

722
    vtkSmartPointer<vtkTexture> texture = vtkSmartPointer<vtkTexture>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
723
    texture->SetInputConnection(source->GetOutputPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
724

725
    actor->SetTexture(texture);
726 727
}

728
template<> cv::viz::WImage3D cv::viz::Widget::cast<cv::viz::WImage3D>()
729 730
{
    Widget3D widget = this->cast<Widget3D>();
731
    return static_cast<WImage3D&>(widget);
732 733 734 735
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// camera position widget implementation
736

737
namespace  cv  { namespace viz { namespace
738
{
739
    struct CameraPositionUtils
740
    {
741
        static vtkSmartPointer<vtkPolyData> createFrustum(double aspect_ratio, double fovy, double scale)
742 743
        {
            vtkSmartPointer<vtkCamera> camera = vtkSmartPointer<vtkCamera>::New();
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
            camera->SetViewAngle(fovy);
            camera->SetPosition(0.0, 0.0, 0.0);
            camera->SetViewUp(0.0, 1.0, 0.0);
            camera->SetFocalPoint(0.0, 0.0, 1.0);
            camera->SetClippingRange(1e-9, scale);

            double planes_array[24];
            camera->GetFrustumPlanes(aspect_ratio, planes_array);

            vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();
            planes->SetFrustumPlanes(planes_array);

            vtkSmartPointer<vtkFrustumSource> frustumSource = vtkSmartPointer<vtkFrustumSource>::New();
            frustumSource->SetPlanes(planes);

            vtkSmartPointer<vtkExtractEdges> extract_edges = vtkSmartPointer<vtkExtractEdges>::New();
            extract_edges->SetInputConnection(frustumSource->GetOutputPort());
            extract_edges->Update();

            return extract_edges->GetOutput();
        }

766
        static Mat ensureColorImage(InputArray image)
767
        {
768 769
            Mat color(image.size(), CV_8UC3);
            if (image.channels() == 1)
Anatoly Baksheev's avatar
Anatoly Baksheev committed
770
            {
771 772
                Vec3b *drow = color.ptr<Vec3b>();
                for(int y = 0; y < color.rows; ++y)
Anatoly Baksheev's avatar
Anatoly Baksheev committed
773
                {
774 775
                    const unsigned char *srow = image.getMat().ptr<unsigned char>(y);
                    const unsigned char *send = srow + color.cols;
Anatoly Baksheev's avatar
Anatoly Baksheev committed
776 777 778 779
                    for(;srow < send;)
                        *drow++ = Vec3b::all(*srow++);
                }
            }
780 781 782
            else
                image.copyTo(color);
            return color;
783
        }
784 785
    };
}}}
786

787
cv::viz::WCameraPosition::WCameraPosition(double scale)
788
{
789
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
790
    VtkUtils::SetInputData(mapper, getPolyData(WCoordinateSystem(scale)));
Ozan Tonkal's avatar
Ozan Tonkal committed
791
    mapper->SetScalarModeToUsePointData();
792

793
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
794
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
795

796 797 798
    WidgetAccessor::setProp(*this, actor);
}

799
cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, double scale, const Color &color)
800
{
801
    double f_x = K(0,0), f_y = K(1,1), c_y = K(1,2);
Ozan Tonkal's avatar
Ozan Tonkal committed
802

803 804 805
    // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
    double fovy = 2.0 * atan2(c_y, f_y) * 180 / CV_PI;
    double aspect_ratio = f_y / f_x;
806

807
    vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
808

809
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
810
    VtkUtils::SetInputData(mapper, polydata);
Ozan Tonkal's avatar
Ozan Tonkal committed
811

812 813
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
814

815 816 817
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
818

819
cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, double scale, const Color &color)
820
{
821
    double aspect_ratio = tan(fov[0] * 0.5) / tan(fov[1] * 0.5);
822
    double fovy = fov[1] * 180 / CV_PI;
Ozan Tonkal's avatar
Ozan Tonkal committed
823

824
    vtkSmartPointer<vtkPolyData> polydata = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
825

826
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
827
    VtkUtils::SetInputData(mapper, polydata);
Ozan Tonkal's avatar
Ozan Tonkal committed
828

829 830
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
831

832 833 834
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
835

836
cv::viz::WCameraPosition::WCameraPosition(const Matx33d &K, InputArray _image, double scale, const Color &color)
837
{
838 839 840 841
    CV_Assert(!_image.empty() && _image.depth() == CV_8U);
    Mat image = CameraPositionUtils::ensureColorImage(_image);
    image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation

842
    double f_y = K(1,1), c_y = K(1,2);
843
    // Assuming that this is an ideal camera (c_y and c_x are at the center of the image)
844 845
    double fovy = 2.0 * atan2(c_y, f_y) * 180.0 / CV_PI;
    double far_end_height = 2.00 * c_y * scale / f_y;
Anatoly Baksheev's avatar
Anatoly Baksheev committed
846
    double aspect_ratio = image.cols/(double)image.rows;
847 848 849 850 851
    double image_scale = far_end_height/image.rows;

    WImage3D image_widget(image, Size2d(image.size()) * image_scale);
    image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
    vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
852 853

    vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
854

855 856 857 858 859 860 861 862 863 864 865 866
    // Frustum needs to be textured or else it can't be combined with image
    vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
    frustum_texture->SetInputConnection(frustum->GetProducerPort());
    frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
    frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color

    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    append_filter->AddInputConnection(frustum_texture->GetOutputPort());
    append_filter->AddInputConnection(plane->GetProducerPort());

    vtkSmartPointer<vtkActor> actor = getActor(image_widget);
    actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
867 868 869
    WidgetAccessor::setProp(*this, actor);
}

870
cv::viz::WCameraPosition::WCameraPosition(const Vec2d &fov, InputArray _image, double scale, const Color &color)
871
{
872 873 874 875
    CV_Assert(!_image.empty() && _image.depth() == CV_8U);
    Mat image = CameraPositionUtils::ensureColorImage(_image);
    image.at<Vec3b>(0, 0) = Vec3d(color.val); //workaround of VTK limitation

876 877
    double fovy = fov[1] * 180.0 / CV_PI;
    double far_end_height = 2.0 * scale * tan(fov[1] * 0.5);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
878
    double aspect_ratio = image.cols/(double)image.rows;
879 880 881 882 883
    double image_scale = far_end_height/image.rows;

    WImage3D image_widget(image, Size2d(image.size()) * image_scale);
    image_widget.applyTransform(Affine3d().translate(Vec3d(0, 0, scale)));
    vtkSmartPointer<vtkPolyData> plane = getPolyData(image_widget);
Anatoly Baksheev's avatar
Anatoly Baksheev committed
884 885

    vtkSmartPointer<vtkPolyData> frustum = CameraPositionUtils::createFrustum(aspect_ratio, fovy, scale);
Ozan Tonkal's avatar
Ozan Tonkal committed
886

887 888 889 890 891 892 893 894 895 896 897 898
    // Frustum needs to be textured or else it can't be combined with image
    vtkSmartPointer<vtkTextureMapToPlane> frustum_texture = vtkSmartPointer<vtkTextureMapToPlane>::New();
    frustum_texture->SetInputConnection(frustum->GetProducerPort());
    frustum_texture->SetSRange(0.0, 0.0); // Texture mapping with only one pixel
    frustum_texture->SetTRange(0.0, 0.0); // from the image to have constant color

    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
    append_filter->AddInputConnection(frustum_texture->GetOutputPort());
    append_filter->AddInputConnection(plane->GetProducerPort());

    vtkSmartPointer<vtkActor> actor = getActor(image_widget);
    actor->GetMapper()->SetInputConnection(append_filter->GetOutputPort());
899 900 901
    WidgetAccessor::setProp(*this, actor);
}

902
template<> cv::viz::WCameraPosition cv::viz::Widget::cast<cv::viz::WCameraPosition>()
903 904
{
    Widget3D widget = this->cast<Widget3D>();
905
    return static_cast<WCameraPosition&>(widget);
906 907
}

908 909 910
///////////////////////////////////////////////////////////////////////////////////////////////
/// trajectory widget implementation

911
cv::viz::WTrajectory::WTrajectory(InputArray _path, int display_mode, double scale, const Color &color)
912
{
913
    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
914

915
    // Bitwise and with 3 in order to limit the domain to 2 bits
916
    if (display_mode & WTrajectory::PATH)
917
    {
918 919
        Mat points = vtkTrajectorySource::ExtractPoints(_path);
        vtkSmartPointer<vtkPolyData> polydata = getPolyData(WPolyLine(points, color));
920
        append_filter->AddInputConnection(polydata->GetProducerPort());
921
    }
Ozan Tonkal's avatar
Ozan Tonkal committed
922

923
    if (display_mode & WTrajectory::FRAMES)
924
    {
925 926
        vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
        source->SetTrajectory(_path);
Ozan Tonkal's avatar
Ozan Tonkal committed
927

928 929
        vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCoordinateSystem(scale));

930
        vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
931 932 933 934 935 936
        tensor_glyph->SetInputConnection(source->GetOutputPort());
        tensor_glyph->SetSourceConnection(glyph->GetProducerPort());
        tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
        tensor_glyph->ThreeGlyphsOff();
        tensor_glyph->SymmetricOff();
        tensor_glyph->ColorGlyphsOff();
Ozan Tonkal's avatar
Ozan Tonkal committed
937

938
        append_filter->AddInputConnection(tensor_glyph->GetOutputPort());
939
    }
940
    append_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
941

942
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
943
    VtkUtils::SetInputData(mapper, append_filter->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
944
    mapper->SetScalarModeToUsePointData();
945
    mapper->SetScalarRange(0, 255);
Ozan Tonkal's avatar
Ozan Tonkal committed
946

947 948
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
949

950 951 952
    WidgetAccessor::setProp(*this, actor);
}

953 954 955 956 957 958 959 960 961
template<> cv::viz::WTrajectory cv::viz::Widget::cast<cv::viz::WTrajectory>()
{
    Widget3D widget = this->cast<Widget3D>();
    return static_cast<WTrajectory&>(widget);
}

///////////////////////////////////////////////////////////////////////////////////////////////
/// WTrajectoryFrustums widget implementation

962
cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Matx33d &K, double scale, const Color &color)
Ozan Tonkal's avatar
Ozan Tonkal committed
963
{
964 965
    vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
    source->SetTrajectory(_path);
Ozan Tonkal's avatar
Ozan Tonkal committed
966

967
    vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(K, scale));
Ozan Tonkal's avatar
Ozan Tonkal committed
968

969 970 971 972 973 974 975 976
    vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
    tensor_glyph->SetInputConnection(source->GetOutputPort());
    tensor_glyph->SetSourceConnection(glyph->GetProducerPort());
    tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
    tensor_glyph->ThreeGlyphsOff();
    tensor_glyph->SymmetricOff();
    tensor_glyph->ColorGlyphsOff();
    tensor_glyph->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
977

978
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
979
    VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
980

981 982
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
983

984 985 986 987
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}

988
cv::viz::WTrajectoryFrustums::WTrajectoryFrustums(InputArray _path, const Vec2d &fov, double scale, const Color &color)
989
{
990 991
    vtkSmartPointer<vtkTrajectorySource> source = vtkSmartPointer<vtkTrajectorySource>::New();
    source->SetTrajectory(_path);
Ozan Tonkal's avatar
Ozan Tonkal committed
992

993
    vtkSmartPointer<vtkPolyData> glyph = getPolyData(WCameraPosition(fov, scale));
Ozan Tonkal's avatar
Ozan Tonkal committed
994

995 996 997 998 999 1000 1001 1002
    vtkSmartPointer<vtkTensorGlyph> tensor_glyph = vtkSmartPointer<vtkTensorGlyph>::New();
    tensor_glyph->SetInputConnection(source->GetOutputPort());
    tensor_glyph->SetSourceConnection(glyph->GetProducerPort());
    tensor_glyph->ExtractEigenvaluesOff();  // Treat as a rotation matrix, not as something with eigenvalues
    tensor_glyph->ThreeGlyphsOff();
    tensor_glyph->SymmetricOff();
    tensor_glyph->ColorGlyphsOff();
    tensor_glyph->Update();
1003

1004
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
1005
    VtkUtils::SetInputData(mapper, tensor_glyph->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
1006

1007 1008
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1009

1010 1011 1012
    WidgetAccessor::setProp(*this, actor);
    setColor(color);
}
1013

1014
template<> cv::viz::WTrajectoryFrustums cv::viz::Widget::cast<cv::viz::WTrajectoryFrustums>()
1015 1016
{
    Widget3D widget = this->cast<Widget3D>();
1017
    return static_cast<WTrajectoryFrustums&>(widget);
1018 1019 1020
}

///////////////////////////////////////////////////////////////////////////////////////////////
1021
/// WTrajectorySpheres widget implementation
1022

1023
cv::viz::WTrajectorySpheres::WTrajectorySpheres(InputArray _path, double line_length, double radius, const Color &from, const Color &to)
1024
{
1025 1026
    CV_Assert(_path.kind() == _InputArray::STD_VECTOR || _path.kind() == _InputArray::MAT);
    CV_Assert(_path.type() == CV_32FC(16) || _path.type() == CV_64FC(16));
Anatoly Baksheev's avatar
Anatoly Baksheev committed
1027

1028 1029 1030 1031
    Mat path64;
    _path.getMat().convertTo(path64, CV_64F);
    Affine3d *traj = path64.ptr<Affine3d>();
    size_t total = path64.total();
Anatoly Baksheev's avatar
Anatoly Baksheev committed
1032

1033
    vtkSmartPointer<vtkAppendPolyData> append_filter = vtkSmartPointer<vtkAppendPolyData>::New();
Ozan Tonkal's avatar
Ozan Tonkal committed
1034

1035
    for(size_t i = 0; i < total; ++i)
1036
    {
1037
        Vec3d curr = traj[i].translation();
Ozan Tonkal's avatar
Ozan Tonkal committed
1038

1039
        vtkSmartPointer<vtkSphereSource> sphere_source = vtkSmartPointer<vtkSphereSource>::New();
1040 1041 1042 1043 1044 1045
        sphere_source->SetCenter(curr.val);
        sphere_source->SetRadius( (i == 0) ? 2 * radius : radius );
        sphere_source->Update();

        double alpha = static_cast<double>(i)/total;
        Color c = from * (1 - alpha) + to * alpha;
Ozan Tonkal's avatar
Ozan Tonkal committed
1046

1047 1048 1049
        vtkSmartPointer<vtkPolyData> polydata = sphere_source->GetOutput();
        polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c));
        append_filter->AddInputConnection(polydata->GetProducerPort());
Ozan Tonkal's avatar
Ozan Tonkal committed
1050

1051 1052 1053 1054 1055 1056 1057
        if (i > 0)
        {
            Vec3d prev = traj[i-1].translation();
            Vec3d lvec = prev - curr;

            if(norm(lvec) > line_length)
                lvec = normalize(lvec) * line_length;
Ozan Tonkal's avatar
Ozan Tonkal committed
1058

1059
            Vec3d lend = curr + lvec;
Ozan Tonkal's avatar
Ozan Tonkal committed
1060

1061 1062 1063 1064 1065 1066 1067 1068
            vtkSmartPointer<vtkLineSource> line_source = vtkSmartPointer<vtkLineSource>::New();
            line_source->SetPoint1(curr.val);
            line_source->SetPoint2(lend.val);
            line_source->Update();
            vtkSmartPointer<vtkPolyData> polydata = line_source->GetOutput();
            polydata->GetCellData()->SetScalars(VtkUtils::FillScalars(polydata->GetNumberOfCells(), c));
            append_filter->AddInputConnection(polydata->GetProducerPort());
        }
1069
    }
1070
    append_filter->Update();
Ozan Tonkal's avatar
Ozan Tonkal committed
1071

1072 1073
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetScalarModeToUseCellData();
1074
    VtkUtils::SetInputData(mapper, append_filter->GetOutput());
Ozan Tonkal's avatar
Ozan Tonkal committed
1075

1076 1077
    vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
Ozan Tonkal's avatar
Ozan Tonkal committed
1078

1079 1080 1081
    WidgetAccessor::setProp(*this, actor);
}

1082
template<> cv::viz::WTrajectorySpheres cv::viz::Widget::cast<cv::viz::WTrajectorySpheres>()
1083 1084
{
    Widget3D widget = this->cast<Widget3D>();
1085
    return static_cast<WTrajectorySpheres&>(widget);
Ozan Tonkal's avatar
Ozan Tonkal committed
1086
}