Skip to content

Commit

Permalink
Add some initial support for handling synthetic points
Browse files Browse the repository at this point in the history
* Add tests for LasReader and LasWriter

* Add method to Segmentation.cpp to separate PointViews into synthetic
  and real points

* Add arguments to SMRF to allow/ignore synthetic points during
  processing

* Add Synthetic to the list of ClassLabels (though this doesn't exactly
  hold for LAS1.4)
  • Loading branch information
chambbj committed Feb 13, 2020
1 parent 5f4e56a commit d9d60ec
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 8 deletions.
24 changes: 17 additions & 7 deletions filters/SMRFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ struct SMRArgs
std::string m_dir;
std::vector<DimRange> m_ignored;
StringList m_returns;
bool m_allowSynthetic;
};

SMRFilter::SMRFilter() : m_args(new SMRArgs) {}
Expand All @@ -113,6 +114,8 @@ void SMRFilter::addArgs(ProgramArgs& args)
args.add("ignore", "Ignore values", m_args->m_ignored);
args.add("returns", "Include last returns?", m_args->m_returns,
{"last", "only"});
args.add("synthetic", "Allow synthetic returns?", m_args->m_allowSynthetic,
true);
}

void SMRFilter::addDimensions(PointLayoutPtr layout)
Expand Down Expand Up @@ -179,15 +182,22 @@ PointViewSet SMRFilter::run(PointViewPtr view)
Segmentation::ignoreDimRanges(m_args->m_ignored, view, keptView,
ignoredView);

PointViewPtr syntheticView = keptView->makeNew();
PointViewPtr realView = keptView->makeNew();
if (m_args->m_allowSynthetic)
realView->append(*keptView);
else
Segmentation::ignoreSynthetic(keptView, realView, syntheticView);

// Check for 0's in ReturnNumber and NumberOfReturns
bool nrOneZero(false);
bool rnOneZero(false);
bool nrAllZero(true);
bool rnAllZero(true);
for (PointId i = 0; i < keptView->size(); ++i)
for (PointId i = 0; i < realView->size(); ++i)
{
uint8_t nr = keptView->getFieldAs<uint8_t>(Id::NumberOfReturns, i);
uint8_t rn = keptView->getFieldAs<uint8_t>(Id::ReturnNumber, i);
uint8_t nr = realView->getFieldAs<uint8_t>(Id::NumberOfReturns, i);
uint8_t rn = realView->getFieldAs<uint8_t>(Id::ReturnNumber, i);
if ((nr == 0) && !nrOneZero)
nrOneZero = true;
if ((rn == 0) && !rnOneZero)
Expand All @@ -204,18 +214,18 @@ PointViewSet SMRFilter::run(PointViewPtr view)
"1.");

// Segment kept view into two views
PointViewPtr inlierView = keptView->makeNew();
PointViewPtr outlierView = keptView->makeNew();
PointViewPtr inlierView = realView->makeNew();
PointViewPtr outlierView = realView->makeNew();
if (nrAllZero && rnAllZero)
{
log()->get(LogLevel::Warning)
<< "Both NumberOfReturns and ReturnNumber are filled with 0's. "
"Proceeding without any further return filtering.\n";
inlierView->append(*keptView);
inlierView->append(*realView);
}
else
{
Segmentation::segmentReturns(keptView, inlierView, outlierView,
Segmentation::segmentReturns(realView, inlierView, outlierView,
m_args->m_returns);
ignoredView->append(*outlierView);
}
Expand Down
16 changes: 15 additions & 1 deletion filters/private/Segmentation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,20 @@ void ignoreDimRanges(std::vector<DimRange>& ranges, PointViewPtr input,
}
}

void ignoreSynthetic(PointViewPtr input, PointViewPtr keep, PointViewPtr ignore)
{
using namespace Dimension;

for (PointId i = 0; i < input->size(); ++i)
{
uint8_t c = input->getFieldAs<uint8_t>(Id::Classification, i);
if (c & ClassLabel::Synthetic)
ignore->appendPoint(*input, i);
else
keep->appendPoint(*input, i);
}
}

