Skip to content

Commit

Permalink
--add semantic region creation and bindings.
Browse files Browse the repository at this point in the history
  • Loading branch information
jturner65 committed Jan 23, 2024
1 parent 1290ce7 commit 7d86961
Show file tree
Hide file tree
Showing 4 changed files with 178 additions and 18 deletions.
17 changes: 15 additions & 2 deletions src/esp/bindings/SceneBindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,13 +159,26 @@ void initSceneBindings(py::module& m) {
semanticRegion
.def_property_readonly(
"id", &SemanticRegion::id,
"The ID of the region, of the form ``<level_id>_<region_id>``")
"The ID of the region, either as the region's unique name, or of the "
"form ``<level_id>_<region_id>``")
.def_property_readonly("level", &SemanticRegion::level)
.def_property_readonly("aabb", &SemanticRegion::aabb)
.def_property_readonly("category", &SemanticRegion::category,
"The semantic category of the region")
.def_property_readonly("objects", &SemanticRegion::objects,
"All objects in the region");
"All objects in the region")
.def_property_readonly("poly_loop_points",
&SemanticRegion::getPolyLoopPoints,
"The points making up the polyloop for this "
"region, coplanar and parallel to the floor.")
.def_property_readonly("floor_height", &SemanticRegion::getFloorHeight,
"The height above the x-z plane for the floor of "
"the semantic region.")
.def_property_readonly("extrusion_height",
&SemanticRegion::getExtrusionHeight,
"The height of the extrusion above the floor.")
.def("contains", &SemanticRegion::contains, "point"_a,
"Check whether the given point is contained in the given region.");

// ==== SemanticObject ====
semanticObject
Expand Down
113 changes: 99 additions & 14 deletions src/esp/scene/SemanticScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
// LICENSE file in the root directory of this source tree.

#include "SemanticScene.h"
#include <Magnum/EigenIntegration/GeometryIntegration.h>
#include <Magnum/EigenIntegration/Integration.h>
#include "GibsonSemanticScene.h"
#include "Mp3dSemanticScene.h"
#include "ReplicaSemanticScene.h"
Expand Down Expand Up @@ -145,22 +147,103 @@ bool SemanticScene::
ESP_DEBUG(Mn::Debug::Flag::NoSpace)
<< "Semantic Attributes : `" << semanticAttr->getHandle() << "` has "
<< semanticAttr->getNumRegionInstances() << " regions defined.";

} // if semantic attributes specifes region annotations
} // if semanticAttrs are not null
// Build Semantic regions for each SemanticRegion attributes instance
const auto regionInstances = semanticAttr->getRegionInstances();
for (const auto regionInstance : regionInstances) {
auto regionPtr = SemanticRegion::create();
// Unique name
regionPtr->name_ = regionInstance->getHandle();
// Build a category
regionPtr->category_ =
LoopRegionCategory::create(-1, regionInstance->getLabel());
// Set y heights
regionPtr->extrusionHeight_ = regionInstance->getExtrusionHeight();
regionPtr->floorHeight_ = regionInstance->getFloorHeight();
// Set bbox
const Mn::Vector3 min = regionInstance->getMinBounds();
const Mn::Vector3 max = regionInstance->getMaxBounds();
regionPtr->setBBox(min, max);
// Set polyloop points and precalc polyloop edge vectors
const std::vector<Mn::Vector3> loopPoints =
regionInstance->getPolyLoop();

std::size_t numPts = loopPoints.size();
regionPtr->polyLoopPoints_ = std::vector<Mn::Vector2>(numPts);
// Save points and edges
for (std::size_t i = 0; i < numPts; ++i) {
Mn::Vector2 pt = {loopPoints[i].x(), loopPoints[i].z()};
regionPtr->polyLoopPoints_[i] = pt;
}
}
} else { // if semantic attributes specifes region annotations
ESP_DEBUG(Mn::Debug::Flag::NoSpace)
<< "Semantic Attributes : `" << semanticAttr->getHandle()
<< "` does not have any regions defined.";
}
} else {
ESP_DEBUG(Mn::Debug::Flag::NoSpace) << "Semantic attributes do not exist.";
} // if semanticAttrs exist or not

