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@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
WLine(const Point3d & pt1,const Point3d & pt2,const Color & color)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
cast()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
WSphere(const Point3d & center,double radius,int sphere_resolution,const Color & color)78 cv::viz::WSphere::WSphere(const Point3d ¢er, 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
cast()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
WPlane(const Size2d & size,const Color & color)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
WPlane(const Point3d & center,const Vec3d & normal,const Vec3d & new_yaxis,const Size2d & size,const Color & color)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
cast()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
WArrow(const Point3d & pt1,const Point3d & pt2,double thickness,const Color & color)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
cast()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
WCircle(double radius,double thickness,const Color & color)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
WCircle(double radius,const Point3d & center,const Vec3d & normal,double thickness,const Color & color)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
cast()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
WCone(double length,double radius,int resolution,const Color & color)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
WCone(double radius,const Point3d & center,const Point3d & tip,int resolution,const Color & color)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
cast()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
WCylinder(const Point3d & axis_point1,const Point3d & axis_point2,double radius,int numsides,const Color & color)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
cast()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
WCube(const Point3d & min_point,const Point3d & max_point,bool wire_frame,const Color & color)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
cast()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
WCoordinateSystem(double scale)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
cast()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
WPolyLine(InputArray points,InputArray colors)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
WPolyLine(InputArray points,const Color & color)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
cast()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
WGrid(const Vec2i & cells,const Vec2d & cells_spacing,const Color & color)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
WGrid(const Point3d & center,const Vec3d & normal,const Vec3d & new_yaxis,const Vec2i & cells,const Vec2d & cells_spacing,const Color & color)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
cast()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
WText3D(const String & text,const Point3d & position,double text_scale,bool face_camera,const Color & color)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
setText(const String & text)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
getText() const529 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
cast()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
WText(const String & text,const Point & pos,int font_size,const Color & color)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
cast()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
setText(const String & text)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
getText() const583 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
WImageOverlay(InputArray image,const Rect & rect)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
setImage(InputArray image)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
cast()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
WImage3D(InputArray image,const Size2d & size)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
WImage3D(InputArray image,const Size2d & size,const Vec3d & center,const Vec3d & normal,const Vec3d & up_vector)700 cv::viz::WImage3D::WImage3D(InputArray image, const Size2d &size, const Vec3d ¢er, 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
setImage(InputArray image)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
cast()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 {
createFrustumcv::viz::__anonf0f343060111::CameraPositionUtils744 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
ensureColorImagecv::viz::__anonf0f343060111::CameraPositionUtils769 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
WCameraPosition(double scale)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
WCameraPosition(const Matx33d & K,double scale,const Color & color)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
WCameraPosition(const Vec2d & fov,double scale,const Color & color)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
WCameraPosition(const Matx33d & K,InputArray _image,double scale,const Color & color)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
WCameraPosition(const Vec2d & fov,InputArray _image,double scale,const Color & color)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
cast()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
WTrajectory(InputArray _path,int display_mode,double scale,const Color & color)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
cast()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
WTrajectoryFrustums(InputArray _path,const Matx33d & K,double scale,const Color & color)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
WTrajectoryFrustums(InputArray _path,const Vec2d & fov,double scale,const Color & color)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
cast()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
WTrajectorySpheres(InputArray _path,double line_length,double radius,const Color & from,const Color & to)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
cast()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