void segmentLastReturns(PointViewPtr input, PointViewPtr last,
PointViewPtr other)
{
Expand Down Expand Up @@ -190,7 +204,7 @@ void segmentReturns(PointViewPtr input, PointViewPtr first,
{
uint8_t rn = input->getFieldAs<uint8_t>(Id::ReturnNumber, i);
uint8_t nr = input->getFieldAs<uint8_t>(Id::NumberOfReturns, i);

if ((((rn == 1) && (nr > 1)) && returnFirst) ||
(((rn > 1) && (rn < nr)) && returnIntermediate) ||
(((rn == nr) && (nr > 1)) && returnLast) ||
Expand Down
3 changes: 3 additions & 0 deletions filters/private/Segmentation.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ PDAL_DLL void ignoreDimRange(DimRange dr, PointViewPtr input, PointViewPtr keep,
PDAL_DLL void ignoreDimRanges(std::vector<DimRange>& ranges,
PointViewPtr input, PointViewPtr keep, PointViewPtr ignore);

PDAL_DLL void ignoreSynthetic(PointViewPtr input, PointViewPtr keep,
PointViewPtr ignore);

PDAL_DLL void segmentLastReturns(PointViewPtr input, PointViewPtr last,
PointViewPtr other);

Expand Down
1 change: 1 addition & 0 deletions pdal/pdal_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,7 @@ namespace ClassLabel
const uint8_t IgnoredGround = 20;
const uint8_t Snow = 21;
const uint8_t TemporalExclusion = 22;
const uint8_t Synthetic = 32;
}

namespace
Expand Down
Binary file added test/data/las/synthetic_test.las
Binary file not shown.
18 changes: 18 additions & 0 deletions test/unit/io/LasReaderTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -536,3 +536,21 @@ TEST(LasReaderTest, IgnoreVLRs)
EXPECT_FALSE(!m.empty()) << "No value for node " << i;
}
}

TEST(LasReaderTest, SyntheticPoints)
{
using namespace Dimension;

PointTable table;

Options readOps;
readOps.add("filename", Support::datapath("las/synthetic_test.las"));
LasReader reader;
reader.setOptions(readOps);

reader.prepare(table);
PointViewSet viewSet = reader.execute(table);
PointViewPtr outView = *viewSet.begin();

EXPECT_EQ(ClassLabel::CreatedNeverClassified | ClassLabel::Synthetic, outView->getFieldAs<uint8_t>(Id::Classification, 0));
}
47 changes: 47 additions & 0 deletions test/unit/io/LasWriterTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1425,3 +1425,50 @@ TEST(LasWriterTest, issue2320)
}
#endif

TEST(LasWriterTest, synthetic_points)
{
using namespace Dimension;

const std::string FILENAME(Support::temppath("synthetic_test.las"));
PointTable table;

table.layout()->registerDims({Id::X, Id::Y, Id::Z, Id::Classification});

BufferReader bufferReader;

PointViewPtr view(new PointView(table));
view->setField(Id::X, 0, 1.0);
view->setField(Id::Y, 0, 2.0);
view->setField(Id::Z, 0, 3.0);
view->setField(Id::Classification, 0, ClassLabel::Ground | ClassLabel::Synthetic);
bufferReader.addView(view);

Options writerOps;
writerOps.add("filename", FILENAME);

LasWriter writer;
writer.setOptions(writerOps);
writer.setInput(bufferReader);

writer.prepare(table);
writer.execute(table);

Options readerOps;
readerOps.add("filename", FILENAME);

PointTable readTable;

LasReader reader;
reader.setOptions(readerOps);

reader.prepare(readTable);
PointViewSet viewSet = reader.execute(readTable);
EXPECT_EQ(viewSet.size(), 1u);
view = *viewSet.begin();
EXPECT_EQ(view->size(), 1u);
EXPECT_EQ(ClassLabel::Ground | ClassLabel::Synthetic, view->getFieldAs<uint8_t>(Id::Classification, 0));

FileUtils::deleteFile(FILENAME);
}


0 comments on commit d9d60ec

Please sign in to comment.