return loadSuccess;

} // SemanticScene::loadSemanticSceneDescriptor

bool SemanticRegion::contains(const Mn::Vector3& pt) const {
auto checkPt = [&](float x, float x0, float x1, float y, float y0,
float y1) -> bool {
float interp = ((y - y0) / (y1 - y0));
return (y < y0) != (y < y1) && (x < x0 + interp * (x1 - x0));
};

// First check height
if ((pt.y() < floorHeight_) || (pt.y() > (floorHeight_ + extrusionHeight_))) {
return false;
}

// next check bbox
if (!bbox_.contains(Mn::EigenIntegration::cast<vec3f>(pt))) {
return false;
}

// Lastly, count casts across edges.
int count = 0;
int numPts = polyLoopPoints_.size();
for (int i = 0; i < numPts; ++i) {
const auto stPt = polyLoopPoints_[i];
const auto endPt = polyLoopPoints_[(i + 1) % numPts];
if (stPt == endPt) {
// Skip points that are equal.
continue;
}
// If two consecutive y values are equal, rotate the cast by 90.
bool checkCrossing =
(endPt.y() == stPt.y()
? checkPt(pt.y(), stPt.y(), endPt.y(), pt.x(), stPt.x(), endPt.x())
: checkPt(pt.x(), stPt.x(), endPt.x(), pt.y(), stPt.y(),
endPt.y()));
if (checkCrossing) {
++count;
}
}

// Want odd crossings for being inside
return (count % 2 == 1);
} // SemanticRegion::contains

void SemanticRegion::setBBox(const Mn::Vector3& min, const Mn::Vector3& max) {
bbox_ = box3f(Mn::EigenIntegration::cast<vec3f>(min),
Mn::EigenIntegration::cast<vec3f>(max));
} // SemanticRegion::setBBox

