/*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*/ #include "precomp.hpp" /////////////////////////////////////////////////////////////////////////////////////////////// /// Point Cloud Widget implementation cv::viz::WCloud::WCloud(InputArray cloud, InputArray colors) { CV_Assert(!cloud.empty() && !colors.empty()); vtkSmartPointer cloud_source = vtkSmartPointer::New(); cloud_source->SetColorCloud(cloud, colors); cloud_source->Update(); vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, cloud_source->GetOutput()); mapper->SetScalarModeToUsePointData(); mapper->ImmediateModeRenderingOff(); mapper->SetScalarRange(0, 255); mapper->ScalarVisibilityOn(); vtkSmartPointer actor = vtkSmartPointer::New(); actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->BackfaceCullingOn(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); } cv::viz::WCloud::WCloud(InputArray cloud, const Color &color) { vtkSmartPointer cloud_source = vtkSmartPointer::New(); cloud_source->SetCloud(cloud); cloud_source->Update(); vtkSmartPointer mapper = vtkSmartPointer::New(); VtkUtils::SetInputData(mapper, cloud_source->GetOutput()); mapper->ImmediateModeRenderingOff(); mapper->ScalarVisibilityOff(); vtkSmartPointer actor = vtkSmartPointer::New(); actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->BackfaceCullingOn(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); setColor(color); } template<> cv::viz::WCloud cv::viz::Widget::cast() { Widget3D widget = this->cast(); return static_cast(widget); } /////////////////////////////////////////////////////////////////////////////////////////////// /// Cloud Collection Widget implementation cv::viz::WCloudCollection::WCloudCollection() { // Just create the actor vtkSmartPointer actor = vtkSmartPointer::New(); WidgetAccessor::setProp(*this, actor); } void cv::viz::WCloudCollection::addCloud(InputArray cloud, InputArray colors, const Affine3d &pose) { vtkSmartPointer source = vtkSmartPointer::New(); source->SetColorCloud(cloud, colors); vtkSmartPointer transform = vtkSmartPointer::New(); transform->SetMatrix(pose.matrix.val); vtkSmartPointer transform_filter = vtkSmartPointer::New(); transform_filter->SetInputConnection(source->GetOutputPort()); transform_filter->SetTransform(transform); transform_filter->Update(); vtkSmartPointer polydata = transform_filter->GetOutput(); vtkSmartPointer actor = vtkLODActor::SafeDownCast(WidgetAccessor::getProp(*this)); CV_Assert("Incompatible widget type." && actor); vtkSmartPointer mapper = vtkPolyDataMapper::SafeDownCast(actor->GetMapper()); if (!mapper) { // This is the first cloud mapper = vtkSmartPointer::New(); mapper->SetScalarRange(0, 255); mapper->SetScalarModeToUsePointData(); mapper->ScalarVisibilityOn(); mapper->ImmediateModeRenderingOff(); VtkUtils::SetInputData(mapper, polydata); actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints()/10)); actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->BackfaceCullingOn(); actor->SetMapper(mapper); return; } vtkPolyData *currdata = vtkPolyData::SafeDownCast(mapper->GetInput()); CV_Assert("Cloud Widget without data" && currdata); vtkSmartPointer append_filter = vtkSmartPointer::New(); append_filter->AddInputConnection(currdata->GetProducerPort()); append_filter->AddInputConnection(polydata->GetProducerPort()); append_filter->Update(); VtkUtils::SetInputData(mapper, append_filter->GetOutput()); actor->SetNumberOfCloudPoints(std::max(1, actor->GetNumberOfCloudPoints() + polydata->GetNumberOfPoints()/10)); } void cv::viz::WCloudCollection::addCloud(InputArray cloud, const Color &color, const Affine3d &pose) { addCloud(cloud, Mat(cloud.size(), CV_8UC3, color), pose); } template<> cv::viz::WCloudCollection cv::viz::Widget::cast() { Widget3D widget = this->cast(); return static_cast(widget); } /////////////////////////////////////////////////////////////////////////////////////////////// /// Cloud Normals Widget implementation cv::viz::WCloudNormals::WCloudNormals(InputArray _cloud, InputArray _normals, int level, double scale, const Color &color) { Mat cloud = _cloud.getMat(); Mat normals = _normals.getMat(); CV_Assert(cloud.type() == CV_32FC3 || cloud.type() == CV_64FC3 || cloud.type() == CV_32FC4 || cloud.type() == CV_64FC4); CV_Assert(cloud.size() == normals.size() && cloud.type() == normals.type()); int sqlevel = (int)std::sqrt((double)level); int ystep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : 1; int xstep = (cloud.cols > 1 && cloud.rows > 1) ? sqlevel : level; vtkSmartPointer points = vtkSmartPointer::New(); points->SetDataType(cloud.depth() == CV_32F ? VTK_FLOAT : VTK_DOUBLE); vtkSmartPointer lines = vtkSmartPointer::New(); int s_chs = cloud.channels(); int n_chs = normals.channels(); int total = 0; for(int y = 0; y < cloud.rows; y += ystep) { if (cloud.depth() == CV_32F) { const float *srow = cloud.ptr(y); const float *send = srow + cloud.cols * s_chs; const float *nrow = normals.ptr(y); for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) if (!isNan(srow) && !isNan(nrow)) { Vec3f endp = Vec3f(srow) + Vec3f(nrow) * (float)scale; points->InsertNextPoint(srow); points->InsertNextPoint(endp.val); lines->InsertNextCell(2); lines->InsertCellPoint(total++); lines->InsertCellPoint(total++); } } else { const double *srow = cloud.ptr(y); const double *send = srow + cloud.cols * s_chs; const double *nrow = normals.ptr(y); for (; srow < send; srow += xstep * s_chs, nrow += xstep * n_chs) if (!isNan(srow) && !isNan(nrow)) { Vec3d endp = Vec3d(srow) + Vec3d(nrow) * (double)scale; points->InsertNextPoint(srow); points->InsertNextPoint(endp.val); lines->InsertNextCell(2); lines->InsertCellPoint(total++); lines->InsertCellPoint(total++); } } } vtkSmartPointer polyData = vtkSmartPointer::New(); polyData->SetPoints(points); polyData->SetLines(lines); vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetColorModeToMapScalars(); mapper->SetScalarModeToUsePointData(); VtkUtils::SetInputData(mapper, polyData); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); setColor(color); } template<> cv::viz::WCloudNormals cv::viz::Widget::cast() { Widget3D widget = this->cast(); return static_cast(widget); } /////////////////////////////////////////////////////////////////////////////////////////////// /// Mesh Widget implementation cv::viz::WMesh::WMesh(const Mesh3d &mesh) { CV_Assert(mesh.cloud.rows == 1 && mesh.polygons.type() == CV_32SC1); vtkSmartPointer source = vtkSmartPointer::New(); source->SetColorCloud(mesh.cloud, mesh.colors); source->Update(); Mat lookup_buffer(1, mesh.cloud.total(), CV_32SC1); int *lookup = lookup_buffer.ptr(); for(int y = 0, index = 0; y < mesh.cloud.rows; ++y) { int s_chs = mesh.cloud.channels(); if (mesh.cloud.depth() == CV_32F) { const float* srow = mesh.cloud.ptr(y); const float* send = srow + mesh.cloud.cols * s_chs; for (; srow != send; srow += s_chs, ++lookup) if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) *lookup = index++; } if (mesh.cloud.depth() == CV_64F) { const double* srow = mesh.cloud.ptr(y); const double* send = srow + mesh.cloud.cols * s_chs; for (; srow != send; srow += s_chs, ++lookup) if (!isNan(srow[0]) && !isNan(srow[1]) && !isNan(srow[2])) *lookup = index++; } } lookup = lookup_buffer.ptr(); vtkSmartPointer polydata = source->GetOutput(); polydata->SetVerts(0); const int * polygons = mesh.polygons.ptr(); vtkSmartPointer cell_array = vtkSmartPointer::New(); int idx = 0; int poly_size = mesh.polygons.total(); for (int i = 0; i < poly_size; ++idx) { int n_points = polygons[i++]; cell_array->InsertNextCell(n_points); for (int j = 0; j < n_points; ++j, ++idx) cell_array->InsertCellPoint(lookup[polygons[i++]]); } cell_array->GetData()->SetNumberOfValues(idx); cell_array->Squeeze(); polydata->SetStrips(cell_array); vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetScalarModeToUsePointData(); mapper->ImmediateModeRenderingOff(); VtkUtils::SetInputData(mapper, polydata); vtkSmartPointer actor = vtkSmartPointer::New(); //actor->SetNumberOfCloudPoints(std::max(1, polydata->GetNumberOfPoints() / 10)); actor->GetProperty()->SetRepresentationToSurface(); actor->GetProperty()->BackfaceCullingOff(); // Backface culling is off for higher efficiency actor->GetProperty()->SetInterpolationToFlat(); actor->GetProperty()->EdgeVisibilityOff(); actor->GetProperty()->ShadingOff(); actor->SetMapper(mapper); WidgetAccessor::setProp(*this, actor); } template<> CV_EXPORTS cv::viz::WMesh cv::viz::Widget::cast() { Widget3D widget = this->cast(); return static_cast(widget); }