diff --git a/src/esp/CMakeLists.txt b/src/esp/CMakeLists.txt index d8c2df4b24..a4639d000c 100644 --- a/src/esp/CMakeLists.txt +++ b/src/esp/CMakeLists.txt @@ -278,8 +278,20 @@ set( metadata/attributes/AttributesEnumMaps.cpp metadata/attributes/AbstractObjectAttributes.h metadata/attributes/AbstractObjectAttributes.cpp + metadata/attributes/AbstractSensorAttributes.h + metadata/attributes/AbstractSensorAttributes.cpp + metadata/attributes/AbstractVisualSensorAttributes.h + metadata/attributes/AbstractVisualSensorAttributes.cpp metadata/attributes/ArticulatedObjectAttributes.h metadata/attributes/ArticulatedObjectAttributes.cpp + metadata/attributes/AudioSensorAttributes.h + metadata/attributes/AudioSensorAttributes.cpp + metadata/attributes/CameraSensorAttributes.h + metadata/attributes/CameraSensorAttributes.cpp + metadata/attributes/CustomSensorAttributes.h + metadata/attributes/CustomSensorAttributes.cpp + metadata/attributes/CubeMapSensorAttributes.h + metadata/attributes/CubeMapSensorAttributes.cpp metadata/attributes/LightLayoutAttributes.h metadata/attributes/LightLayoutAttributes.cpp metadata/attributes/MarkerSets.h @@ -319,6 +331,8 @@ set( metadata/managers/SceneDatasetAttributesManager.cpp metadata/managers/SemanticAttributesManager.h metadata/managers/SemanticAttributesManager.cpp + metadata/managers/SensorAttributesManager.h + metadata/managers/SensorAttributesManager.cpp metadata/managers/StageAttributesManager.h metadata/managers/StageAttributesManager.cpp metadata/MetadataMediator.h diff --git a/src/esp/bindings/SensorBindings.cpp b/src/esp/bindings/SensorBindings.cpp index 9b73e7c391..5960044828 100644 --- a/src/esp/bindings/SensorBindings.cpp +++ b/src/esp/bindings/SensorBindings.cpp @@ -53,14 +53,16 @@ void initSensorBindings(py::module& m) { // TODO fill out other SensorTypes // ==== enum SensorType ==== py::enum_(m, "SensorType") - .value("NONE", SensorType::None) + .value("NONE", SensorType::Unspecified) + .value("CUSTOM", SensorType::Custom) .value("COLOR", SensorType::Color) .value("DEPTH", SensorType::Depth) .value("SEMANTIC", SensorType::Semantic) .value("AUDIO", SensorType::Audio); py::enum_(m, "SensorSubType") - .value("NONE", SensorSubType::None) + .value("NONE", SensorSubType::Unspecified) + .value("CUSTOM", SensorSubType::Custom) .value("PINHOLE", SensorSubType::Pinhole) .value("ORTHOGRAPHIC", SensorSubType::Orthographic) .value("FISHEYE", SensorSubType::Fisheye) @@ -70,6 +72,7 @@ void initSensorBindings(py::module& m) { // NOTE : esp::sensor::SemanticSensorTarget is an alias for // esp::scene::SceneNodeSemanticDataIDX. py::enum_(m, "SemanticSensorTarget") + .value("DRAWABLE_ID", SemanticSensorTarget::DrawableID) .value("SEMANTIC_ID", SemanticSensorTarget::SemanticID) .value("OBJECT_ID", SemanticSensorTarget::ObjectID); diff --git a/src/esp/metadata/MetadataMediator.cpp b/src/esp/metadata/MetadataMediator.cpp index e67ca5bdfa..0386021ee4 100644 --- a/src/esp/metadata/MetadataMediator.cpp +++ b/src/esp/metadata/MetadataMediator.cpp @@ -19,6 +19,8 @@ void MetadataMediator::buildAttributesManagers() { pbrShaderAttributesManager_ = managers::PbrShaderAttributesManager::create(); + sensorAttributesManager_ = managers::SensorAttributesManager::create(); + sceneDatasetAttributesManager_ = managers::SceneDatasetAttributesManager::create( physicsAttributesManager_, pbrShaderAttributesManager_); diff --git a/src/esp/metadata/MetadataMediator.h b/src/esp/metadata/MetadataMediator.h index 47cf4fd10f..9ba798a01f 100644 --- a/src/esp/metadata/MetadataMediator.h +++ b/src/esp/metadata/MetadataMediator.h @@ -19,6 +19,7 @@ #include "esp/metadata/managers/PhysicsAttributesManager.h" #include "esp/metadata/managers/SceneDatasetAttributesManager.h" #include "esp/metadata/managers/SemanticAttributesManager.h" +#include "esp/metadata/managers/SensorAttributesManager.h" #include "esp/metadata/managers/StageAttributesManager.h" #include "esp/sim/SimulatorConfiguration.h" @@ -198,6 +199,15 @@ class MetadataMediator { return pbrShaderAttributesManager_; } // getPbrShaderAttributesManager + /** + * @brief Return manager for construction and access to Sensor attributes; + * @return A shared pointer to the current @ref esp::metadata::managers::SensorAttributesManager. + */ + const managers::SensorAttributesManager::ptr& getSensorAttributesManager() + const { + return sensorAttributesManager_; + } // getSensorAttributesManager + /** * @brief Return manager for construction and access to * @ref esp::attributes::SceneInstanceAttributes for current dataset. @@ -683,6 +693,12 @@ class MetadataMediator { managers::PbrShaderAttributesManager::ptr pbrShaderAttributesManager_ = nullptr; + /** + * @brief Manages all the SensorAttributes configuration settings, used to + * build sensors, independent of loaded datasets. + */ + managers::SensorAttributesManager::ptr sensorAttributesManager_ = nullptr; + public: ESP_SMART_POINTERS(MetadataMediator) }; // namespace metadata diff --git a/src/esp/metadata/attributes/AbstractSensorAttributes.cpp b/src/esp/metadata/attributes/AbstractSensorAttributes.cpp new file mode 100644 index 0000000000..b14ca71d6a --- /dev/null +++ b/src/esp/metadata/attributes/AbstractSensorAttributes.cpp @@ -0,0 +1,63 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "AbstractSensorAttributes.h" +namespace esp { +namespace metadata { +namespace attributes { + +AbstractSensorAttributes::AbstractSensorAttributes( + const std::string& attributesClassKey, + const std::string& handle) + : AbstractAttributes(attributesClassKey, handle) { + init("position", Mn::Vector3{0.0, 1.5, 0.0}); + init("orientation", Mn::Vector3{0.0, 0.0, 0.0}); + init("noise_model", "None"); + + initTranslated("sensor_type", + getSensorTypeName(sensor::SensorType::Unspecified)); + initTranslated("sensor_subtype", + getSensorSubTypeName(sensor::SensorSubType::Unspecified)); +} // AbstractSensorAttributes ctor + +void AbstractSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + setPosition(spec->position); + setOrientation(spec->orientation); + setNoiseModel(spec->noiseModel); + setSensorTypeEnum(spec->sensorType); + setSensorSubTypeEnum(spec->sensorSubType); +} // AbstractSensorAttributes::populateWithSensorSpec + +void AbstractSensorAttributes::writeValuesToJson( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // write AbstractSensorAttributes to JSON + writeValueToJson("position", jsonObj, allocator); + writeValueToJson("orientation", jsonObj, allocator); + writeValueToJson("noise_model", jsonObj, allocator); + writeValueToJson("sensor_type", jsonObj, allocator); + writeValueToJson("sensor_subtype", jsonObj, allocator); + + // call child-class-specific + writeValuesToJsonInternal(jsonObj, allocator); +} // AbstractSensorAttributes::writeValuesToJson + +std::string AbstractSensorAttributes::getObjectInfoHeaderInternal() const { + return "Position XYZ,Orientation XYZ,Noise Model,Sensor " + "Type,Sensor Subtype," + + getAbstractSensorInfoHeaderInternal(); +} // AbstractSensorAttributes::getObjectInfoHeaderInternal + +std::string AbstractSensorAttributes::getObjectInfoInternal() const { + return Cr::Utility::formatString("{},{},{},{},{},{}", getAsString("position"), + getAsString("orientation"), getNoiseModel(), + getSensorTypeName(getSensorType()), + getSensorSubTypeName(getSensorSubType()), + getAbstractSensorInfoInternal()); +} // AbstractSensorAttributes::getObjectInfoInternal + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/AbstractSensorAttributes.h b/src/esp/metadata/attributes/AbstractSensorAttributes.h new file mode 100644 index 0000000000..86e97c4553 --- /dev/null +++ b/src/esp/metadata/attributes/AbstractSensorAttributes.h @@ -0,0 +1,207 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_ABSTRACTSENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_ABSTRACTSENSORATTRIBUTES_H_ + +#include "AbstractAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { + +/** + * @brief Attributes object holding the descriptions of a Sensor object + */ +class AbstractSensorAttributes : public AbstractAttributes { + public: + AbstractSensorAttributes(const std::string& classKey, + const std::string& handle); + + /** + * @brief Populate this attributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + virtual void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec); + + /** @brief Set the position of the sensor. */ + void setPosition(const Magnum::Vector3& position) { + set("position", position); + } + + /** @brief Get the position of the sensor. */ + Magnum::Vector3 getPosition() const { + return get("position"); + } + + /** @brief Set the position of the sensor. */ + void setOrientation(const Magnum::Vector3& orientation) { + set("orientation", orientation); + } + + /** @brief Get the position of the sensor. */ + Magnum::Vector3 getOrientation() const { + return get("orientation"); + } + + /** @brief Sets the noise model to use for this sensor. */ + void setNoiseModel(const std::string& noise_model) { + set("noise_model", noise_model); + } + + /** @brief Gets the noise model to use for this sensor. */ + std::string getNoiseModel() const { return get("noise_model"); } + + /** + * @brief Set the sensor type for this sensor. + */ + void setSensorType(const std::string& sensorType) { + // force to lowercase to check if present + const std::string sensorTypeLC = Cr::Utility::String::lowercase(sensorType); + auto mapIter = SensorTypeNamesMap.find(sensorTypeLC); + if (mapIter == SensorTypeNamesMap.end()) { + ESP_ERROR(Mn::Debug::Flag::NoSpace) + << "'" << sensorType + << "' is an illegal value for " + "AbstractSensorAttributes::setSensorType, so current value " + << get("sensor_type") << " not changed."; + return; + } + setTranslated("sensor_type", sensorType); + } // setSensorType + + /** + * @brief Set the sensor type for this sensor as specified by given @ref SensorType + */ + void setSensorTypeEnum(sensor::SensorType sensorTypeEnum) { + // force to lowercase to check if present + const std::string sensorType = getSensorTypeName(sensorTypeEnum); + auto mapIter = SensorTypeNamesMap.find(sensorType); + + ESP_CHECK(mapIter != SensorTypeNamesMap.end(), + "Illegal SensorType enum value given" + << static_cast(sensorTypeEnum) << ":" << sensorType + << "attempted to be initialized in AbstractSensorAttributes:" + << getHandle() << ". Aborting."); + + setTranslated("sensor_type", sensorType); + } // setSensorTypeEnum + + /** + * @brief Get the sensor type for this sensor. + */ + sensor::SensorType getSensorType() const { + const std::string val = + Cr::Utility::String::lowercase(get("sensor_type")); + auto mapIter = SensorTypeNamesMap.find(val); + if (mapIter != SensorTypeNamesMap.end()) { + return mapIter->second; + } + // This should never get to here. It would mean that this field was set + // to an invalid value somehow. + return sensor::SensorType::Unspecified; + } + + /** + * @brief Set the sensor type for this sensor. + */ + void setSensorSubType(const std::string& sensorSubType) { + // force to lowercase to check if present + const std::string sensorTypeLC = + Cr::Utility::String::lowercase(sensorSubType); + auto mapIter = SensorSubTypeNamesMap.find(sensorTypeLC); + if (mapIter == SensorSubTypeNamesMap.end()) { + ESP_ERROR(Mn::Debug::Flag::NoSpace) + << "'" << sensorSubType + << "' is an illegal value for " + "AbstractSensorAttributes::setSensorSubType, so current value " + << get("sensor_subtype") << " not changed."; + return; + } + setTranslated("sensor_subtype", sensorSubType); + } // setSensorSubType + + /** + * @brief Set the sensor subtype for this sensor as specified by given @ref SensorSubType + */ + void setSensorSubTypeEnum(sensor::SensorSubType sensorSubTypeEnum) { + // force to lowercase to check if present + const std::string sensorSubType = getSensorSubTypeName(sensorSubTypeEnum); + auto mapIter = SensorSubTypeNamesMap.find(sensorSubType); + + ESP_CHECK(mapIter != SensorSubTypeNamesMap.end(), + "Illegal SensorSubType enum value given" + << static_cast(sensorSubTypeEnum) << ":" << sensorSubType + << "attempted to be initialized in AbstractSensorAttributes:" + << getHandle() << ". Aborting."); + + setTranslated("sensor_subtype", sensorSubType); + } // setSensorSubTypeEnum + + /** + * @brief Get the sensor subtype for this sensor. + */ + sensor::SensorSubType getSensorSubType() const { + const std::string val = + Cr::Utility::String::lowercase(get("sensor_subtype")); + auto mapIter = SensorSubTypeNamesMap.find(val); + if (mapIter != SensorSubTypeNamesMap.end()) { + return mapIter->second; + } + // This should never get to here. It would mean that this field was set + // to an invalid value somehow. + return sensor::SensorSubType::Unspecified; + } // getSensorSubType + + /** + * @brief Populate a json object with all the first-level values held in this + * configuration. Default is overridden to handle special cases for + * AbstractSensorAttributes and deriving (i.e. AudioSensorAttributes or + * VisualSensorAttributes) classes. + */ + void writeValuesToJson(io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + protected: + /** + * @brief Write child-class-specific values to json object + * + */ + virtual void writeValuesToJsonInternal( + CORRADE_UNUSED io::JsonGenericValue& jsonObj, + CORRADE_UNUSED io::JsonAllocator& allocator) const {} + + /** + * @brief Retrieve a comma-separated string holding the header values for the + * info returned for this managed object, type-specific. + */ + + std::string getObjectInfoHeaderInternal() const override; + /** + * @brief get AbstractSensorAttributes-specific info header + */ + virtual std::string getAbstractSensorInfoHeaderInternal() const { + return ""; + }; + + /** + * @brief Retrieve a comma-separated informational string about the contents + * of this managed object. + */ + std::string getObjectInfoInternal() const override; + /** + * @brief get AbstractSensorAttributes specific info for csv string + */ + virtual std::string getAbstractSensorInfoInternal() const { return ""; }; + + public: + ESP_SMART_POINTERS(AbstractSensorAttributes) +}; // class AbstractSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_ABSTRACTSENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/attributes/AbstractVisualSensorAttributes.cpp b/src/esp/metadata/attributes/AbstractVisualSensorAttributes.cpp new file mode 100644 index 0000000000..6fe17a0452 --- /dev/null +++ b/src/esp/metadata/attributes/AbstractVisualSensorAttributes.cpp @@ -0,0 +1,81 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "AbstractVisualSensorAttributes.h" +#include "esp/sensor/VisualSensor.h" + +namespace esp { +namespace metadata { +namespace attributes { + +AbstractVisualSensorAttributes::AbstractVisualSensorAttributes( + const std::string& classKey, + const std::string& handle) + : AbstractSensorAttributes(classKey, handle) { + init("resolution", Mn::Vector2i{128, 128}); + init("channels", 4); + init("gpu_to_gpu_transfer", false); + init("near_plane", 0.01); + init("far_plane", 1000.0); + init("clear_color", Mn::Color4{0, 0, 0, 1}); + initTranslated("semantic_sensor_target", + getSemanitcSensorTargetName( + esp::sensor::SemanticSensorTarget::SemanticID)); + +} // AbstractVisualSensorAttributes ctor + +void AbstractVisualSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Base class version + AbstractSensorAttributes::populateWithSensorSpec(spec); + // Appropriately cast to get visual spec data if exists + const esp::sensor::VisualSensorSpec::ptr& visualSpec = + std::dynamic_pointer_cast(spec); + + setResolution(visualSpec->resolution); + setChannels(visualSpec->channels); + setGPUToGPUTransfer(visualSpec->gpu2gpuTransfer); + setNearPlane(visualSpec->near); + setFarPlane(visualSpec->far); + setClearColor(visualSpec->clearColor); + setSemanticSensorTargetEnum(visualSpec->semanticTarget); + +} // AbstractVisualSensorAttributes::populateWithSensorSpec + +void AbstractVisualSensorAttributes::writeValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // write AbstractVisualSensorAttributes values to json + writeValueToJson("resolution", jsonObj, allocator); + writeValueToJson("channels", jsonObj, allocator); + writeValueToJson("gpu_to_gpu_transfer", jsonObj, allocator); + writeValueToJson("near_plane", jsonObj, allocator); + writeValueToJson("far_plane", jsonObj, allocator); + writeValueToJson("clear_color", jsonObj, allocator); + writeValueToJson("semantic_sensor_target", jsonObj, allocator); + // call child-class-specific + writeVisualSensorValuesToJsonInternal(jsonObj, allocator); +} // AbstractVisualSensorAttributes::writeValuesToJsonInternal + +std::string +AbstractVisualSensorAttributes::getAbstractSensorInfoHeaderInternal() const { + return "Resolution YX,Channels,GPU to GPU Transfer,Near Plane,Far " + "Plane,Clear Color RGBA,Semantic Sensor Target," + + getAbstractVisualSensorInfoHeaderInternal(); +} // AbstractVisualSensorAttributes::getAbstractSensorInfoHeaderInternal + +std::string AbstractVisualSensorAttributes::getAbstractSensorInfoInternal() + const { + return Cr::Utility::formatString( + "{},{},{},{},{},{},{},{}", getAsString("resolution"), + getAsString("channels"), getAsString("gpu_to_gpu_transfer"), + getAsString("near_plane"), getAsString("far_plane"), + getAsString("clear_color"), + getSemanitcSensorTargetName(getSemanticSensorTarget()), + getAbstractVisualSensorInfoInternal()); +} // AbstractVisualSensorAttributes::getAbstractSensorInfoInternal + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/AbstractVisualSensorAttributes.h b/src/esp/metadata/attributes/AbstractVisualSensorAttributes.h new file mode 100644 index 0000000000..3abf7e9f90 --- /dev/null +++ b/src/esp/metadata/attributes/AbstractVisualSensorAttributes.h @@ -0,0 +1,207 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_ABSTRACTVISUALSENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_ABSTRACTVISUALSENSORATTRIBUTES_H_ + +#include "AbstractSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { + +/** + * @brief Class to suppoort creating visual sensors by providing common + * attributes. + */ +class AbstractVisualSensorAttributes : public AbstractSensorAttributes { + public: + AbstractVisualSensorAttributes(const std::string& classKey, + const std::string& handle); + + /** + * @brief Populate this AbstractVisualSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + + /** + * @brief Set the resolution (Height, Width) of the Visual Sensor built from + * this attributes. + */ + void setResolution(const Mn::Vector2i& resolution) { + set("resolution", resolution); + } + + /** + * @brief Get the resolution (Height, Width) of the Visual Sensor built from + * this attributes. + */ + + Mn::Vector2i getResolution() const { return get("resolution"); } + + /** + * @brief Set the number of channels for the Visual Sensor built from + * this attributes. + */ + void setChannels(int channels) { set("channels", channels); } + + /** + * @brief get the number of channels for the Visual Sensor built from this + * attributes. + */ + int getChannels() const { return get("channels"); } + + /** + * @brief Set whether to enable gpu-to-gpu transfer for the sensor built + * from this attributes. + */ + void setGPUToGPUTransfer(bool transfer) { + set("gpu_to_gpu_transfer", transfer); + } + + /** + * @brief get whether to enable gpu-to-gpu transfer for the sensor built + * from this attributes. + */ + bool getGPUToGPUTransfer() const { return get("gpu_to_gpu_transfer"); } + + /** + * @brief Set the near plane distance for visual sensors built from this + * attributes. + */ + void setNearPlane(float near_plane) { set("near_plane", near_plane); } + /** + * @brief Get the near plane distance for visual sensors built from this + * attributes. + */ + float getNearPlane() const { + return static_cast(get("near_plane")); + } + + /** + * @brief Set the far plane distance for visual sensors built from this + * attributes. + */ + void setFarPlane(float far_plane) { set("far_plane", far_plane); } + + /** + * @brief Get the far plane distance for visual sensors built from this + * attributes. + */ + float getFarPlane() const { + return static_cast(get("far_plane")); + } + + /** + * @brief Set the clear color to use for the visual sensor built from this + * attributes. + */ + + void setClearColor(const Mn::Color4& clear_color) { + set("clear_color", clear_color); + } + + /** + * @brief Get the clear color to use for the visual sensor built from this + * attributes. + */ + Mn::Color4 getClearColor() const { return get("clear_color"); } + + /** + * @brief Set the SemanticSensorTarget to use for a Semantic Sensor built + * from this attributes. + */ + void setSemanticSensorTarget(const std::string& semantic_target) { + // force to lowercase before setting + const std::string semanticTargetLC = + Cr::Utility::String::lowercase(semantic_target); + auto mapIter = SemanticSensorTargetMap.find(semanticTargetLC); + ESP_CHECK(mapIter != SemanticSensorTargetMap.end(), + "Illegal semantic sensor target value" + << semantic_target + << "attempted to be set in AbstractVisualSensorAttributes:" + << getHandle() << ". Aborting."); + setTranslated("semantic_sensor_target", semantic_target); + } + + /** + * @brief Set the SemanticSensorTarget to use for a Semantic Sensor built + * from this attributes using the given @ref sensor::SemanticSensorTarget enum value. + */ + void setSemanticSensorTargetEnum( + sensor::SemanticSensorTarget semanticTargetEnum) { + // force to lowercase before setting + const std::string semanticTarget = + getSemanitcSensorTargetName(semanticTargetEnum); + auto mapIter = SemanticSensorTargetMap.find(semanticTarget); + ESP_CHECK(mapIter != SemanticSensorTargetMap.end(), + "Illegal Semantic Sensor Tyarget enum value given" + << static_cast(semanticTargetEnum) << ":" + << semanticTarget + << "attempted to be set in AbstractVisualSensorAttributes:" + << getHandle() << ". Aborting."); + setTranslated("semantic_sensor_target", semanticTarget); + } + + /** + * @brief Get the SemanticSensorTarget to use for a Semantic Sensor built + * from this attributes. + */ + sensor::SemanticSensorTarget getSemanticSensorTarget() const { + const std::string val = Cr::Utility::String::lowercase( + get("semantic_sensor_target")); + auto mapIter = SemanticSensorTargetMap.find(val); + if (mapIter != SemanticSensorTargetMap.end()) { + return mapIter->second; + } + // Default to semantic ID + return esp::sensor::SemanticSensorTarget::SemanticID; + } + + protected: + /** + * @brief Write Visual Sensor-specific values to json object + */ + void writeValuesToJsonInternal(io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + virtual void writeVisualSensorValuesToJsonInternal( + CORRADE_UNUSED io::JsonGenericValue& jsonObj, + CORRADE_UNUSED io::JsonAllocator& allocator) const {}; + + /** + * @brief get AbstractSensorAttributes-specific info header + */ + std::string getAbstractSensorInfoHeaderInternal() const override; + + /** + * @brief get AbstractSensorAttributes specific info for csv string + */ + std::string getAbstractSensorInfoInternal() const override; + + /** + * @brief get AbstractVisualSensorAttributes-specific info header + */ + virtual std::string getAbstractVisualSensorInfoHeaderInternal() const { + return ""; + } + + /** + * @brief get AbstractSensorAttributes specific info for csv string + */ + virtual std::string getAbstractVisualSensorInfoInternal() const { + return ""; + }; + + public: + ESP_SMART_POINTERS(AbstractVisualSensorAttributes) +}; // class VisualSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_ABSTRACTVISUALSENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/attributes/AttributesEnumMaps.cpp b/src/esp/metadata/attributes/AttributesEnumMaps.cpp index fce088beae..f8407811bf 100644 --- a/src/esp/metadata/attributes/AttributesEnumMaps.cpp +++ b/src/esp/metadata/attributes/AttributesEnumMaps.cpp @@ -254,7 +254,8 @@ std::string getMotionTypeName(esp::physics::MotionType motionTypeEnum) { } // getMotionTypeName const std::map SensorTypeNamesMap = { - {"none", esp::sensor::SensorType::None}, + {"unspecified", esp::sensor::SensorType::Unspecified}, + {"custom", esp::sensor::SensorType::Custom}, {"color", esp::sensor::SensorType::Color}, {"depth", esp::sensor::SensorType::Depth}, {"normal", esp::sensor::SensorType::Normal}, @@ -266,9 +267,9 @@ std::string getSensorTypeName(esp::sensor::SensorType sensorTypeEnum) { // this verifies that enum value being checked is supported by string-keyed // map. The values below should be the minimum and maximum enums supported by // SensorTypeNamesMap - if ((sensorTypeEnum <= esp::sensor::SensorType::None) || + if ((sensorTypeEnum <= esp::sensor::SensorType::Unspecified) || (sensorTypeEnum >= esp::sensor::SensorType::EndSensorType)) { - return "none"; + return "unspecified"; } // Must always be valid value for (const auto& it : SensorTypeNamesMap) { @@ -276,12 +277,13 @@ std::string getSensorTypeName(esp::sensor::SensorType sensorTypeEnum) { return it.first; } } - return "none"; + return "unspecified"; } // getSensorTypeName const std::map SensorSubTypeNamesMap = { - {"none", esp::sensor::SensorSubType::None}, + {"unspecified", esp::sensor::SensorSubType::Unspecified}, + {"custom", esp::sensor::SensorSubType::Custom}, {"pinhole", esp::sensor::SensorSubType::Pinhole}, {"orthographic", esp::sensor::SensorSubType::Orthographic}, {"fisheye", esp::sensor::SensorSubType::Fisheye}, @@ -293,9 +295,9 @@ std::string getSensorSubTypeName(esp::sensor::SensorSubType sensorSubTypeEnum) { // this verifies that enum value being checked is supported by string-keyed // map. The values below should be the minimum and maximum enums supported by // SensorSubTypeNamesMap - if ((sensorSubTypeEnum <= esp::sensor::SensorSubType::None) || + if ((sensorSubTypeEnum <= esp::sensor::SensorSubType::Unspecified) || (sensorSubTypeEnum >= esp::sensor::SensorSubType::EndSensorSubType)) { - return "none"; + return "unspecified"; } // Must always be valid value for (const auto& it : SensorSubTypeNamesMap) { @@ -303,11 +305,11 @@ std::string getSensorSubTypeName(esp::sensor::SensorSubType sensorSubTypeEnum) { return it.first; } } - return "none"; + return "unspecified"; } // getSensorSubTypeName const std::map - SemanticSensorTargetNamesMap = { + SemanticSensorTargetMap = { {"semantic_id", esp::sensor::SemanticSensorTarget::SemanticID}, {"object_id", esp::sensor::SemanticSensorTarget::ObjectID}, {"drawable_id", esp::sensor::SemanticSensorTarget::DrawableID}, @@ -317,7 +319,7 @@ std::string getSemanitcSensorTargetName( esp::sensor::SemanticSensorTarget semanticSensorTargetEnum) { // this verifies that enum value being checked is supported by string-keyed // map. The values below should be the minimum and maximum enums supported by - // SemanticSensorTargetNamesMap + // SemanticSensorTargetMap if ((semanticSensorTargetEnum <= esp::sensor::SemanticSensorTarget::SemanticID) || (semanticSensorTargetEnum >= @@ -326,7 +328,7 @@ std::string getSemanitcSensorTargetName( return "semantic_id"; } // Must always be valid value - for (const auto& it : SemanticSensorTargetNamesMap) { + for (const auto& it : SemanticSensorTargetMap) { if (it.second == semanticSensorTargetEnum) { return it.first; } diff --git a/src/esp/metadata/attributes/AudioSensorAttributes.cpp b/src/esp/metadata/attributes/AudioSensorAttributes.cpp new file mode 100644 index 0000000000..d4c87ba923 --- /dev/null +++ b/src/esp/metadata/attributes/AudioSensorAttributes.cpp @@ -0,0 +1,58 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "AudioSensorAttributes.h" +#include "esp/sensor/AudioSensor.h" + +namespace esp { +namespace metadata { +namespace attributes { + +AudioSensorAttributes::AudioSensorAttributes(const std::string& handle) + : AbstractSensorAttributes("AudioSensorAttributes", handle) { +} // AudioSensorAttributes ctor + +void AudioSensorAttributes::populateWithSensorSpec( + const std::shared_ptr& spec) { + AbstractSensorAttributes::populateWithSensorSpec(spec); +#ifdef ESP_BUILD_WITH_AUDIO + // Appropriately cast to get audio data if exists + const esp::sensor::AudioSensorSpec::ptr& audioSpec = + std::dynamic_pointer_cast(spec); + setOutputDirectory(audioSpec->outputDirectory_); + setAcousticsConfig(audioSpec->acousticsConfig_); + setChannelLayout(audioSpec->channelLayout_); + +#endif // ESP_BUILD_WITH_AUDIO +} // AudioSensorAttributes::populateWithSensorSpec + +void AudioSensorAttributes::writeValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // write AbstractObjectAttributes values to json + writeValueToJson("output_directory", jsonObj, allocator); + // TODO need some way to transform RLRAudioPropagation constructs to strings +} // AudioSensorAttributes::writeValuesToJsonInternal + +std::string AudioSensorAttributes::getAbstractSensorInfoHeaderInternal() const { +// TODO need some way to transform RLRAudioPropagation constructs to strings +#ifdef ESP_BUILD_WITH_AUDIO + return "Output Directory"; +#else + return ""; +#endif +} // AudioSensorAttributes::getAbstractSensorInfoHeaderInternal + +std::string AudioSensorAttributes::getAbstractSensorInfoInternal() const { +// TODO need some way to transform RLRAudioPropagation constructs to strings +#ifdef ESP_BUILD_WITH_AUDIO + return Cr::Utility::formatString("{}", getOutputDirectory()); +#else + return ""; +#endif +} // AudioSensorAttributes::getAbstractSensorInfoInternal + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/AudioSensorAttributes.h b/src/esp/metadata/attributes/AudioSensorAttributes.h new file mode 100644 index 0000000000..718fc3edad --- /dev/null +++ b/src/esp/metadata/attributes/AudioSensorAttributes.h @@ -0,0 +1,106 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_AUDIOSENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_AUDIOSENSORATTRIBUTES_H_ + +#include "AbstractSensorAttributes.h" + +#ifdef ESP_BUILD_WITH_AUDIO +#include "rlr-audio-propagation/RLRAudioPropagationPkg/headers/RLRAudioPropagation.h" +#endif // ESP_BUILD_WITH_AUDIO + +namespace esp { +namespace metadata { +namespace attributes { + +/** + * @brief Class to support creating audio sensors + */ +class AudioSensorAttributes : public AbstractSensorAttributes { + public: + explicit AudioSensorAttributes(const std::string& handle = ""); + + /** + * @brief Populate this audio attributes from an appropriate @ref sensor::AudioSensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec( + const std::shared_ptr& spec) override; + +#ifdef ESP_BUILD_WITH_AUDIO + private: + RLRAudioPropagation::Configuration acousticsConfig_; + RLRAudioPropagation::ChannelLayout channelLayout_; + + public: + /** + * @brief Set the output directory + */ + void setOutputDirectory(const std::string& output_directory) { + set("output_directory", output_directory); + } + + /** + * @brief Get the output directory + */ + std::string getOutputDirectory() const { + return get("output_directory"); + } + + /** + * @brief Sets the acoustics configuration. + */ + void setAcousticsConfig( + const RLRAudioPropagation::Configuration& acousticsConfig) { + acousticsConfig_ = acousticsConfig; + } + /** + * @brief Gets the acoustics configuration. + */ + RLRAudioPropagation::Configuration getAcousticsConfig() const { + return acousticsConfig_; + } + /** + * @brief Sets the acoustic channel layout. + */ + void setChannelLayout( + const RLRAudioPropagation::ChannelLayout& channelLayout) { + channelLayout_ = channelLayout; + } + /** + * @brief Gets the acoustic channel layout. + */ + RLRAudioPropagation::ChannelLayout getChannelLayout() const { + return channelLayout_; + } + +#endif // ESP_BUILD_WITH_AUDIO + + protected: + /** + * @brief Write Audio Sensor-specific values to json object + */ + void writeValuesToJsonInternal(io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + /** + * @brief get AbstractSensorAttributes-specific info header + */ + std::string getAbstractSensorInfoHeaderInternal() const override; + /** + * @brief get AbstractObject specific info for csv string + */ + std::string getAbstractSensorInfoInternal() const override; + + public: + ESP_SMART_POINTERS(AudioSensorAttributes) +}; // class AudioSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_AUDIOSENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/attributes/CameraSensorAttributes.cpp b/src/esp/metadata/attributes/CameraSensorAttributes.cpp new file mode 100644 index 0000000000..d5369fb1b8 --- /dev/null +++ b/src/esp/metadata/attributes/CameraSensorAttributes.cpp @@ -0,0 +1,54 @@ + +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "CameraSensorAttributes.h" +#include "esp/sensor/CameraSensor.h" + +using Magnum::Math::Literals::operator""_degf; + +namespace esp { +namespace metadata { +namespace attributes { + +CameraSensorAttributes::CameraSensorAttributes(const std::string& handle) + : AbstractVisualSensorAttributes("CameraSensorAttributes", handle) { + init("hfov", 90.0_degf); + init("ortho_scale", 0.1f); +} // CameraSensorAttributes ctor + +void CameraSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Parent class version + AbstractVisualSensorAttributes::populateWithSensorSpec(spec); + // Appropriately cast to get camera spec data if exists + const esp::sensor::CameraSensorSpec::ptr& cameraSpec = + std::dynamic_pointer_cast(spec); + setHFOV(cameraSpec->hfov); + setOrthoScale(cameraSpec->orthoScale); +} // CameraSensorAttributes::populateWithSensorSpec +void CameraSensorAttributes::writeVisualSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // write CameraSensorAttributes values to json + writeValueToJson("hfov", jsonObj, allocator); + writeValueToJson("ortho_scale", jsonObj, allocator); + +} // CameraSensorAttributes::writeVisualSensorValuesToJsonInternal + +std::string CameraSensorAttributes::getAbstractVisualSensorInfoHeaderInternal() + const { + return "Horizontal FOV,Orthographic Scale,"; +} // CameraSensorAttributes::getAbstractVisualSensorInfoHeaderInternal() + +std::string CameraSensorAttributes::getAbstractVisualSensorInfoInternal() + const { + return Cr::Utility::formatString("{},{}", getAsString("hfov"), + getAsString("ortho_scale")); + +} // CameraSensorAttributes::getAbstractVisualSensorInfoInternal + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/CameraSensorAttributes.h b/src/esp/metadata/attributes/CameraSensorAttributes.h new file mode 100644 index 0000000000..9b9cef8321 --- /dev/null +++ b/src/esp/metadata/attributes/CameraSensorAttributes.h @@ -0,0 +1,79 @@ + +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_CAMERASENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_CAMERASENSORATTRIBUTES_H_ + +#include "AbstractVisualSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { + +/** + * @brief Class to suppoort creating camera sensors + */ +class CameraSensorAttributes : public AbstractVisualSensorAttributes { + public: + explicit CameraSensorAttributes(const std::string& handle = ""); + + /** + * @brief Populate this CameraSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + /** + * @brief Set the horizontal Field of View (in degrees) for the CameraSensor + * built by this attributes. + */ + void setHFOV(Magnum::Deg hfov) { set("hfov", hfov); } + /** + * @brief Get the horizontal Field of View (in degrees) for the CameraSensor + * built by this attributes. + */ + Magnum::Deg getHFOV() const { return get("hfov"); } + + /** + * @brief Set the orthographic scale for the CameraSensor built by this + * attributes. + */ + void setOrthoScale(float ortho_scale) { set("ortho_scale", ortho_scale); } + + /** + * @brief Get the orthographic scale for the CameraSensor built by this + * attributes. + */ + float getOrthoScale() const { + return static_cast(get("ortho_scale")); + } + + protected: + /** + * @brief Write Camera Sensor-specific values to json object + */ + void writeVisualSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + /** + * @brief get CameraSensorAttributes-specific info header + */ + std::string getAbstractVisualSensorInfoHeaderInternal() const override; + + /** + * @brief get CameraSensorAttributes specific info for csv string + */ + std::string getAbstractVisualSensorInfoInternal() const override; + + public: + ESP_SMART_POINTERS(CameraSensorAttributes) +}; // class CameraSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_CAMERASENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/attributes/CubeMapSensorAttributes.cpp b/src/esp/metadata/attributes/CubeMapSensorAttributes.cpp new file mode 100644 index 0000000000..7194eacc96 --- /dev/null +++ b/src/esp/metadata/attributes/CubeMapSensorAttributes.cpp @@ -0,0 +1,153 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "CubeMapSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { +AbstractCubeMapSensorAttributes::AbstractCubeMapSensorAttributes( + const std::string& classKey, + const std::string& handle) + : AbstractVisualSensorAttributes(classKey, handle) { + setHidden("__useSpecifiedCubeMapSize", false); + // Replacing nullopt field - 0 means to ignore + init("cubemap_size", 0); +} // AbstractCubeMapSensorAttributes ctor + +void AbstractCubeMapSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Parent class version + AbstractVisualSensorAttributes::populateWithSensorSpec(spec); + // Appropriately cast to get camera spec data if exists + const esp::sensor::CubeMapSensorBaseSpec::ptr& cubemapSpec = + std::dynamic_pointer_cast(spec); + if (cubemapSpec->cubemapSize != Cr::Containers::NullOpt) { + // automatically sets useSpecifiedCubeMapSize boolean to true + setCubeMapSize(*cubemapSpec->cubemapSize); + } +} // AbstractCubeMapSensorAttributes::populateWithSensorSpec + +void AbstractCubeMapSensorAttributes::writeVisualSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // write AbstractCubeMapSensorAttributes values to json + if (getUseSpecifiedCubeMapSize()) { + // Only write if actually specified by user input + writeValueToJson("cubemap_size", jsonObj, allocator); + } + // call child-class specific + writeCubeMapSensorValuesToJsonInternal(jsonObj, allocator); +} // AbstractCubeMapSensorAttributes::writeVisualSensorValuesToJsonInternal + +std::string +AbstractCubeMapSensorAttributes::getAbstractVisualSensorInfoHeaderInternal() + const { + return "User-specified CubeMap Size (0 : use min dim of resolution)" + + getCubeMapSensorInfoHeaderInternal(); +} // AbstractCubeMapSensorAttributes::getAbstractVisualSensorInfoHeaderInternal() + +std::string +AbstractCubeMapSensorAttributes::getAbstractVisualSensorInfoInternal() const { + return Cr::Utility::formatString("{},{}", getAsString("cubemap_size"), + getCubeMapSensorInfoInternal()); +} // AbstractCubeMapSensorAttributes::getAbstractVisualSensorInfoInternal + +/////////////////////////////////// +// Equirectangular CubeMap + +EquirectangularSensorAttributes::EquirectangularSensorAttributes( + const std::string& handle) + : AbstractCubeMapSensorAttributes("EquirectangularSensorAttributes", + handle) { +} // EquirectangularSensorAttributes ctor + +void EquirectangularSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Parent class version + AbstractCubeMapSensorAttributes::populateWithSensorSpec(spec); + // Appropriately cast to get EquirectangularSensorAttributes-specific spec + // data if exists + // No EquirectangularSensorAttributes-specific data +} // EquirectangularSensorAttributes::populateWithSensorSpec + +void EquirectangularSensorAttributes::writeCubeMapSensorValuesToJsonInternal( + CORRADE_UNUSED io::JsonGenericValue& jsonObj, + CORRADE_UNUSED io::JsonAllocator& allocator) const { + // Currently no EquirectangularSensor-specific attributes to write +} // EquirectangularSensorAttributes::writeCubeMapSensorValuesToJsonInternal + +std::string +EquirectangularSensorAttributes::getCubeMapSensorInfoHeaderInternal() const { + return ""; +} // EquirectangularSensorAttributes::getCubeMapSensorInfoHeaderInternal() + +std::string EquirectangularSensorAttributes::getCubeMapSensorInfoInternal() + const { + return ""; +} // EquirectangularSensorAttributes::getCubeMapSensorInfoInternal() + +/////////////////////////////////// +// Fisheye CubeMap + +FisheyeSensorAttributes::FisheyeSensorAttributes(const std::string& handle) + : AbstractCubeMapSensorAttributes("FisheyeSensorAttributes", handle) { + // init double-sphere model-specific values + init("ds_alpha", 0.59f); + init("ds_xi", -0.18f); + // TODO not a legal assignment - focal length needs to be positive in both + // fields + init("focal_length", Magnum::Vector2(0.01, 0.01)); + setHidden("__useSpecifiedPPO", false); + init("principle_point_offset", Magnum::Vector2(0.0, 0.0)); +} // FisheyeSensorAttributes ctor + +void FisheyeSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Parent class version + AbstractCubeMapSensorAttributes::populateWithSensorSpec(spec); + // Appropriately cast to get FisheyeSensorDoubleSphereSpec-spec data if exists + const esp::sensor::FisheyeSensorDoubleSphereSpec::ptr& fisheyeDSSpec = + std::dynamic_pointer_cast( + spec); + setFocalLength(fisheyeDSSpec->focalLength); + if (fisheyeDSSpec->principalPointOffset != Cr::Containers::NullOpt) { + setPrincipalPointOffset(*fisheyeDSSpec->principalPointOffset); + } + setDoubleSphereXi(fisheyeDSSpec->xi); + setDoubleSphereAlpha(fisheyeDSSpec->alpha); + // Currently no other Fisheye algorithm is implemented + +} // FisheyeSensorAttributes::populateWithSensorSpec + +void FisheyeSensorAttributes::writeCubeMapSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const { + // Write fisheye-sensor-specific values to json + writeValueToJson("ds_alpha", jsonObj, allocator); + writeValueToJson("ds_xi", jsonObj, allocator); + writeValueToJson("focal_length", jsonObj, allocator); + if (getUsePrincipalPointOffset()) { + writeValueToJson("principle_point_offset", jsonObj, allocator); + } + +} // FisheyeSensorAttributes::writeCubeMapSensorValuesToJsonInternal + +std::string FisheyeSensorAttributes::getCubeMapSensorInfoHeaderInternal() + const { + return "Focal Length fx fy,Use PPO,Principal Point Offset,Alpha " + "(double-sphere model),Xi (double-sphere model)"; +} // FisheyeSensorAttributes::getCubeMapSensorInfoHeaderInternal() + +std::string FisheyeSensorAttributes::getCubeMapSensorInfoInternal() const { + return Cr::Utility::formatString( + "{},{},{},{},{}", getAsString("focal_length"), + getAsString("use_specified_ppo"), getAsString("principle_point_offset"), + getAsString("ds_alpha"), getAsString("ds_xi")); + +} // FisheyeSensorAttributes::getCubeMapSensorInfoInternal() + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/CubeMapSensorAttributes.h b/src/esp/metadata/attributes/CubeMapSensorAttributes.h new file mode 100644 index 0000000000..dece93f913 --- /dev/null +++ b/src/esp/metadata/attributes/CubeMapSensorAttributes.h @@ -0,0 +1,305 @@ + +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_ABSTRACTCUBEMAPSENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_ABSTRACTCUBEMAPSENSORATTRIBUTES_H_ + +#include "AbstractVisualSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { +class AbstractCubeMapSensorAttributes : public AbstractVisualSensorAttributes { + public: + /** + * @brief Class to suppoort creating CubeMap-based sensors by providing common + * attributes. + */ + AbstractCubeMapSensorAttributes(const std::string& classKey, + const std::string& handle); + + /** + * @brief Populate this AbstractCubeMapSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + + /** + * @brief Set whether to use a user-specified CubeMap size. Otherwise, should + * be the smallest of the x or y resolution values. + */ + void setUseSpecifiedCubeMapSize(bool _useCubeMapSize) { + setHidden("__useSpecifiedCubeMapSize", _useCubeMapSize); + } + /** + * @brief Get whether to use a user-specified CubeMap size. Otherwise, should + * be the smallest of the x or y resolution values. + */ + bool getUseSpecifiedCubeMapSize() const { + return get("__useSpecifiedCubeMapSize"); + } + + /** + * @brief Set user-specified CubeMap Size. 0 means ignore this field and use + * the min dimension of the resolution as the size + */ + void setCubeMapSize(int cubemap_size) { + set("cubemap_size", cubemap_size); + setUseSpecifiedCubeMapSize(true); + } + + void clearCubeMapSize() { + set("cubemap_size", 0); + setUseSpecifiedCubeMapSize(false); + } + + /** + * @brief Get user-specified CubeMap Size. 0 means ignore this field and use + * the max dimension of the resolution as the size + */ + int getCubeMapSize() const { return get("cubemap_size"); } + + /** + * @brief Get the actual cube map size to use when constructing the cube map - + * either the user's specified value or the minimum resolution dimension. This + * should not be saved, and is just offered as a convenience accessor. + */ + int getCubeMapSizeToUse() const { + if (getUseSpecifiedCubeMapSize()) { + return get("cubemap_size"); + } + // If no cubemap size is specified, use the minimum resolution dimension + return getResolution().min(); + } + + protected: + /** + * @brief Write CubeMap Sensor-specific values to json object + */ + void writeVisualSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + virtual void writeCubeMapSensorValuesToJsonInternal( + CORRADE_UNUSED io::JsonGenericValue& jsonObj, + CORRADE_UNUSED io::JsonAllocator& allocator) const {}; + /** + * @brief get AbstractCubeMapSensorAttributes-specific info header + */ + std::string getAbstractVisualSensorInfoHeaderInternal() const override; + + /** + * @brief get AbstractCubeMapSensorAttributes specific info for csv string + */ + std::string getAbstractVisualSensorInfoInternal() const override; + + /** + * @brief get AbstractCubeMapSensorAttributes-child class info header + */ + virtual std::string getCubeMapSensorInfoHeaderInternal() const { return ""; } + + /** + * @brief get AbstractCubeMapSensorAttributes-child class info for csv string + */ + virtual std::string getCubeMapSensorInfoInternal() const { return ""; }; + + public: + ESP_SMART_POINTERS(AbstractCubeMapSensorAttributes) + +}; // class AbstractCubeMapSensorAttributes + +// AbstractCubeMapSensorAttributes Child classes + +/** + * @brief Class holding attributes for CubeMap-based Equirectangular sensor + */ +class EquirectangularSensorAttributes : public AbstractCubeMapSensorAttributes { + public: + explicit EquirectangularSensorAttributes(const std::string& handle = ""); + /** + * @brief Populate this EquirectangularSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + + protected: + /** + * @brief Write EquirectangularSensorAttributes Sensor-specific values to json + * object + */ + void writeCubeMapSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + /** + * @brief get EquirectangularSensorAttributes-specific info header + */ + std::string getCubeMapSensorInfoHeaderInternal() const override; + + /** + * @brief get EquirectangularSensorAttributes specific info for csv string + */ + std::string getCubeMapSensorInfoInternal() const override; + + public: + ESP_SMART_POINTERS(EquirectangularSensorAttributes) +}; // class EquirectangularSensorAttributes + +/** + * @brief Class holding attributes for CubeMap-based Fisheye sensor + */ +class FisheyeSensorAttributes : public AbstractCubeMapSensorAttributes { + public: + explicit FisheyeSensorAttributes(const std::string& handle = ""); + /** + * @brief Populate this FisheyeSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + /** + * @brief Set the fisheye sensor focal length, fx, fy, the distance between + * the pinhole and the image plane. In practice, fx and fy can differ for a + * number of reasons. See details here: + * http://ksimek.github.io/2013/08/13/intrinsic/ + * Both values must be positive to be legal + */ + void setFocalLength(const Magnum::Vector2& focal_length) { + set("focal_length", focal_length); + } + + /** + * @brief Get the fisheye sensor focal length, fx, fy, the distance between + * the pinhole and the image plane. In practice, fx and fy can differ for a + * number of reasons. See details here: + * http://ksimek.github.io/2013/08/13/intrinsic/ + * Both values must be positive to be legal + */ + Magnum::Vector2 getFocalLength() const { + return get("focal_length"); + } + + /** + * @brief Set whether to use specified Principal Point Offset. If false, the + * Principle Point Offset will be placed in the middle of the image. + */ + void setUsePrincipalPointOffset(bool use_specified_ppo) { + setHidden("__useSpecifiedPPO", use_specified_ppo); + } + /** + * @brief Get whether to use specified Principal Point Offset. If false, the + * Principle Point Offset will be placed in the middle of the image. + */ + bool getUsePrincipalPointOffset() const { + return get("__useSpecifiedPPO"); + } + + /** + * @brief Set the Principal Point Offset in pixel, cx, cy, location of the + * principal point relative to the image plane's origin. + */ + void setPrincipalPointOffset(const Magnum::Vector2& principle_point_offset) { + // TODO both values should always be > 0 + set("principle_point_offset", principle_point_offset); + setUsePrincipalPointOffset(true); + } + + /** + * @brief Clear out any specified Principal Point Offsets that might have been + * set. + */ + void clearPrincipalPointOffset() { + set("principle_point_offset", Magnum::Vector2(0.0, 0.0)); + setUsePrincipalPointOffset(false); + } + /** + * @brief Get the Principal Point Offset - the pixel, cx, cy, location of the + * principal point relative to the image plane's origin. If not specified use + * center of the sensor image. + */ + Magnum::Vector2 getPrincipalPointOffset() const { + return get("principle_point_offset"); + } + /** + * @brief Get the Actual Principal Point Offset to use; pixel, cx, cy, + * location of the principal point relative to the image plane's origin. This + * value is what should be used to create the sensor - if not specified, use + * the halfway point of the resolution specified (i.e. the center of the + * sensor image). + */ + Magnum::Vector2 getPrincipalPointOffsetToUse() const { + if (getUsePrincipalPointOffset()) { + return get("principle_point_offset"); + } + // If not specified then should be center of given resolution + return Magnum::Vector2(getResolution()) * 0.5; + } + + /** + * @brief Set the alpha value specifiec to the "double sphere" fisheye camera + * model. see details (value ranges) in: Vladyslav Usenko, Nikolaus Demmel and + * Daniel Cremers: The Double Sphere Camera Model, The International + * Conference on 3D Vision (3DV), 2018 + */ + void setDoubleSphereAlpha(float ds_alpha) { set("ds_alpha", ds_alpha); } + + /** + * @brief Get the alpha value specifiec to the "double sphere" fisheye camera + * model. see details (value ranges) in: Vladyslav Usenko, Nikolaus Demmel and + * Daniel Cremers: The Double Sphere Camera Model, The International + * Conference on 3D Vision (3DV), 2018 + */ + float getDoubleSphereAlpha() const { + return static_cast(get("ds_alpha")); + } + + /** + * @brief Set the xi value specifiec to the "double sphere" fisheye camera + * model. see details (value ranges) in: Vladyslav Usenko, Nikolaus Demmel and + * Daniel Cremers: The Double Sphere Camera Model, The International + * Conference on 3D Vision (3DV), 2018 + */ + void setDoubleSphereXi(float ds_xi) { set("ds_xi", ds_xi); } + + /** + * @brief Get the xi value specifiec to the "double sphere" fisheye camera + * model. see details (value ranges) in: Vladyslav Usenko, Nikolaus Demmel and + * Daniel Cremers: The Double Sphere Camera Model, The International + * Conference on 3D Vision (3DV), 2018 + */ + float getDoubleSphereXi() const { + return static_cast(get("ds_xi")); + } + + protected: + /** + * @brief Write FisheyeSensorAttributes Sensor-specific values to json + * object + */ + void writeCubeMapSensorValuesToJsonInternal( + io::JsonGenericValue& jsonObj, + io::JsonAllocator& allocator) const override; + + /** + * @brief get FisheyeSensorAttributes-specific info header + */ + std::string getCubeMapSensorInfoHeaderInternal() const override; + + /** + * @brief get FisheyeSensorAttributes specific info for csv string + */ + std::string getCubeMapSensorInfoInternal() const override; + + public: + ESP_SMART_POINTERS(FisheyeSensorAttributes) +}; // class FisheyeSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_ABSTRACTCUBEMAPSENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/attributes/CustomSensorAttributes.cpp b/src/esp/metadata/attributes/CustomSensorAttributes.cpp new file mode 100644 index 0000000000..749052f84b --- /dev/null +++ b/src/esp/metadata/attributes/CustomSensorAttributes.cpp @@ -0,0 +1,51 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#include "CustomSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { + +CustomSensorAttributes::CustomSensorAttributes(const std::string& handle) + : AbstractSensorAttributes("CustomSensorAttributes", handle) { + addOrEditSubgroup("custom_attributes"); +} // CustomSensorAttributes ctor + +void CustomSensorAttributes::populateWithSensorSpec( + const sensor::SensorSpec::ptr& spec) { + // Call Base class version + AbstractSensorAttributes::populateWithSensorSpec(spec); + // TODO handle setting custom_attributes subconfig with any values in spec + // beyond base values. + // std::shared_ptr custAttrs = editCustomAttrFields(); + // put values in custAttrs directly +} // CustomSensorAttributes::populateWithSensorSpec +std::string CustomSensorAttributes::getAbstractSensorInfoHeaderInternal() + const { + // get every key from custom attributes + const std::vector sortedKeys = + getCustomAttrFieldsView()->getKeys(true); + std::string res = ""; + for (const std::string& key : sortedKeys) { + Cr::Utility::formatInto(res, res.size(), "{},", key); + } + return res; +} // CustomSensorAttributes::getObjectInfoHeaderInternal + +std::string CustomSensorAttributes::getAbstractSensorInfoInternal() const { + std::shared_ptr custAttrs = getCustomAttrFieldsView(); + // get every key from custom attributes + const std::vector sortedKeys = custAttrs->getKeys(true); + std::string res = ""; + for (const std::string& key : sortedKeys) { + Cr::Utility::formatInto(res, res.size(), "{},", + custAttrs->getAsString(key)); + } + return res; +} // CustomSensorAttributes::getObjectInfoInternal + +} // namespace attributes +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/attributes/CustomSensorAttributes.h b/src/esp/metadata/attributes/CustomSensorAttributes.h new file mode 100644 index 0000000000..ef2e08016c --- /dev/null +++ b/src/esp/metadata/attributes/CustomSensorAttributes.h @@ -0,0 +1,105 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_ATTRIBUTES_CUSTOMSENSORATTRIBUTES_H_ +#define ESP_METADATA_ATTRIBUTES_CUSTOMSENSORATTRIBUTES_H_ + +#include "AbstractSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace attributes { + +/** + * @brief Class to support creating custom sensors via python that will be + * managed in Sim. + */ +class CustomSensorAttributes : public AbstractSensorAttributes { + public: + explicit CustomSensorAttributes(const std::string& handle = ""); + + /** + * @brief Populate this CustomSensorAttributes from an appropriate @ref sensor::SensorSpec. + * @todo Remove when SensorSpecs are removed + * + */ + void populateWithSensorSpec(const sensor::SensorSpec::ptr& spec) override; + + /** + * @brief Gets a smart pointer reference to a copy of the custom attributes + * configuration data from config file. Habitat does not parse or process this + * data, but it will be available to the user via python bindings for each + * object. + */ + std::shared_ptr getCustomAttrFields() const { + return getSubconfigCopy("custom_attributes"); + } + + /** + * @brief Gets a const smart pointer reference to a view of the custom + * attributes configuration data from config file. Habitat does not parse or + * process this data, but it will be available to the user via python bindings + * for each object. + */ + std::shared_ptr getCustomAttrFieldsView() const { + return getSubconfigView("custom_attributes"); + } + + /** + * @brief Gets a smart pointer reference to the actual custom attributes + * configuration data from config file. Habitat does not parse or process this + * data, but it will be available to the user via python bindings for each + * object. This method is for editing the configuration. + */ + std::shared_ptr editCustomAttrFields() { + return editSubconfig("custom_attributes"); + } + + /** + * @brief Move an existing custom_attributes subconfiguration into this + * configuration, overwriting the existing copy if it exists. Habitat does not + * parse or process this data, but it will be available to the user via python + * bindings for each object. This method is for editing the configuration. + */ + void setCustomAttrFields(std::shared_ptr& custAttrs) { + setSubconfigPtr("custom_attributes", custAttrs); + } + + /** + * @brief Returns the number of custom attributes values (within the + * "custom_attributes" sub-Configuration) this attributes has. + */ + int getNumCustomAttrFields() const { + return getSubconfigNumEntries("custom_attributes"); + } + + /** + * @brief Returns the number of custom attributes values and subconfig values + * (recursive) (within the "custom_attributes" sub-Configuration) this + * attributes has in its entire tree. + */ + int getTotalNumCustomAttrFields() const { + return getSubconfigTreeNumEntries("custom_attributes"); + } + + protected: + /** + * @brief get AbstractSensorAttributes-specific info header + */ + std::string getAbstractSensorInfoHeaderInternal() const override; + + /** + * @brief get AbstractSensorAttributes specific info for csv string + */ + std::string getAbstractSensorInfoInternal() const override; + + public: + ESP_SMART_POINTERS(CustomSensorAttributes) +}; // class CustomSensorAttributes + +} // namespace attributes +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_ATTRIBUTES_CUSTOMSENSORATTRIBUTES_H_ diff --git a/src/esp/metadata/managers/AssetAttributesManager.h b/src/esp/metadata/managers/AssetAttributesManager.h index 75bd106828..3274ab0f32 100644 --- a/src/esp/metadata/managers/AssetAttributesManager.h +++ b/src/esp/metadata/managers/AssetAttributesManager.h @@ -555,6 +555,11 @@ class AssetAttributesManager */ template attributes::AbstractPrimitiveAttributes::ptr createPrimAttributes() { + static_assert( + std::is_base_of::value, + "AbstractPrimitiveAttributes must be base class of desired " + "PrimitiveAttributes class."); + if (primitiveType == PrimObjTypes::END_PRIM_OBJ_TYPES) { ESP_ERROR() << "Cannot instantiate " "attributes::AbstractPrimitiveAttributes object for " diff --git a/src/esp/metadata/managers/SemanticAttributesManager.h b/src/esp/metadata/managers/SemanticAttributesManager.h index 76d3e9adf1..de649f69be 100644 --- a/src/esp/metadata/managers/SemanticAttributesManager.h +++ b/src/esp/metadata/managers/SemanticAttributesManager.h @@ -148,7 +148,7 @@ class SemanticAttributesManager */ core::managedContainers::ManagedObjectPreregistration preRegisterObjectFinalize(attributes::SemanticAttributes::ptr object, - const std::string& objectHandle, + CORRADE_UNUSED const std::string& objectHandle, CORRADE_UNUSED bool forceRegistration) override; /** diff --git a/src/esp/metadata/managers/SensorAttributesManager.cpp b/src/esp/metadata/managers/SensorAttributesManager.cpp new file mode 100644 index 0000000000..6df662eac3 --- /dev/null +++ b/src/esp/metadata/managers/SensorAttributesManager.cpp @@ -0,0 +1,259 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. +#include "SensorAttributesManager.h" + +#include "esp/metadata/attributes/AbstractSensorAttributes.h" +#include "esp/metadata/attributes/AudioSensorAttributes.h" +#include "esp/metadata/attributes/CameraSensorAttributes.h" +#include "esp/metadata/attributes/CubeMapSensorAttributes.h" +#include "esp/metadata/attributes/CustomSensorAttributes.h" + +namespace esp { +namespace metadata { +using attributes::AbstractSensorAttributes; +namespace managers { + +const std::map + SensorAttributesManager::SenssorAttrsTypeNamesMap = { + {sensor::SensorSubType::Unspecified, ""}, + {sensor::SensorSubType::Custom, "CustomSensorAttributes"}, + {sensor::SensorSubType::Pinhole, "CameraSensorAttributes"}, + {sensor::SensorSubType::Orthographic, "CameraSensorAttributes"}, + {sensor::SensorSubType::Equirectangular, + "EquirectangularSensorAttributes"}, + {sensor::SensorSubType::ImpulseResponse, "AudioSensorAttributes"}, + {sensor::SensorSubType::Fisheye, "FisheyeSensorAttributes"}, + {sensor::SensorSubType::EndSensorSubType, ""}}; + +SensorAttributesManager::SensorAttributesManager() + : AbstractAttributesManager:: + AbstractAttributesManager("Sensor Attributes", "sensor_config.json") { + // create constructor maps for various types of sensors mapping to their + // attributes + sensorTypeConstructorMap_["AudioSensorAttributes"] = + &SensorAttributesManager::createSensorAttributes< + attributes::AudioSensorAttributes>; + sensorTypeConstructorMap_["CameraSensorAttributes"] = + &SensorAttributesManager::createSensorAttributes< + attributes::CameraSensorAttributes>; + sensorTypeConstructorMap_["CustomSensorAttributes"] = + &SensorAttributesManager::createSensorAttributes< + attributes::CustomSensorAttributes>; + sensorTypeConstructorMap_["EquirectangularSensorAttributes"] = + &SensorAttributesManager::createSensorAttributes< + attributes::EquirectangularSensorAttributes>; + sensorTypeConstructorMap_["FisheyeSensorAttributes"] = + &SensorAttributesManager::createSensorAttributes< + attributes::FisheyeSensorAttributes>; + + // create copy constructor map entries for each type of Sensor Attributes + this->copyConstructorMap_["AudioSensorAttributes"] = + &SensorAttributesManager::createObjCopyCtorMapEntry< + attributes::AudioSensorAttributes>; + this->copyConstructorMap_["CameraSensorAttributes"] = + &SensorAttributesManager::createObjCopyCtorMapEntry< + attributes::CameraSensorAttributes>; + this->copyConstructorMap_["CustomSensorAttributes"] = + &SensorAttributesManager::createObjCopyCtorMapEntry< + attributes::CustomSensorAttributes>; + this->copyConstructorMap_["EquirectangularSensorAttributes"] = + &SensorAttributesManager::createObjCopyCtorMapEntry< + attributes::EquirectangularSensorAttributes>; + this->copyConstructorMap_["FisheyeSensorAttributes"] = + &SensorAttributesManager::createObjCopyCtorMapEntry< + attributes::FisheyeSensorAttributes>; + +} // SensorAttributesManager ctor + +AbstractSensorAttributes::ptr +SensorAttributesManager::createAttributesFromSensorSpecInternal( + const sensor::SensorSpec::ptr& sensorSpec, + bool registerTemplate) { + // Get attributes class name from sensorSpec + const std::string& sensorAttrClassName = + SensorAttributesManager::SenssorAttrsTypeNamesMap.at( + sensorSpec->sensorSubType); + CORRADE_ASSERT(!sensorAttrClassName.empty(), + "Unknown SensorAttributes class for SensorSubType enum value :" + << static_cast(sensorSpec->sensorSubType), + nullptr); + // Build and initialize appropriate class of Attributes based on class name + auto sensorAttributes = + this->initNewObjectInternal(sensorAttrClassName, false); + // Populate attributes from sensorSpec + sensorAttributes->populateWithSensorSpec(sensorSpec); + // TODO : Rename attributes to appropriate name and register + // Build name using more than just spec uuid? + std::string newAttrHandle = sensorSpec->uuid; + // set handle appropriately to be registration key + sensorAttributes->setHandle(newAttrHandle); + + return this->postCreateRegister(std::move(sensorAttributes), + registerTemplate); +} // SensorAttributesManager::createAttributesFromSensorSpec + +AbstractSensorAttributes::ptr SensorAttributesManager::createObject( + const std::string& sensorFileName, + bool registerTemplate) { + auto sensorAttrs = this->createDefaultObject(sensorFileName, false); + if (nullptr == sensorAttrs) { + return sensorAttrs; + } + ESP_DEBUG(Mn::Debug::Flag::NoSpace) + << "Sensor attributes (" << sensorFileName << ":" + << sensorAttrs->getHandle() << ") created" + << (registerTemplate ? " and registered." : "."); + + // TODO : set handle appropriately to be registration key + + return this->postCreateRegister(std::move(sensorAttrs), registerTemplate); +} // SensorAttributesManager::createObject + +AbstractSensorAttributes::ptr SensorAttributesManager::buildObjectFromJSONDoc( + const std::string& filename, + const io::JsonGenericValue& jsonConfig) { + // Get sensor class type from jsonconfig, use this to determine class + // name to build + std::string tmpStrVal = ""; + // Look for sensor_subtype string value in json config + if (!io::readMember(jsonConfig, "sensor_subtype", tmpStrVal)) { + // Value not found in json so this is an error - we don't know what kind of + // sensor to create + return nullptr; + } + std::string strToLookFor = Cr::Utility::String::lowercase(tmpStrVal); + if (strToLookFor == "unspecified") { + // cannot instantiate unspecified sensor; error + ESP_ERROR(Mn::Debug::Flag::NoSpace) + << "Unable to determine Sensor Sub Type in JSON Config `" << filename + << "` so unable to build correct SensorAttributes. " + "Aborting."; + return nullptr; + } + auto found = attributes::SensorSubTypeNamesMap.find(strToLookFor); + if (found == attributes::SensorSubTypeNamesMap.end()) { + // string representation of enum value was not found in mappings; error + return nullptr; + } + // By here, legal sensor subtype is found + sensor::SensorSubType sensorSubType = found->second; + + const std::string& sensorAttrClassName = + SensorAttributesManager::SenssorAttrsTypeNamesMap.at(sensorSubType); + CORRADE_ASSERT(!sensorAttrClassName.empty(), + "Unknown SensorAttributes class for SensorSubType enum value :" + << static_cast(sensorSubType), + nullptr); + + // Build and initialize appropriate class of Attributes based on class name + auto sensorAttributes = + this->initNewObjectInternal(sensorAttrClassName, true); + if (nullptr == sensorAttributes) { + return sensorAttributes; + } + // This should never fail + this->setValsFromJSONDoc(sensorAttributes, jsonConfig); + return sensorAttributes; +} // SensorAttributesManager::buildObjectFromJSONDoc + +void SensorAttributesManager::setValsFromJSONDoc( + AbstractSensorAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) { + // TODO support loading values from JSON docs for each type of + // SensorAttributes. + // position of sensor + io::jsonIntoConstSetter( + jsonConfig, "position", [attribs](const Magnum::Vector3& position) { + attribs->setPosition(position); + }); + + // orientation + io::jsonIntoConstSetter( + jsonConfig, "orientation", [attribs](const Magnum::Vector3& orientation) { + attribs->setOrientation(orientation); + }); + + // noise model + io::jsonIntoConstSetter( + jsonConfig, "noise_model", [attribs](const std::string& noise_model) { + attribs->setNoiseModel(noise_model); + }); + + // sensor type + this->setEnumStringFromJsonDoc( + jsonConfig, "sensor_type", "SensorTypeNamesMap", false, + attributes::SensorTypeNamesMap, + [attribs](const std::string& val) { attribs->setSensorType(val); }); + + // sensor subtype + this->setEnumStringFromJsonDoc( + jsonConfig, "sensor_subtype", "SensorSubTypeNamesMap", false, + attributes::SensorSubTypeNamesMap, + [attribs](const std::string& val) { attribs->setSensorSubType(val); }); + + // TODO populate other types of sensor attributes from json + + // check for user defined attributes + this->parseUserDefinedJsonVals(attribs, jsonConfig); + +} // SensorAttributesManager::setValsFromJSONDoc + +AbstractSensorAttributes::ptr SensorAttributesManager::initNewObjectInternal( + const std::string& sensorAttrClassName, + bool builtFromConfig) { + // sensorAttrClassName is the class of the sensor attributes to build + // Instead of building the attributes using whatever name is passed into the + // create workflow, we use the sensorAttrClassName to determine which + // constructor to invoke. + + auto sensorTypeCtorIter = sensorTypeConstructorMap_.find(sensorAttrClassName); + if (sensorTypeCtorIter == sensorTypeConstructorMap_.end()) { + ESP_ERROR() + << "No sensor attributes class" << sensorAttrClassName + << "constructor exists in the sensorTypeConstructorMap, so unable to " + "create an appropriate new SensorAttributes object."; + return nullptr; + } + // these attributes ignore any default settings. + auto newAttributes = (*this.*sensorTypeCtorIter->second)(); + + if (builtFromConfig) { + ESP_VERY_VERBOSE(Mn::Debug::Flag::NoSpace) + << "New " << sensorAttrClassName + << " object created and inited from json"; + } else { + // Built from sensorspec + ESP_VERY_VERBOSE(Mn::Debug::Flag::NoSpace) + << "New " << sensorAttrClassName + << " object created and inited from SensorSpec"; + } + return newAttributes; +} // SensorAttributesManager::initNewObjectInternal + +core::managedContainers::ManagedObjectPreregistration +SensorAttributesManager::preRegisterObjectFinalize( + AbstractSensorAttributes::ptr sensorAttrs, + const std::string& sensorAttrsHandle, + CORRADE_UNUSED bool forceRegistration) { + // This method will verify syntax and uniqueness of given handle, and once it + // is verified, it will set the object's handle and use it as the registration + // key. + + // TODO: Verify attributes' field data. This should be done at Configuration + // level. + // Find first unique variant of given objectHandle. + const std::string newHandle = + this->getUniqueHandleFromCandidate(sensorAttrsHandle); + // Set handle to be first unique variant of given objectHandle + sensorAttrs->setHandle(newHandle); + // if this succeeds the registration should use the object's handle and not + // the given + return core::managedContainers::ManagedObjectPreregistration:: + Success_Use_Object_Handle; +} // SensorAttributesManager::preRegisterObjectFinalize + +} // namespace managers +} // namespace metadata +} // namespace esp diff --git a/src/esp/metadata/managers/SensorAttributesManager.h b/src/esp/metadata/managers/SensorAttributesManager.h new file mode 100644 index 0000000000..3c40bb58cc --- /dev/null +++ b/src/esp/metadata/managers/SensorAttributesManager.h @@ -0,0 +1,252 @@ +// Copyright (c) Meta Platforms, Inc. and its affiliates. +// This source code is licensed under the MIT license found in the +// LICENSE file in the root directory of this source tree. + +#ifndef ESP_METADATA_MANAGERS_SENSORATTRIBUTEMANAGER_H_ +#define ESP_METADATA_MANAGERS_SENSORATTRIBUTEMANAGER_H_ + +/** @file + * @brief Class Template @ref esp::metadata::managers::SensorAttributesManager + * This class manages attributes describing/configuring habitat sensors. + */ + +#include "AbstractAttributesManager.h" +#include "esp/metadata/attributes/AbstractSensorAttributes.h" +#include "esp/metadata/attributes/AudioSensorAttributes.h" +#include "esp/metadata/attributes/CameraSensorAttributes.h" +#include "esp/metadata/attributes/CubeMapSensorAttributes.h" +#include "esp/metadata/attributes/CustomSensorAttributes.h" + +namespace esp { +namespace metadata { +namespace managers { + +class SensorAttributesManager + : public AbstractAttributesManager { + public: + /** + * @brief Constant Map holding names of concrete SensorAttributes classes, + * keyed by SensorSubtype enum values used to denote them. + */ + static const std::map + SenssorAttrsTypeNamesMap; + SensorAttributesManager(); + + /** + * @brief Create an attributes from a SensorSpec. + * + * TODO : Once SensorSpecs are removed, this should be removed as well. + * + * @param sensorSpec The SensorSpec holding the values to use to create a + * sensor. + * @param registerTemplate whether to add this template to the library. + * If the user is going to edit this template, this should be false - any + * subsequent editing will require re-registration. Defaults to true. If + * specified as true, then this function returns a copy of the registered + * template. + * @return a reference to the desired template. + */ + + template + std::shared_ptr createAttributesFromSensorSpec( + const sensor::SensorSpec::ptr& sensorSpec, + bool registerTemplate = true) { + static_assert( + std::is_base_of::value, + "AbstractSensorAttributes must be the base type of the requested new " + "SensorSpec-based attributes"); + + attributes::AbstractSensorAttributes::ptr attrs = + this->createAttributesFromSensorSpecInternal(sensorSpec, + registerTemplate); + + return std::static_pointer_cast(attrs); + } + + /** + * @brief Should only be called internally. Creates an instance of a sensor + * attributes template described by the passed string. + * + * @param sensorClassName A string descriptor of the sensor attributes + * template to be created. + * @param registerTemplate whether to add this template to the library. + * If the user is going to edit this template, this should be false - any + * subsequent editing will require re-registration. Defaults to true. If + * specified as true, then this function returns a copy of the registered + * template. + * @return a reference to the desired template. + */ + + attributes::AbstractSensorAttributes::ptr createObject( + const std::string& sensorClassName, + bool registerTemplate = true) override; + + /** + * @brief Parse passed JSON Document specifically for @ref + * esp::metadata::attributes::AbstractSensorAttributes object. It always + * returns a valid @ref esp::metadata::attributes::AbstractSensorAttributes + * shared_ptr object. + * + * TODO : currently do not support file-based Sensor attributes. + * + * @param filename the name of the file describing the sensor attributes + * @param jsonConfig json document to parse + * @return a reference to the desired template. + */ + attributes::AbstractSensorAttributes::ptr buildObjectFromJSONDoc( + const std::string& filename, + const io::JsonGenericValue& jsonConfig) override; + + /** + * @brief Method to take an existing attributes and set its values from passed + * json config file. + * @param attribs (out) an existing attributes to be modified. + * @param jsonConfig json document to parse + */ + void setValsFromJSONDoc(attributes::AbstractSensorAttributes::ptr attribs, + const io::JsonGenericValue& jsonConfig) override; + + /** + * @brief This function will be called to finalize attributes' paths before + * registration, moving fully qualified paths to the appropriate hidden + * attribute fields. This can also be called without registration to make sure + * the paths specified in an attributes are properly configured. + * @param attributes The attributes to be filtered. + */ + void finalizeAttrPathsBeforeRegister( + CORRADE_UNUSED const attributes::AbstractSensorAttributes::ptr& + attributes) const override {} + + protected: + /** + * @brief Internal only. Create an attributes from a SensorSpec. + * + * TODO : Once SensorSpecs are removed, this should be removed as well. + * + * @param sensorSpec The SensorSpec holding the values to use to create a + * sensor. + * @param registerTemplate whether to add this template to the library. + * If the user is going to edit this template, this should be false - any + * subsequent editing will require re-registration. Defaults to true. If + * specified as true, then this function returns a copy of the registered + * template. + * @return a reference to the desired template. + */ + attributes::AbstractSensorAttributes::ptr + createAttributesFromSensorSpecInternal( + const sensor::SensorSpec::ptr& sensorSpec, + bool registerTemplate); + + /** + * @brief Used Internally. Create and configure newly-created attributes with + * any default values, before any specific values are set. + * + * @param handleName handle name to be assigned to attributes + * @param builtFromConfig Whether this AbstractSensorAttributes is being built + * from a config file (i.e. handleName is the name of a configuration file) or + * from some other source. + * @return Newly created but unregistered AbstractSensorAttributes pointer, + * with only default values set. + */ + attributes::AbstractSensorAttributes::ptr initNewObjectInternal( + const std::string& handleName, + bool builtFromConfig) override; + + /** + * @brief Build a shared pointer to the appropriate attributes for passed + * object type as defined in @ref PrimObjTypes, where each entry except @ref + * PrimObjTypes::END_PRIM_OBJ_TYPES corresponds to a Magnum Primitive type + */ + template + attributes::AbstractSensorAttributes::ptr createSensorAttributes() { + static_assert( + std::is_base_of::value, + "AbstractSensorAttributes must be base class of desired " + "SensorAttributes class."); + return T::create(); + } // AssetAttributeManager::createPrimAttributes + + /** + * @brief This method will perform any necessary updating that is + * AbstractAttributesManager-specific upon template removal, such as removing + * a specific template handle from the list of file-based template handles in + * ObjectAttributesManager. This should only be called @ref + * esp::core::managedContainers::ManagedContainerBase. + * + * @param templateID the ID of the template to remove + * @param templateHandle the string key of the attributes desired. + */ + void deleteObjectInternalFinalize( + CORRADE_UNUSED int templateID, + CORRADE_UNUSED const std::string& templateHandle) override {} + + /** + * @brief This method will perform any essential updating to the managed + * object before registration is performed. If this updating fails, + * registration will also fail. In the case of SensorAttributes, it will + * verify the handle syntax and uniqueness. + * @param object the managed object to be registered + * @param objectHandle the name to register the managed object with. + * Expected to be valid. + * @param forceRegistration Should register object even if conditional + * registration checks fail. + * @return Whether the preregistration has succeeded and what handle to use to + * register the object if it has. + */ + core::managedContainers::ManagedObjectPreregistration + preRegisterObjectFinalize(attributes::AbstractSensorAttributes::ptr object, + const std::string& objectHandle, + CORRADE_UNUSED bool forceRegistration) override; + + /** + * @brief Not required for this manager. + * + * This method will perform any final manager-related handling after + * successfully registering an object. + * + * See @ref esp::attributes::managers::ObjectAttributesManager for an example. + * + * @param objectID the ID of the successfully registered managed object + * @param objectHandle The name of the managed object + */ + void postRegisterObjectHandling( + CORRADE_UNUSED int objectID, + CORRADE_UNUSED const std::string& objectHandle) override {} + + /** + * @brief Any AbstractSensorAttributes-attributes-specific resetting that + * needs to happen on ManagedContainerBase::reset(). + */ + void resetFinalize() override { + // build default attributes::AbstractSensorAttributes objects - reset does + // not remove constructor mappings. + } + + // ======== Typedefs and Instance Variables ======== + + /** + * @brief Define a map type referencing function pointers to @ref + * createSensorAttributes() keyed by esp::sensor::SensorSubType corresponding + * to sensor classes being instanced, + */ + typedef std::unordered_map + Map_Of_SensorTypeCtors; + + /** + * @brief Map of function pointers to instantiate a sennsor attributes + * object, + */ + Map_Of_SensorTypeCtors sensorTypeConstructorMap_; + + public: + ESP_SMART_POINTERS(SensorAttributesManager) +}; // class SensorAttributesManager + +} // namespace managers +} // namespace metadata +} // namespace esp + +#endif // ESP_METADATA_MANAGERS_SENSORATTRIBUTEMANAGER_H_ diff --git a/src/esp/sensor/AudioSensor.cpp b/src/esp/sensor/AudioSensor.cpp index 8bcfcac4c6..91afe8cb86 100644 --- a/src/esp/sensor/AudioSensor.cpp +++ b/src/esp/sensor/AudioSensor.cpp @@ -2,6 +2,7 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. +#include #include #include #include diff --git a/src/esp/sensor/AudioSensor.h b/src/esp/sensor/AudioSensor.h index 713f8b1ac8..f55a9db740 100644 --- a/src/esp/sensor/AudioSensor.h +++ b/src/esp/sensor/AudioSensor.h @@ -9,7 +9,6 @@ #include "esp/assets/MeshData.h" #include "esp/core/Esp.h" -#include "esp/scene/SemanticScene.h" #include "esp/sensor/Sensor.h" #ifdef ESP_BUILD_WITH_AUDIO diff --git a/src/esp/sensor/CubeMapSensorBase.cpp b/src/esp/sensor/CubeMapSensorBase.cpp index f74c0c6008..45f4f6ab59 100644 --- a/src/esp/sensor/CubeMapSensorBase.cpp +++ b/src/esp/sensor/CubeMapSensorBase.cpp @@ -16,7 +16,7 @@ namespace sensor { CubeMapSensorBaseSpec::CubeMapSensorBaseSpec() : VisualSensorSpec() { uuid = "cubemap_sensor_base"; - sensorSubType = SensorSubType::None; + sensorSubType = SensorSubType::Unspecified; } void CubeMapSensorBaseSpec::sanityCheck() const { diff --git a/src/esp/sensor/Sensor.cpp b/src/esp/sensor/Sensor.cpp index ad8d0e63eb..366c45ed9a 100644 --- a/src/esp/sensor/Sensor.cpp +++ b/src/esp/sensor/Sensor.cpp @@ -27,11 +27,11 @@ void SensorSpec::sanityCheck() const { // Check that all parameters are initialized to legal values CORRADE_ASSERT(!uuid.empty(), "SensorSpec::sanityCheck(): uuid cannot be an empty string", ); - CORRADE_ASSERT( - sensorType > SensorType::None && sensorType < SensorType::EndSensorType, - "SensorSpec::sanityCheck(): sensorType" << int32_t(sensorType) - << "is illegal", ); - CORRADE_ASSERT(sensorSubType > SensorSubType::None && + CORRADE_ASSERT(sensorType > SensorType::Unspecified && + sensorType < SensorType::EndSensorType, + "SensorSpec::sanityCheck(): sensorType" << int32_t(sensorType) + << "is illegal", ); + CORRADE_ASSERT(sensorSubType > SensorSubType::Unspecified && sensorSubType < SensorSubType::EndSensorSubType, "SensorSpec::sanityCheck(): sensorSubType" << int32_t(sensorType) << "is illegal", ); @@ -69,6 +69,15 @@ Sensor::~Sensor() { ESP_DEBUG() << "Deconstructing Sensor"; } +scene::SceneNode& Sensor::object() { + return static_cast( + Magnum::SceneGraph::AbstractFeature3D::object()); +} +const scene::SceneNode& Sensor::object() const { + return static_cast( + Magnum::SceneGraph::AbstractFeature3D::object()); +} + void Sensor::setTransformationFromSpec() { CORRADE_ASSERT(spec_, "Sensor::setTransformationFromSpec: Cannot set " @@ -85,6 +94,15 @@ void Sensor::setTransformationFromSpec() { SensorSuite::SensorSuite(scene::SceneNode& node) : Magnum::SceneGraph::AbstractFeature3D{node} {} +scene::SceneNode& SensorSuite::object() { + return static_cast( + Magnum::SceneGraph::AbstractFeature3D::object()); +} +const scene::SceneNode& SensorSuite::object() const { + return static_cast( + Magnum::SceneGraph::AbstractFeature3D::object()); +} + void SensorSuite::add(sensor::Sensor& sensor) { sensors_.emplace(sensor.specification()->uuid, std::ref(sensor)); } diff --git a/src/esp/sensor/Sensor.h b/src/esp/sensor/Sensor.h index 2d564f9710..80d279b635 100644 --- a/src/esp/sensor/Sensor.h +++ b/src/esp/sensor/Sensor.h @@ -5,14 +5,17 @@ #ifndef ESP_SENSOR_SENSOR_H_ #define ESP_SENSOR_SENSOR_H_ -#include "esp/scene/SceneNode.h" - +#include +#include #include "esp/core/Buffer.h" #include "esp/core/Esp.h" #include "esp/sensor/configure.h" namespace esp { +namespace scene { +class SceneNode; +} namespace sim { class Simulator; @@ -21,7 +24,8 @@ class Simulator; namespace sensor { // Enumeration of types of sensors enum class SensorType : int32_t { - None = 0, + Unspecified = 0, + Custom, Color, Depth, Normal, @@ -38,7 +42,8 @@ enum class ObservationSpaceType { }; enum class SensorSubType : int32_t { - None = 0, + Unspecified = 0, + Custom, Pinhole, Orthographic, Fisheye, @@ -51,8 +56,8 @@ enum class SensorSubType : int32_t { // User should make sure all uuids are unique struct SensorSpec { std::string uuid = ""; - SensorType sensorType = SensorType::None; - SensorSubType sensorSubType = SensorSubType::None; + SensorType sensorType = SensorType::Unspecified; + SensorSubType sensorSubType = SensorSubType::Unspecified; Magnum::Vector3 position = {0, 1.5, 0}; Magnum::Vector3 orientation = {0, 0, 0}; std::string noiseModel = "None"; @@ -91,14 +96,9 @@ class Sensor : public Magnum::SceneGraph::AbstractFeature3D { const scene::SceneNode& node() const { return object(); } // Overloads to avoid confusion - scene::SceneNode& object() { - return static_cast( - Magnum::SceneGraph::AbstractFeature3D::object()); - } - const scene::SceneNode& object() const { - return static_cast( - Magnum::SceneGraph::AbstractFeature3D::object()); - } + scene::SceneNode& object(); + const scene::SceneNode& object() const; + /** * @brief Return a pointer to this Sensor's SensorSpec */ @@ -167,14 +167,9 @@ class SensorSuite : public Magnum::SceneGraph::AbstractFeature3D { const scene::SceneNode& node() const { return object(); } // Overloads to avoid confusion - scene::SceneNode& object() { - return static_cast( - Magnum::SceneGraph::AbstractFeature3D::object()); - } - const scene::SceneNode& object() const { - return static_cast( - Magnum::SceneGraph::AbstractFeature3D::object()); - } + scene::SceneNode& object(); + + const scene::SceneNode& object() const; /** * @brief Add Sensor sensor to existing sensors_ with key sensor's uuid diff --git a/src/esp/sensor/SensorFactory.h b/src/esp/sensor/SensorFactory.h index 267c9091cb..420be63afd 100644 --- a/src/esp/sensor/SensorFactory.h +++ b/src/esp/sensor/SensorFactory.h @@ -2,7 +2,6 @@ // This source code is licensed under the MIT license found in the // LICENSE file in the root directory of this source tree. -#include "esp/scene/SceneNode.h" #include "esp/sensor/Sensor.h" namespace esp { diff --git a/src/tests/AttributesConfigsTest.cpp b/src/tests/AttributesConfigsTest.cpp index 97d8bb04f4..bad5b0334e 100644 --- a/src/tests/AttributesConfigsTest.cpp +++ b/src/tests/AttributesConfigsTest.cpp @@ -12,19 +12,38 @@ #include "esp/metadata/managers/ObjectAttributesManager.h" #include "esp/metadata/managers/PbrShaderAttributesManager.h" #include "esp/metadata/managers/PhysicsAttributesManager.h" +#include "esp/metadata/managers/SensorAttributesManager.h" #include "esp/metadata/managers/StageAttributesManager.h" #include "esp/physics/RigidBase.h" #include "configure.h" +// Remove once SensorSpecs are removed +#ifdef ESP_BUILD_WITH_AUDIO +#include "esp/sensor/AudioSensor.h" +#endif +#include "esp/sensor/CameraSensor.h" +#include "esp/sensor/EquirectangularSensor.h" +#include "esp/sensor/FisheyeSensor.h" + +#ifdef ESP_BUILD_WITH_AUDIO +using esp::sensor::AudioSensorSpec; +#endif +using esp::sensor::CameraSensorSpec; +using esp::sensor::EquirectangularSensorSpec; +using esp::sensor::FisheyeSensorDoubleSphereSpec; +using esp::sensor::SensorSpec; +// End SensorSpec remove + namespace Cr = Corrade; namespace Mn = Magnum; - -using Mn::Math::Literals::operator""_radf; namespace AttrMgrs = esp::metadata::managers; namespace Attrs = esp::metadata::attributes; +using Mn::Math::Literals::operator""_degf; +using Mn::Math::Literals::operator""_radf; + using esp::metadata::MetadataMediator; using esp::metadata::PrimObjTypes; @@ -32,6 +51,13 @@ using esp::physics::MotionType; using AttrMgrs::AbstractAttributesManager; using Attrs::ArticulatedObjectAttributes; +#ifdef ESP_BUILD_WITH_AUDIO +using Attrs::AudioSensorAttributes; +#endif +using Attrs::CameraSensorAttributes; +using Attrs::CustomSensorAttributes; +using Attrs::EquirectangularSensorAttributes; +using Attrs::FisheyeSensorAttributes; using Attrs::MarkerSets; using Attrs::ObjectAttributes; using Attrs::PbrShaderAttributes; @@ -127,6 +153,10 @@ struct AttributesConfigsTest : Cr::TestSuite::Tester { const AllMarkerSetsTestMap& // markers in link subset markerSetsInfoHierarchy); + ////////////////////////////// + // Test attributes values + // These tests validate passed attributes' values to what is expected. + /** * @brief This test will verify that the physics attributes' managers' JSON * loading process is working as expected. @@ -167,6 +197,50 @@ struct AttributesConfigsTest : Cr::TestSuite::Tester { void testSemanticAttrVals( std::shared_ptr semanticAttr, const std::string& assetPath); + + /** + * @brief This test will verify that the AudioSensorAttributes' will match + * expected values. + */ + +#ifdef ESP_BUILD_WITH_AUDIO + + void testAudioSensorAttrVals( + std::shared_ptr audioAttr, + const std::string& assetPath); +#endif + /** + * @brief This test will verify that the CameraSensorAttributes' will match + * expected values. + */ + void testCameraSensorAttrVals( + std::shared_ptr cameraAttr, + const std::string& assetPath); + + /** + * @brief This test will verify that the CustomSensorAttributes' will match + * expected values. + */ + void testCustomSensorAttrVals( + std::shared_ptr customAttr, + const std::string& assetPath); + + /** + * @brief This test will verify that the EquirectangularSensorAttributes' will + * match expected values. + */ + void testEquirectangularSensorAttrVals( + std::shared_ptr equirectAttr, + const std::string& assetPath); + + /** + * @brief This test will verify that the FisheyeSensorAttributes' will match + * expected values. + */ + void testFisheyeSensorAttrVals( + std::shared_ptr fisheyeAttr, + const std::string& assetPath); + /** * @brief This test will verify that the Stage attributes' managers' JSON * loading process is working as expected. @@ -200,6 +274,11 @@ struct AttributesConfigsTest : Cr::TestSuite::Tester { void testLightJSONLoad(); void testSceneInstanceJSONLoad(); void testSemanticJSONLoad(); + /** + * @brief Remove once SensorSpec is removed + */ + void testSensorAttrSpecLoad(); + void testSensorAttrJSONLoad(); void testStageJSONLoad(); void testObjectJSONLoad(); void testArticulatedObjectJSONLoad(); @@ -219,6 +298,8 @@ struct AttributesConfigsTest : Cr::TestSuite::Tester { sceneInstanceAttributesManager_ = nullptr; AttrMgrs::SemanticAttributesManager::ptr semanticAttributesManager_ = nullptr; + AttrMgrs::SensorAttributesManager::ptr sensorAttributesManager_ = nullptr; + AttrMgrs::StageAttributesManager::ptr stageAttributesManager_ = nullptr; }; // struct AttributesConfigsTest @@ -235,6 +316,7 @@ AttributesConfigsTest::AttributesConfigsTest() { pbrShaderAttributesManager_ = MM->getPbrShaderAttributesManager(); sceneInstanceAttributesManager_ = MM->getSceneInstanceAttributesManager(); semanticAttributesManager_ = MM->getSemanticAttributesManager(); + sensorAttributesManager_ = MM->getSensorAttributesManager(); stageAttributesManager_ = MM->getStageAttributesManager(); addTests({ @@ -242,7 +324,9 @@ AttributesConfigsTest::AttributesConfigsTest() { &AttributesConfigsTest::testPbrShaderAttrJSONLoad, &AttributesConfigsTest::testLightJSONLoad, &AttributesConfigsTest::testSceneInstanceJSONLoad, + &AttributesConfigsTest::testSensorAttrSpecLoad, &AttributesConfigsTest::testSemanticJSONLoad, + &AttributesConfigsTest::testSensorAttrJSONLoad, &AttributesConfigsTest::testStageJSONLoad, &AttributesConfigsTest::testObjectJSONLoad, &AttributesConfigsTest::testArticulatedObjectJSONLoad, @@ -1299,6 +1383,298 @@ void AttributesConfigsTest::testSemanticJSONLoad() { } // AttributesConfigsTest::testSemanticJSONLoad +#ifdef ESP_BUILD_WITH_AUDIO +void AttributesConfigsTest::testAudioSensorAttrVals( + std::shared_ptr audioAttr, + const std::string& assetPath) { + // match values to expected values in JSON or spec + CORRADE_COMPARE(audioAttr->getHandle(), "audio_sensor_handle_:0000"); + CORRADE_COMPARE(static_cast(audioAttr->getSensorType()), + static_cast(esp::sensor::SensorType::Audio)); + CORRADE_COMPARE( + static_cast(audioAttr->getSensorSubType()), + static_cast(esp::sensor::SensorSubType::ImpulseResponse)); + CORRADE_COMPARE(audioAttr->getPosition(), Mn::Vector3(1.5, 2.5, 3.5)); + CORRADE_COMPARE(audioAttr->getOrientation(), Mn::Vector3(1.0, 2.0, 3.0)); + CORRADE_COMPARE(audioAttr->getNoiseModel(), "audio_noise"); + CORRADE_COMPARE(audioAttr->getOutputDirectory(), "audio_sensor_output_dir"); + // TODO : + // Support user_defined attributes once being read from JSON +} // AttributesConfigsTest::testAudioSensorAttrVals +#endif // ESP_BUILD_WITH_AUDIO + +void AttributesConfigsTest::testCameraSensorAttrVals( + std::shared_ptr cameraAttr, + const std::string& assetPath) { + // base SensorSpec values + CORRADE_COMPARE(cameraAttr->getHandle(), "camera_sensor_handle_:0000"); + CORRADE_COMPARE(static_cast(cameraAttr->getSensorType()), + static_cast(esp::sensor::SensorType::Color)); + CORRADE_COMPARE(static_cast(cameraAttr->getSensorSubType()), + static_cast(esp::sensor::SensorSubType::Pinhole)); + CORRADE_COMPARE(cameraAttr->getPosition(), Mn::Vector3(2.1, 3.2, 4.3)); + CORRADE_COMPARE(cameraAttr->getOrientation(), Mn::Vector3(4.0, 3.0, 2.0)); + CORRADE_COMPARE(cameraAttr->getNoiseModel(), "pinhole_camera_noise"); + // visual SensorSpec values + CORRADE_COMPARE(cameraAttr->getResolution(), Mn::Vector2i(256, 512)); + CORRADE_COMPARE(cameraAttr->getChannels(), 3); + CORRADE_COMPARE(cameraAttr->getGPUToGPUTransfer(), true); + CORRADE_COMPARE(cameraAttr->getNearPlane(), 0.1f); + CORRADE_COMPARE(cameraAttr->getFarPlane(), 2000.0f); + // camera SensorSpec values + CORRADE_COMPARE(cameraAttr->getOrthoScale(), 0.2f); + CORRADE_COMPARE(cameraAttr->getHFOV(), 120.0_degf); + // TODO : + // Support user_defined attributes once being read from JSON +} // AttributesConfigsTest::testCameraSensorAttrVals + +void AttributesConfigsTest::testCustomSensorAttrVals( + std::shared_ptr customAttr, + const std::string& assetPath) { + // base SensorSpec values + CORRADE_COMPARE(customAttr->getHandle(), "custom_sensor_handle_:0000"); + CORRADE_COMPARE(static_cast(customAttr->getSensorType()), + static_cast(esp::sensor::SensorType::Custom)); + CORRADE_COMPARE(static_cast(customAttr->getSensorSubType()), + static_cast(esp::sensor::SensorSubType::Custom)); + CORRADE_COMPARE(customAttr->getPosition(), Mn::Vector3(1.5, 2.5, 3.5)); + CORRADE_COMPARE(customAttr->getOrientation(), Mn::Vector3(1.0, 2.0, 3.0)); + CORRADE_COMPARE(customAttr->getNoiseModel(), "custom_noise"); + + // TODO + // Custom sensor specifying attributes only available from JSON load. + + // TODO : + // Support user_defined attributes once being read from JSON +} // AttributesConfigsTest::testCustomSensorAttrVals + +void AttributesConfigsTest::testEquirectangularSensorAttrVals( + std::shared_ptr equirectAttr, + const std::string& assetPath) { + // base SensorSpec values + CORRADE_COMPARE(equirectAttr->getHandle(), "equirect_sensor_handle_:0000"); + CORRADE_COMPARE(static_cast(equirectAttr->getSensorType()), + static_cast(esp::sensor::SensorType::Depth)); + CORRADE_COMPARE( + static_cast(equirectAttr->getSensorSubType()), + static_cast(esp::sensor::SensorSubType::Equirectangular)); + CORRADE_COMPARE(equirectAttr->getPosition(), Mn::Vector3(1.1, 2.2, 3.3)); + CORRADE_COMPARE(equirectAttr->getOrientation(), + Mn::Vector3(20.0, 10.0, 30.0)); + CORRADE_COMPARE(equirectAttr->getNoiseModel(), "equirect_camera_noise"); + // visual SensorSpec values + CORRADE_COMPARE(equirectAttr->getResolution(), Mn::Vector2i(300, 400)); + CORRADE_COMPARE(equirectAttr->getChannels(), 1); + CORRADE_COMPARE(equirectAttr->getGPUToGPUTransfer(), true); + CORRADE_COMPARE(equirectAttr->getNearPlane(), 0.7f); + CORRADE_COMPARE(equirectAttr->getFarPlane(), 1200.0f); + // cubemap sensor spec values + CORRADE_COMPARE(equirectAttr->getCubeMapSize(), 320); + CORRADE_COMPARE(equirectAttr->getCubeMapSizeToUse(), 320); + + // TODO : + // Support user_defined attributes once being read from JSON +} // AttributesConfigsTest::testEquirectangularSensorAttrVals + +void AttributesConfigsTest::testFisheyeSensorAttrVals( + std::shared_ptr fisheyeAttr, + const std::string& assetPath) { + // base SensorSpec values + CORRADE_COMPARE(fisheyeAttr->getHandle(), "fisheye_sensor_handle_:0000"); + CORRADE_COMPARE(static_cast(fisheyeAttr->getSensorType()), + static_cast(esp::sensor::SensorType::Semantic)); + CORRADE_COMPARE(static_cast(fisheyeAttr->getSensorSubType()), + static_cast(esp::sensor::SensorSubType::Fisheye)); + CORRADE_COMPARE(fisheyeAttr->getPosition(), Mn::Vector3(2.1, 3.2, 4.3)); + CORRADE_COMPARE(fisheyeAttr->getOrientation(), Mn::Vector3(40.0, 34.0, 21.0)); + CORRADE_COMPARE(fisheyeAttr->getNoiseModel(), "fisheye_camera_noise"); + // visual SensorSpec values + CORRADE_COMPARE(fisheyeAttr->getResolution(), Mn::Vector2i(500, 300)); + CORRADE_COMPARE(fisheyeAttr->getChannels(), 3); + CORRADE_COMPARE(fisheyeAttr->getGPUToGPUTransfer(), true); + CORRADE_COMPARE(fisheyeAttr->getNearPlane(), 0.05f); + CORRADE_COMPARE(fisheyeAttr->getFarPlane(), 1500.0f); + // cubemap SensorSpec values + CORRADE_COMPARE(fisheyeAttr->getCubeMapSize(), 0); + CORRADE_COMPARE(fisheyeAttr->getCubeMapSizeToUse(), 300); + // fisheye SensorSpec values + + CORRADE_COMPARE(fisheyeAttr->getFocalLength(), Mn::Vector2(5.1, 2.5)); + CORRADE_COMPARE(fisheyeAttr->getPrincipalPointOffset(), + Mn::Vector2(200, 100)); + CORRADE_COMPARE(fisheyeAttr->getPrincipalPointOffsetToUse(), + Mn::Vector2(200, 100)); + + // TODO : + // Support user_defined attributes once being read from JSON +} // AttributesConfigsTest::testFisheyeSensorAttrVals + +void AttributesConfigsTest::testSensorAttrSpecLoad() { + // add dummy test so that test will run + CORRADE_VERIFY(true); + // to be removed once specs are removed + // build one of each of 5 types of SensorAttributes, driven by data values, + // from the appropriate SensorSpec, and then test their values. + +#ifdef ESP_BUILD_WITH_AUDIO + { + AudioSensorSpec::ptr audioSpec = AudioSensorSpec::create(); + // base SensorSpec values + audioSpec->uuid = "audio_sensor_handle"; + audioSpec->sensorType = esp::sensor::SensorType::Audio; + audioSpec->sensorSubType = esp::sensor::SensorSubType::ImpulseResponse; + audioSpec->position = {1.5, 2.5, 3.5}; + audioSpec->orientation = {1.0, 2.0, 3.0}; + audioSpec->noiseModel = "audio_noise"; + audioSpec->outputDirectory_ = "audio_sensor_output_dir"; + + // build audio attributes - data should direct manager to build correct + // attributes type + AudioSensorAttributes::ptr audioAttr = + sensorAttributesManager_ + ->createAttributesFromSensorSpec(audioSpec, + true); + CORRADE_VERIFY(audioAttr); + // Verify attributes are correct class + CORRADE_COMPARE(audioAttr->getClassKey(), "AudioSensorAttributes"); + + // test audio attributes' values + testAudioSensorAttrVals(audioAttr, ""); + } +#endif // ESP_BUILD_WITH_AUDIO + { + CameraSensorSpec::ptr cameraSpec = CameraSensorSpec::create(); + // base SensorSpec values + cameraSpec->uuid = "camera_sensor_handle"; + cameraSpec->sensorType = esp::sensor::SensorType::Color; + cameraSpec->sensorSubType = esp::sensor::SensorSubType::Pinhole; + cameraSpec->position = {2.1, 3.2, 4.3}; + cameraSpec->orientation = {4.0, 3.0, 2.0}; + cameraSpec->noiseModel = "pinhole_camera_noise"; + // visual SensorSpec values + cameraSpec->resolution = Mn::Vector2i(256, 512); + cameraSpec->channels = 3; + cameraSpec->gpu2gpuTransfer = true; + cameraSpec->near = 0.1f; + cameraSpec->far = 2000.0f; + // camera SensorSpec values + cameraSpec->orthoScale = 0.2f; + cameraSpec->hfov = 120.0_degf; + + // build camera attributes - data should direct manager to build correct + // attributes type + CameraSensorAttributes::ptr cameraAttr = + sensorAttributesManager_ + ->createAttributesFromSensorSpec(cameraSpec, + true); + CORRADE_VERIFY(cameraAttr); + // Verify attributes are correct class + CORRADE_COMPARE(cameraAttr->getClassKey(), "CameraSensorAttributes"); + + // test camera attributes' values + testCameraSensorAttrVals(cameraAttr, ""); + } + { + SensorSpec::ptr customSpec = SensorSpec::create(); + // base SensorSpec values + customSpec->uuid = "custom_sensor_handle"; + customSpec->sensorType = esp::sensor::SensorType::Custom; + customSpec->sensorSubType = esp::sensor::SensorSubType::Custom; + customSpec->position = {1.5, 2.5, 3.5}; + customSpec->orientation = {1.0, 2.0, 3.0}; + customSpec->noiseModel = "custom_noise"; + + // build custom attributes - data should direct manager to build correct + // attributes type + + CustomSensorAttributes::ptr custAttr = + sensorAttributesManager_ + ->createAttributesFromSensorSpec(customSpec, + true); + CORRADE_VERIFY(custAttr); + // Verify attributes are correct class + CORRADE_COMPARE(custAttr->getClassKey(), "CustomSensorAttributes"); + + // test custom attributes' values + testCustomSensorAttrVals(custAttr, ""); + } + { + EquirectangularSensorSpec::ptr equirectSpec = + EquirectangularSensorSpec::create(); + // base SensorSpec values + equirectSpec->uuid = "equirect_sensor_handle"; + equirectSpec->sensorType = esp::sensor::SensorType::Depth; + equirectSpec->sensorSubType = esp::sensor::SensorSubType::Equirectangular; + equirectSpec->position = {1.1, 2.2, 3.3}; + equirectSpec->orientation = {20.0, 10.0, 30.0}; + equirectSpec->noiseModel = "equirect_camera_noise"; + // visual SensorSpec values + equirectSpec->resolution = Mn::Vector2i(300, 400); + equirectSpec->channels = 1; + equirectSpec->gpu2gpuTransfer = true; + equirectSpec->near = 0.7f; + equirectSpec->far = 1200.0f; + // cubemap sensor spec values + equirectSpec->cubemapSize = 320; + // No further sensorSpec vaues for equirect + + // build equirect attributes - data should direct manager to build correct + // attributes type + EquirectangularSensorAttributes::ptr equiAttr = + sensorAttributesManager_ + ->createAttributesFromSensorSpec( + equirectSpec, true); + + CORRADE_VERIFY(equiAttr); + // Verify attributes are correct class + CORRADE_COMPARE(equiAttr->getClassKey(), "EquirectangularSensorAttributes"); + + // test equirect attributes' values + testEquirectangularSensorAttrVals(equiAttr, ""); + } + { + FisheyeSensorDoubleSphereSpec::ptr fisheyeSpec = + FisheyeSensorDoubleSphereSpec::create(); + // base SensorSpec values + fisheyeSpec->uuid = "fisheye_sensor_handle"; + fisheyeSpec->sensorType = esp::sensor::SensorType::Semantic; + fisheyeSpec->sensorSubType = esp::sensor::SensorSubType::Fisheye; + fisheyeSpec->position = {2.1, 3.2, 4.3}; + fisheyeSpec->orientation = {40.0, 34.0, 21.0}; + fisheyeSpec->noiseModel = "fisheye_camera_noise"; + // visual SensorSpec values + fisheyeSpec->resolution = Mn::Vector2i(500, 300); + fisheyeSpec->channels = 3; + fisheyeSpec->gpu2gpuTransfer = true; + fisheyeSpec->near = 0.05f; + fisheyeSpec->far = 1500.0f; + // cubemap SensorSpec values + fisheyeSpec->cubemapSize = Cr::Containers::NullOpt; + // fisheye SensorSpec values + fisheyeSpec->fisheyeModelType = + esp::sensor::FisheyeSensorModelType::DoubleSphere; + fisheyeSpec->focalLength = Mn::Vector2(5.1, 2.5); + fisheyeSpec->principalPointOffset = Mn::Vector2(200, 100); + // build Fisheye attributes - data should direct manager to build correct + // attributes type + FisheyeSensorAttributes::ptr fisheyeAttr = + sensorAttributesManager_ + ->createAttributesFromSensorSpec( + fisheyeSpec, true); + + CORRADE_VERIFY(fisheyeAttr); + // Verify attributes are correct class + CORRADE_COMPARE(fisheyeAttr->getClassKey(), "FisheyeSensorAttributes"); + + // test Fisheye attributes' values + testFisheyeSensorAttrVals(fisheyeAttr, ""); + } +} // AttributesConfigsTest::testSensorAttrSpecLoad +void AttributesConfigsTest::testSensorAttrJSONLoad() { + // add dummy test so that test will run + CORRADE_VERIFY(true); +} // AttributesConfigsTest::testSensorAttrJSONLoad + void AttributesConfigsTest::testStageAttrVals( std::shared_ptr stageAttr, const std::string& assetPath) { diff --git a/src/utils/viewer/viewer.cpp b/src/utils/viewer/viewer.cpp index 69fd73797c..79230ebcd5 100644 --- a/src/utils/viewer/viewer.cpp +++ b/src/utils/viewer/viewer.cpp @@ -1105,7 +1105,7 @@ void Viewer::switchCameraType() { case esp::sensor::SensorSubType::Equirectangular: { return; } - case esp::sensor::SensorSubType::None: { + case esp::sensor::SensorSubType::Unspecified: { CORRADE_INTERNAL_ASSERT_UNREACHABLE(); return; }