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