namespace {
/**
* @brief Build an AABB for a given set of vertex indices in @p verts list, and
* return in a std::pair, along with the count of verts used to build the AABB.
* @brief Build an AABB for a given set of vertex indices in @p verts list,
* and return in a std::pair, along with the count of verts used to build the
* AABB.
* @param colorInt Semantic Color of object
* @param verts The mesh's vertex buffer.
* @param setOfIDXs set of vertex IDXs in the vertex buffer being used to build
* the resultant AABB.
* @param setOfIDXs set of vertex IDXs in the vertex buffer being used to
* build the resultant AABB.
*/
CCSemanticObject::ptr buildCCSemanticObjForSetOfVerts(
uint32_t colorInt,
Expand Down Expand Up @@ -189,8 +272,8 @@ CCSemanticObject::ptr buildCCSemanticObjForSetOfVerts(
} // buildCCSemanticObjForSetOfVerts

/**
* @brief build per-SSD object vector of known semantic IDs - doing this in case
* semanticIDs are not contiguous.
* @brief build per-SSD object vector of known semantic IDs - doing this in
* case semanticIDs are not contiguous.
*/

std::vector<int> getObjsIdxToIDMap(
Expand Down Expand Up @@ -236,8 +319,8 @@ SemanticScene::buildCCBasedSemanticObjs(
}
}

// only map to semantic ID if semanticScene exists, otherwise return map with
// objects keyed by hex color
// only map to semantic ID if semanticScene exists, otherwise return map
// with objects keyed by hex color
if (!semanticScene) {
return semanticCCObjsByVertTag;
}
Expand Down Expand Up @@ -432,8 +515,9 @@ std::vector<uint32_t> SemanticScene::buildSemanticOBBs(
// number of unique ssdObjs mappings.

for (int vertIdx = 0; vertIdx < vertSemanticIDs.size(); ++vertIdx) {
// semantic ID on vertex - valid values are 1->semanticIDToSSOBJidx.size().
// Invalid/unknown semantic ids are > semanticIDToSSOBJidx.size()
// semantic ID on vertex - valid values are
// 1->semanticIDToSSOBJidx.size(). Invalid/unknown semantic ids are >
// semanticIDToSSOBJidx.size()
const auto semanticID = vertSemanticIDs[vertIdx];
if ((semanticID >= 0) && (semanticID < semanticIDToSSOBJidx.size())) {
const auto vert = vertices[vertIdx];
Expand Down Expand Up @@ -473,7 +557,8 @@ std::vector<uint32_t> SemanticScene::buildSemanticOBBs(
center = .5f * (vertMax[semanticID] + vertMin[semanticID]);
dims = vertMax[semanticID] - vertMin[semanticID];
ESP_VERY_VERBOSE() << Cr::Utility::formatString(
"{} Semantic ID : {} : color : {} tag : {} present in {} verts | BB "
"{} Semantic ID : {} : color : {} tag : {} present in {} verts | "
"BB "
"Center [{} {} {}] Dims [{} {} {}]",
msgPrefix, semanticID, geo::getColorAsString(ssdObj.getColor()),
ssdObj.id(), vertCounts[semanticID], center.x(), center.y(),
Expand Down
55 changes: 53 additions & 2 deletions src/esp/scene/SemanticScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,26 +432,68 @@ class SemanticLevel {
ESP_SMART_POINTERS(SemanticLevel)
};

class LoopRegionCategory : public SemanticCategory {
public:
LoopRegionCategory(const int id, const std::string& name)
: id_(id), name_(name) {}

int index(const std::string& /*mapping*/) const override { return id_; }

std::string name(const std::string& mapping) const override {
if (mapping == "category" || mapping.empty()) {
return name_;
} else {
ESP_ERROR() << "Unknown mapping type:" << mapping;
return "UNKNOWN";
}
}

protected:
int id_;
std::string name_;
ESP_SMART_POINTERS(LoopRegionCategory)

}; // class LoopRegionCategory

//! Represents a region (typically room) in a level of a house
class SemanticRegion {
public:
virtual ~SemanticRegion() = default;
virtual std::string id() const {
if (!name_.empty()) {
return name_;
}
if (level_ != nullptr) {
return level_->id() + "_" + std::to_string(index_);
} else {
return "_" + std::to_string(index_);
}
}

int getIndex() const { return index_; }
SemanticLevel::ptr level() const { return level_; }

const std::vector<std::shared_ptr<SemanticObject>>& objects() const {
return objects_;
}

/**
* @brief Test whether this region contains the passed point
*/
virtual bool contains(const Mn::Vector3& point) const;

void setBBox(const Mn::Vector3& min, const Mn::Vector3& max);

box3f aabb() const { return bbox_; }

const std::vector<Mn::Vector2>& getPolyLoopPoints() const {
return polyLoopPoints_;
}

double getExtrusionHeight() const { return extrusionHeight_; }

double getFloorHeight() const { return floorHeight_; }

SemanticCategory::ptr category() const { return category_; }

protected:
Expand All @@ -460,8 +502,17 @@ class SemanticRegion {
std::shared_ptr<SemanticCategory> category_;
vec3f position_;
box3f bbox_;
vec3f floorNormal_;
std::vector<vec3f> floorPoints_;

std::string name_;

// Extrusion-based regions
double extrusionHeight_{};
// Floor height
double floorHeight_{};

// poly loop points
std::vector<Mn::Vector2> polyLoopPoints_;

std::vector<std::shared_ptr<SemanticObject>> objects_;
std::shared_ptr<SemanticLevel> level_;
friend SemanticScene;
Expand Down
11 changes: 11 additions & 0 deletions src/esp/sim/Simulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,17 @@ bool Simulator::createSceneInstance(const std::string& activeSceneName) {
"failed due to specified semantic tag `{}` not being found in "
"SemanticAttributesManager. Aborting",
activeSceneName, currSemanticAttrHandle));
if (semanticAttr) {
ESP_VERY_VERBOSE(Mn::Debug::Flag::NoSpace)
<< "Scene Instance `" << activeSceneName
<< "` has Semantic attr handle : `" << currSemanticAttrHandle
<< "` which tagged attributes : `" << semanticAttr->getHandle() << "`";
} else {
ESP_VERY_VERBOSE(Mn::Debug::Flag::NoSpace)
<< "Scene Instance `" << activeSceneName
<< "` has Semantic attr handle : `" << currSemanticAttrHandle
<< "` which did not reference any attributes";
}
// - Load semantic scene
resourceManager_->loadSemanticScene(semanticAttr, activeSceneName);

Expand Down

0 comments on commit 7d86961

Please sign in to comment.