PointViewSet LocateFilter::run(PointViewPtr inView) { PointViewSet viewSet; if (!inView->size()) return viewSet; PointId minidx, maxidx; double minval = (std::numeric_limits<double>::max)(); double maxval = std::numeric_limits<double>::lowest(); for (PointId idx = 0; idx < inView->size(); idx++) { double val = inView->getFieldAs<double>(m_dimId, idx); if (val > maxval) { maxval = val; maxidx = idx; } if (val < minval) { minval = val; minidx = idx; } } PointViewPtr outView = inView->makeNew(); if (Utils::iequals("min", m_minmax)) outView->appendPoint(*inView.get(), minidx); if (Utils::iequals("max", m_minmax)) outView->appendPoint(*inView.get(), maxidx); viewSet.insert(outView); return viewSet; }
virtual PointViewSet run(PointViewPtr view) { PointViewSet out; PointViewPtr v = view->makeNew(); for (PointId i = 0; i < view->size(); ++i) { if (i && (i % m_viewSize == 0)) { out.insert(v); v = v->makeNew(); } v->appendPoint(*view, i); } out.insert(v); return out; }
PointViewSet PredicateFilter::run(PointViewPtr view) { MetadataNode n; m_pythonMethod->resetArguments(); m_pythonMethod->begin(*view, n); m_pythonMethod->execute(); if (!m_pythonMethod->hasOutputVariable("Mask")) throw pdal::pdal_error("Mask variable not set in predicate " "filter function."); PointViewPtr outview = view->makeNew(); void *pydata = m_pythonMethod->extractResult("Mask", Dimension::Type::Unsigned8); char *ok = (char *)pydata; for (PointId idx = 0; idx < view->size(); ++idx) if (*ok++) outview->appendPoint(*view, idx); PointViewSet viewSet; viewSet.insert(outview); return viewSet; }
PointViewSet DecimationFilter::run(PointViewPtr inView) { PointViewSet viewSet; PointViewPtr outView = inView->makeNew(); decimate(*inView.get(), *outView.get()); viewSet.insert(outView); return viewSet; }
MetadataNode InfoKernel::dumpQuery(PointViewPtr inView) const { int count; std::string location; // See if there's a provided point count. StringList parts = Utils::split2(m_queryPoint, '/'); if (parts.size() == 2) { location = parts[0]; count = atoi(parts[1].c_str()); } else if (parts.size() == 1) { location = parts[0]; count = inView->size(); } else count = 0; if (count == 0) throw pdal_error("Invalid location specificiation. " "--query=\"X,Y[/count]\""); auto seps = [](char c){ return (c == ',' || c == '|' || c == ' '); }; std::vector<std::string> tokens = Utils::split2(location, seps); std::vector<double> values; for (auto ti = tokens.begin(); ti != tokens.end(); ++ti) { double d; if (Utils::fromString(*ti, d)) values.push_back(d); } if (values.size() != 2 && values.size() != 3) throw pdal_error("--points must be two or three values"); PointViewPtr outView = inView->makeNew(); std::vector<PointId> ids; if (values.size() >= 3) { KD3Index kdi(*inView); kdi.build(); ids = kdi.neighbors(values[0], values[1], values[2], count); } else { KD2Index kdi(*inView); kdi.build(); ids = kdi.neighbors(values[0], values[1], count); } for (auto i = ids.begin(); i != ids.end(); ++i) outView->appendPoint(*inView.get(), *i); return outView->toMetadata(); }
PointViewSet PMFFilter::run(PointViewPtr input) { bool logOutput = log()->getLevel() > LogLevel::Debug1; if (logOutput) log()->floatPrecision(8); log()->get(LogLevel::Debug2) << "Process PMFFilter...\n"; auto idx = processGround(input); PointViewSet viewSet; if (!idx.empty() && (m_classify || m_extract)) { if (m_classify) { log()->get(LogLevel::Debug2) << "Labeled " << idx.size() << " ground returns!\n"; // set the classification label of ground returns as 2 // (corresponding to ASPRS LAS specification) for (const auto& i : idx) { input->setField(Dimension::Id::Classification, i, 2); } viewSet.insert(input); } if (m_extract) { log()->get(LogLevel::Debug2) << "Extracted " << idx.size() << " ground returns!\n"; // create new PointView containing only ground returns PointViewPtr output = input->makeNew(); for (const auto& i : idx) { output->appendPoint(*input, i); } viewSet.erase(input); viewSet.insert(output); } } else { if (idx.empty()) log()->get(LogLevel::Debug2) << "Filtered cloud has no ground returns!\n"; if (!(m_classify || m_extract)) log()->get(LogLevel::Debug2) << "Must choose --classify or --extract\n"; // return the input buffer unchanged viewSet.insert(input); } return viewSet; }
PointViewSet SMRFilter::run(PointViewPtr view) { log()->get(LogLevel::Info) << "run: Process SMRFilter...\n"; std::vector<PointId> idx = processGround(view); PointViewSet viewSet; if (!idx.empty() && (m_classify || m_extract)) { if (m_classify) { log()->get(LogLevel::Info) << "run: Labeled " << idx.size() << " ground returns!\n"; // set the classification label of ground returns as 2 // (corresponding to ASPRS LAS specification) for (const auto& i : idx) { view->setField(Dimension::Id::Classification, i, 2); } viewSet.insert(view); } if (m_extract) { log()->get(LogLevel::Info) << "run: Extracted " << idx.size() << " ground returns!\n"; // create new PointView containing only ground returns PointViewPtr output = view->makeNew(); for (const auto& i : idx) { output->appendPoint(*view, i); } viewSet.erase(view); viewSet.insert(output); } } else { if (idx.empty()) log()->get(LogLevel::Info) << "run: Filtered cloud has no ground returns!\n"; if (!(m_classify || m_extract)) log()->get(LogLevel::Info) << "run: Must choose --classify or --extract\n"; // return the view buffer unchanged viewSet.insert(view); } return viewSet; }
PointViewSet run(PointViewPtr view) { if (m_count > view->size()) log()->get(LogLevel::Warning) << "Requested number of points (count=" << m_count << ") exceeds number of available points.\n"; PointViewSet viewSet; PointViewPtr outView = view->makeNew(); for (PointId i = view->size() - std::min(m_count, view->size()); i < view->size(); ++i) outView->appendPoint(*view, i); viewSet.insert(outView); return viewSet; }
PointViewSet VoxelGridFilter::run(PointViewPtr input) { PointViewPtr output = input->makeNew(); PointViewSet viewSet; viewSet.insert(output); bool logOutput = log()->getLevel() > LogLevel::Debug1; if (logOutput) log()->floatPrecision(8); log()->get(LogLevel::Debug2) << "Process VoxelGridFilter..." << std::endl; BOX3D buffer_bounds; input->calculateBounds(buffer_bounds); // convert PointView to PointNormal typedef pcl::PointCloud<pcl::PointXYZ> Cloud; Cloud::Ptr cloud(new Cloud); pclsupport::PDALtoPCD(input, *cloud, buffer_bounds); pclsupport::setLogLevel(log()->getLevel()); // initial setup pcl::VoxelGrid<pcl::PointXYZ> vg; vg.setInputCloud(cloud); vg.setLeafSize(m_leaf_x, m_leaf_y, m_leaf_z); // create PointCloud for results Cloud::Ptr cloud_f(new Cloud); vg.filter(*cloud_f); if (cloud_f->points.empty()) { log()->get(LogLevel::Debug2) << "Filtered cloud has no points!" << std::endl; return viewSet; } pclsupport::PCDtoPDAL(*cloud_f, output, buffer_bounds); log()->get(LogLevel::Debug2) << cloud->points.size() << " before, " << cloud_f->points.size() << " after" << std::endl; log()->get(LogLevel::Debug2) << output->size() << std::endl; return viewSet; }
PointViewSet SampleFilter::run(PointViewPtr inView) { point_count_t np = inView->size(); // Return empty PointViewSet if the input PointView has no points. // Otherwise, make a new output PointView. PointViewSet viewSet; if (!np) return viewSet; PointViewPtr outView = inView->makeNew(); // Build the 3D KD-tree. KD3Index index(*inView); index.build(); // All points are marked as kept (1) by default. As they are masked by // neighbors within the user-specified radius, their value is changed to 0. std::vector<int> keep(np, 1); // We are able to subsample in a single pass over the shuffled indices. for (PointId i = 0; i < np; ++i) { // If a point is masked, it is forever masked, and cannot be part of the // sampled cloud. Otherwise, the current index is appended to the output // PointView. if (keep[i] == 0) continue; outView->appendPoint(*inView, i); // We now proceed to mask all neighbors within m_radius of the kept // point. auto ids = index.radius(i, m_radius); for (auto const& id : ids) keep[id] = 0; } // Simply calculate the percentage of retained points. double frac = (double)outView->size() / (double)inView->size(); log()->get(LogLevel::Debug2) << "Retaining " << outView->size() << " of " << inView->size() << " points (" << 100 * frac << "%)\n"; viewSet.insert(outView); return viewSet; }
PointViewSet RangeFilter::run(PointViewPtr inView) { PointViewSet viewSet; if (!inView->size()) return viewSet; PointViewPtr outView = inView->makeNew(); for (PointId i = 0; i < inView->size(); ++i) { PointRef point = inView->point(i); if (processOne(point)) outView->appendPoint(*inView, i); } viewSet.insert(outView); return viewSet; }
PointViewSet MADFilter::run(PointViewPtr view) { using namespace Dimension; PointViewSet viewSet; PointViewPtr output = view->makeNew(); auto estimate_median = [](std::vector<double> vals) { std::nth_element(vals.begin(), vals.begin()+vals.size()/2, vals.end()); return *(vals.begin()+vals.size()/2); }; std::vector<double> z(view->size()); for (PointId j = 0; j < view->size(); ++j) z[j] = view->getFieldAs<double>(m_dimId, j); double median = estimate_median(z); log()->get(LogLevel::Debug) << getName() << " estimated median value: " << median << std::endl; std::transform(z.begin(), z.end(), z.begin(), [median](double v) { return std::fabs(v - median); }); double mad = estimate_median(z)*m_madMultiplier; log()->get(LogLevel::Debug) << getName() << " mad " << mad << std::endl; for (PointId j = 0; j < view->size(); ++j) { if (z[j]/mad < m_multiplier) output->appendPoint(*view, j); } double low_fence = median - m_multiplier * mad; double hi_fence = median + m_multiplier * mad; log()->get(LogLevel::Debug) << getName() << " cropping " << m_dimName << " in the range (" << low_fence << "," << hi_fence << ")" << std::endl; viewSet.erase(view); viewSet.insert(output); return viewSet; }
PointViewSet SplitterFilter::run(PointViewPtr inView) { PointViewSet viewSet; if (!inView->size()) return viewSet; // Use the location of the first point as the origin, unless specified. // (!= test == isnan(), which doesn't exist on windows) if (m_xOrigin != m_xOrigin) m_xOrigin = inView->getFieldAs<double>(Dimension::Id::X, 0); if (m_yOrigin != m_yOrigin) m_yOrigin = inView->getFieldAs<double>(Dimension::Id::Y, 0); // Overlay a grid of squares on the points (m_length sides). Each square // corresponds to a new point buffer. Place the points falling in the // each square in the corresponding point buffer. for (PointId idx = 0; idx < inView->size(); idx++) { double x = inView->getFieldAs<double>(Dimension::Id::X, idx); x -= m_xOrigin; int xpos = x / m_length; if (x < 0) xpos--; double y = inView->getFieldAs<double>(Dimension::Id::Y, idx); y -= m_yOrigin; int ypos = y / m_length; if (y < 0) ypos--; Coord loc(xpos, ypos); PointViewPtr& outView = m_viewMap[loc]; if (!outView) outView = inView->makeNew(); outView->appendPoint(*inView.get(), idx); } // Pull the buffers out of the map and stick them in the standard // output set. for (auto bi = m_viewMap.begin(); bi != m_viewMap.end(); ++bi) viewSet.insert(bi->second); return viewSet; }
PointViewSet GroupByFilter::run(PointViewPtr inView) { PointViewSet viewSet; if (!inView->size()) return viewSet; for (PointId idx = 0; idx < inView->size(); idx++) { uint64_t val = inView->getFieldAs<uint64_t>(m_dimId, idx); PointViewPtr& outView = m_viewMap[val]; if (!outView) outView = inView->makeNew(); outView->appendPoint(*inView.get(), idx); } // Pull the buffers out of the map and stick them in the standard // output set. for (auto bi = m_viewMap.begin(); bi != m_viewMap.end(); ++bi) viewSet.insert(bi->second); return viewSet; }
TEST(LasReaderTest, test_sequential) { PointTable table; Options ops1; ops1.add("filename", Support::datapath("las/1.2-with-color.las")); ops1.add("count", 103); LasReader reader; reader.setOptions(ops1); reader.prepare(table); PointViewSet viewSet = reader.execute(table); EXPECT_EQ(viewSet.size(), 1u); PointViewPtr view = *viewSet.begin(); Support::check_p0_p1_p2(*view); PointViewPtr view2 = view->makeNew(); view2->appendPoint(*view, 100); view2->appendPoint(*view, 101); view2->appendPoint(*view, 102); Support::check_p100_p101_p102(*view2); }
MetadataNode InfoKernel::dumpPoints(PointViewPtr inView) const { MetadataNode root; PointViewPtr outView = inView->makeNew(); // Stick points in a inViewfer. std::vector<PointId> points = getListOfPoints(m_pointIndexes); for (size_t i = 0; i < points.size(); ++i) { PointId id = (PointId)points[i]; if (id < inView->size()) outView->appendPoint(*inView.get(), id); } MetadataNode tree = outView->toMetadata(); std::string prefix("point "); for (size_t i = 0; i < outView->size(); ++i) { MetadataNode n = tree.findChild(std::to_string(i)); n.add("PointId", points[i]); root.add(n.clone("point")); } return root; }
void RialtoReader::doQuery(const TileMath& tmm, const GpkgTile& tile, PointViewPtr view, double qMinX, double qMinY, double qMaxX, double qMaxY) { const uint32_t level = tile.getLevel(); const uint32_t column = tile.getColumn(); const uint32_t row = tile.getRow(); const uint32_t numPoints = tile.getNumPoints(); // if this tile is entirely inside the query box, then // we won't need to check each point double tileMinX, tileMinY, tileMaxX, tileMaxY; tmm.getTileBounds(column, row, level, tileMinX, tileMinY, tileMaxX, tileMaxY); const bool tileEntirelyInsideQueryBox = tmm.rectContainsRect(qMinX, qMinY, qMaxX, qMaxY, tileMinX, tileMinY, tileMaxX, tileMaxY); log()->get(LogLevel::Debug) << " intersecting tile " << "(" << level << "," << column << "," << row << ")" << " contains " << numPoints << " points" << std::endl; PointViewPtr tempView = view->makeNew(); GpkgTile::exportToPV(numPoints, tempView, tile.getBlob()); for (uint32_t i=0; i<tempView->size(); i++) { const double x = tempView->getFieldAs<double>(Dimension::Id::X, i); const double y = tempView->getFieldAs<double>(Dimension::Id::Y, i); if (tileEntirelyInsideQueryBox || (x >= qMinX && x <= qMaxX && y >= qMinY && y <= qMaxY)) { view->appendPoint(*tempView, i); } } }
PointViewSet RadiusOutlierFilter::run(PointViewPtr input) { bool logOutput = log()->getLevel() > LogLevel::Debug1; if (logOutput) log()->floatPrecision(8); log()->get(LogLevel::Debug2) << "Process RadiusOutlierFilter...\n"; // convert PointView to PointXYZ typedef pcl::PointCloud<pcl::PointXYZ> Cloud; Cloud::Ptr cloud(new Cloud); BOX3D bounds; input->calculateBounds(bounds); pclsupport::PDALtoPCD(input, *cloud, bounds); pclsupport::setLogLevel(log()->getLevel()); // setup the outlier filter pcl::RadiusOutlierRemoval<pcl::PointXYZ> ror(true); ror.setInputCloud(cloud); ror.setMinNeighborsInRadius(m_min_neighbors); ror.setRadiusSearch(m_radius); pcl::PointCloud<pcl::PointXYZ> output; ror.setNegative(true); ror.filter(output); // filtered to return inliers pcl::PointIndicesPtr inliers(new pcl::PointIndices); ror.getRemovedIndices(*inliers); PointViewSet viewSet; if (inliers->indices.empty()) { log()->get(LogLevel::Warning) << "Requested filter would remove all points. Try a larger radius/smaller minimum neighbors.\n"; viewSet.insert(input); return viewSet; } // inverse are the outliers std::vector<int> outliers(input->size()-inliers->indices.size()); for (PointId i = 0, j = 0, k = 0; i < input->size(); ++i) { if (i == (PointId)inliers->indices[j]) { j++; continue; } outliers[k++] = i; } if (!outliers.empty() && (m_classify || m_extract)) { if (m_classify) { log()->get(LogLevel::Debug2) << "Labeled " << outliers.size() << " outliers as noise!\n"; // set the classification label of outlier returns as 18 // (corresponding to ASPRS LAS specification for high noise) for (const auto& i : outliers) { input->setField(Dimension::Id::Classification, i, 18); } viewSet.insert(input); } if (m_extract) { log()->get(LogLevel::Debug2) << "Extracted " << inliers->indices.size() << " inliers!\n"; // create new PointView containing only outliers PointViewPtr output = input->makeNew(); for (const auto& i : inliers->indices) { output->appendPoint(*input, i); } viewSet.erase(input); viewSet.insert(output); } } else { if (outliers.empty()) log()->get(LogLevel::Warning) << "Filtered cloud has no outliers!\n"; if (!(m_classify || m_extract)) log()->get(LogLevel::Warning) << "Must choose --classify or --extract\n"; // return the input buffer unchanged viewSet.insert(input); } return viewSet; }
std::vector<PointId> PMFFilter::processGround(PointViewPtr view) { point_count_t np(view->size()); // Compute the series of window sizes and height thresholds std::vector<float> height_thresholds; std::vector<float> window_sizes; int iteration = 0; float window_size = 0.0f; float height_threshold = 0.0f; while (window_size < m_maxWindowSize) { // Determine the initial window size. if (1) // exponential window_size = m_cellSize * (2.0f * std::pow(2, iteration) + 1.0f); else window_size = m_cellSize * (2.0f * (iteration+1) * 2 + 1.0f); // Calculate the height threshold to be used in the next iteration. if (iteration == 0) height_threshold = m_initialDistance; else height_threshold = m_slope * (window_size - window_sizes[iteration-1]) * m_cellSize + m_initialDistance; // Enforce max distance on height threshold if (height_threshold > m_maxDistance) height_threshold = m_maxDistance; window_sizes.push_back(window_size); height_thresholds.push_back(height_threshold); iteration++; } std::vector<PointId> groundIdx; for (PointId i = 0; i < np; ++i) groundIdx.push_back(i); // Progressively filter ground returns using morphological open for (size_t j = 0; j < window_sizes.size(); ++j) { // Limit filtering to those points currently considered ground returns PointViewPtr ground = view->makeNew(); for (PointId i = 0; i < groundIdx.size(); ++i) ground->appendPoint(*view, groundIdx[i]); printf(" Iteration %ld (height threshold = %f, window size = %f)...", j, height_thresholds[j], window_sizes[j]); // Create new cloud to hold the filtered results. Apply the morphological // opening operation at the current window size. auto maxZ = morphOpen(ground, window_sizes[j]*0.5); // Find indices of the points whose difference between the source and // filtered point clouds is less than the current height threshold. std::vector<PointId> pt_indices; for (PointId i = 0; i < ground->size(); ++i) { double z0 = ground->getFieldAs<double>(Dimension::Id::Z, i); double z1 = maxZ[i]; float diff = z0 - z1; if (diff < height_thresholds[j]) pt_indices.push_back(groundIdx[i]); } groundIdx.swap(pt_indices); } return groundIdx; }
std::vector<PointId> PMFFilter::processGround(PointViewPtr view) { // Compute the series of window sizes and height thresholds std::vector<float> htvec; std::vector<float> wsvec; int iter = 0; float ws = 0.0f; float ht = 0.0f; while (ws < m_maxWindowSize) { // Determine the initial window size. if (1) // exponential ws = m_cellSize * (2.0f * std::pow(2, iter) + 1.0f); else ws = m_cellSize * (2.0f * (iter+1) * 2 + 1.0f); // Calculate the height threshold to be used in the next iteration. if (iter == 0) ht = m_initialDistance; else ht = m_slope * (ws - wsvec[iter-1]) * m_cellSize + m_initialDistance; // Enforce max distance on height threshold if (ht > m_maxDistance) ht = m_maxDistance; wsvec.push_back(ws); htvec.push_back(ht); iter++; } std::vector<PointId> groundIdx; for (PointId i = 0; i < view->size(); ++i) groundIdx.push_back(i); // Progressively filter ground returns using morphological open for (size_t j = 0; j < wsvec.size(); ++j) { // Limit filtering to those points currently considered ground returns PointViewPtr ground = view->makeNew(); for (PointId i = 0; i < groundIdx.size(); ++i) ground->appendPoint(*view, groundIdx[i]); log()->get(LogLevel::Debug) << "Iteration " << j << " (height threshold = " << htvec[j] << ", window size = " << wsvec[j] << ")...\n"; // Create new cloud to hold the filtered results. Apply the // morphological opening operation at the current window size. auto maxZ = morphOpen(ground, wsvec[j]*0.5); // Find indices of the points whose difference between the source and // filtered point clouds is less than the current height threshold. std::vector<PointId> groundNewIdx; for (PointId i = 0; i < ground->size(); ++i) { double z0 = ground->getFieldAs<double>(Dimension::Id::Z, i); float diff = z0 - maxZ[i]; if (diff < htvec[j]) groundNewIdx.push_back(groundIdx[i]); } groundIdx.swap(groundNewIdx); log()->get(LogLevel::Debug) << "Ground now has " << groundIdx.size() << " points.\n"; } return groundIdx; }
PointViewSet StatisticalOutlierFilter::run(PointViewPtr input) { bool logOutput = log()->getLevel() > LogLevel::Debug1; if (logOutput) log()->floatPrecision(8); log()->get(LogLevel::Debug2) << "Process StatisticalOutlierFilter...\n"; // convert PointView to PointXYZ typedef pcl::PointCloud<pcl::PointXYZ> Cloud; Cloud::Ptr cloud(new Cloud); BOX3D bounds; input->calculateBounds(bounds); pclsupport::PDALtoPCD(input, *cloud, bounds); // PCL should provide console output at similar verbosity level as PDAL int level = log()->getLevel(); switch (level) { case 0: pcl::console::setVerbosityLevel(pcl::console::L_ALWAYS); break; case 1: pcl::console::setVerbosityLevel(pcl::console::L_ERROR); break; case 2: pcl::console::setVerbosityLevel(pcl::console::L_WARN); break; case 3: pcl::console::setVerbosityLevel(pcl::console::L_INFO); break; case 4: pcl::console::setVerbosityLevel(pcl::console::L_DEBUG); break; default: pcl::console::setVerbosityLevel(pcl::console::L_VERBOSE); break; } // setup the outlier filter pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor(true); sor.setInputCloud(cloud); sor.setMeanK(m_meanK); sor.setStddevMulThresh(m_multiplier); pcl::PointCloud<pcl::PointXYZ> output; sor.setNegative(true); sor.filter(output); // filtered to return inliers pcl::PointIndicesPtr inliers(new pcl::PointIndices); sor.getRemovedIndices(*inliers); log()->get(LogLevel::Debug2) << inliers->indices.size() << std::endl; PointViewSet viewSet; if (inliers->indices.empty()) { log()->get(LogLevel::Warning) << "Requested filter would remove all points. Try increasing the multiplier.\n"; viewSet.insert(input); return viewSet; } // inverse are the outliers std::vector<int> outliers(input->size()-inliers->indices.size()); for (PointId i = 0, j = 0, k = 0; i < input->size(); ++i) { if (i == (PointId)inliers->indices[j]) { j++; continue; } outliers[k++] = i; } if (!outliers.empty() && (m_classify || m_extract)) { if (m_classify) { log()->get(LogLevel::Debug2) << "Labeled " << outliers.size() << " outliers as noise!\n"; // set the classification label of outlier returns as 18 // (corresponding to ASPRS LAS specification for high noise) for (const auto& i : outliers) { input->setField(Dimension::Id::Classification, i, 18); } viewSet.insert(input); } if (m_extract) { log()->get(LogLevel::Debug2) << "Extracted " << inliers->indices.size() << " inliers!\n"; // create new PointView containing only outliers PointViewPtr output = input->makeNew(); for (const auto& i : inliers->indices) { output->appendPoint(*input, i); } viewSet.erase(input); viewSet.insert(output); } } else { if (outliers.empty()) log()->get(LogLevel::Warning) << "Filtered cloud has no outliers!\n"; if (!(m_classify || m_extract)) log()->get(LogLevel::Warning) << "Must choose --classify or --extract\n"; // return the input buffer unchanged viewSet.insert(input); } return viewSet; }
PointViewSet DartSampleFilter::run(PointViewPtr input) { PointViewSet viewSet; PointViewPtr output = input->makeNew(); log()->floatPrecision(2); log()->get(LogLevel::Info) << "DartSampleFilter (radius=" << m_radius << ")\n"; BOX3D buffer_bounds; input->calculateBounds(buffer_bounds); typedef pcl::PointCloud<pcl::PointXYZ> Cloud; Cloud::Ptr cloud(new Cloud); pclsupport::PDALtoPCD(input, *cloud, buffer_bounds); int level = log()->getLevel(); switch (level) { case 0: pcl::console::setVerbosityLevel(pcl::console::L_ALWAYS); break; case 1: pcl::console::setVerbosityLevel(pcl::console::L_ERROR); break; case 2: pcl::console::setVerbosityLevel(pcl::console::L_WARN); break; case 3: pcl::console::setVerbosityLevel(pcl::console::L_INFO); break; case 4: pcl::console::setVerbosityLevel(pcl::console::L_DEBUG); break; default: pcl::console::setVerbosityLevel(pcl::console::L_VERBOSE); break; } pcl::DartSample<pcl::PointXYZ> ds; ds.setInputCloud(cloud); ds.setRadius(m_radius); std::vector<int> samples; ds.filter(samples); if (samples.empty()) { log()->get(LogLevel::Warning) << "Filtered cloud has no points!\n"; return viewSet; } for (const auto& i : samples) output->appendPoint(*input, i); double frac = (double)samples.size() / (double)cloud->size(); log()->get(LogLevel::Info) << "Retaining " << samples.size() << " of " << cloud->size() << " points (" << 100*frac << "%)\n"; viewSet.insert(output); return viewSet; }
PointViewSet PoissonFilter::run(PointViewPtr input) { PointViewPtr output = input->makeNew(); PointViewSet viewSet; viewSet.insert(output); bool logOutput = log()->getLevel() > LogLevel::Debug1; if (logOutput) log()->floatPrecision(8); log()->get(LogLevel::Debug2) << "Process PoissonFilter..." << std::endl; BOX3D buffer_bounds; input->calculateBounds(buffer_bounds); // convert PointView to PointNormal typedef pcl::PointCloud<pcl::PointXYZ> Cloud; Cloud::Ptr cloud(new Cloud); pclsupport::PDALtoPCD(input, *cloud, buffer_bounds); pclsupport::setLogLevel(log()->getLevel()); // pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>); pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>); pcl::search::KdTree<pcl::PointXYZ>::Ptr tree; pcl::search::KdTree<pcl::PointNormal>::Ptr tree2; // Create search tree tree.reset(new pcl::search::KdTree<pcl::PointXYZ> (false)); tree->setInputCloud(cloud); // Normal estimation pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n; pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal> ()); n.setInputCloud(cloud); n.setSearchMethod(tree); n.setKSearch(20); n.compute(*normals); // Concatenate XYZ and normal information pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); // Create search tree tree2.reset(new pcl::search::KdTree<pcl::PointNormal>); tree2->setInputCloud(cloud_with_normals); // initial setup pcl::Poisson<pcl::PointNormal> p; p.setInputCloud(cloud_with_normals); p.setSearchMethod(tree2); p.setDepth(m_depth); p.setPointWeight(m_point_weight); // create PointCloud for results pcl::PolygonMesh grid; p.reconstruct(grid); Cloud::Ptr cloud_f(new Cloud); pcl::fromPCLPointCloud2(grid.cloud, *cloud_f); if (cloud_f->points.empty()) { log()->get(LogLevel::Debug2) << "Filtered cloud has no points!" << std::endl; return viewSet; } pclsupport::PCDtoPDAL(*cloud_f, output, buffer_bounds); log()->get(LogLevel::Debug2) << cloud->points.size() << " before, " << cloud_f->points.size() << " after" << std::endl; log()->get(LogLevel::Debug2) << output->size() << std::endl; return viewSet; }