diff options
Diffstat (limited to 'internal/dynamic_depth/depth_map.cc')
-rw-r--r-- | internal/dynamic_depth/depth_map.cc | 362 |
1 files changed, 362 insertions, 0 deletions
diff --git a/internal/dynamic_depth/depth_map.cc b/internal/dynamic_depth/depth_map.cc new file mode 100644 index 0000000..4d16c8d --- /dev/null +++ b/internal/dynamic_depth/depth_map.cc @@ -0,0 +1,362 @@ +#include "dynamic_depth/depth_map.h" + +#include "android-base/logging.h" +#include "dynamic_depth/const.h" +#include "dynamic_depth/item.h" +#include "strings/numbers.h" +#include "xmpmeta/base64.h" + +using photos_editing_formats::dynamic_depth::Item; +using photos_editing_formats::xml::Deserializer; +using photos_editing_formats::xml::Serializer; + +namespace photos_editing_formats { +namespace dynamic_depth { +namespace { +constexpr const char* kNamespaceHref = + "http://ns.google.com/photos/dd/1.0/depthmap/"; + +constexpr const char* kFormat = "Format"; +constexpr const char* kNear = "Near"; +constexpr const char* kFar = "Far"; +constexpr const char* kUnits = "Units"; +constexpr const char* kDepthUri = "DepthURI"; +constexpr const char* kItemSemantic = "ItemSemantic"; +constexpr const char* kConfidenceUri = "ConfidenceURI"; +constexpr const char* kMeasureType = "MeasureType"; +constexpr const char* kSoftware = "Software"; +constexpr const char* kFocalTable = "FocalTable"; +constexpr const char* kFocalTableEntryCount = "FocalTableEntryCount"; + +constexpr const char* kFormatRangeInverse = "RangeInverse"; +constexpr const char* kFormatRangeLinear = "RangeLinear"; +constexpr const char* kFormatRangeInverseLower = "rangeinverse"; +constexpr const char* kFormatRangeLinearLower = "rangelinear"; + +constexpr const char* kUnitsMeters = "Meters"; +constexpr const char* kUnitsDiopters = "Diopters"; +constexpr const char* kUnitsNone = "None"; +constexpr const char* kUnitsMetersLower = "meters"; +constexpr const char* kUnitsDioptersLower = "diopters"; + +constexpr const char* kMeasureTypeOpticalAxis = "OpticalAxis"; +constexpr const char* kMeasureTypeOpticRay = "OpticRay"; +constexpr const char* kMeasureTypeOpticRayLower = "opticray"; + +constexpr const char* kItemSemanticDepth = "Depth"; +constexpr const char* kItemSemanticSegmentation = "Segmentation"; +constexpr const char* kItemSemanticSegmentationLower = "segmentation"; + +string ItemSemanticToString(DepthItemSemantic item_semantic) { + switch (item_semantic) { + case DepthItemSemantic::kDepth: + return kItemSemanticDepth; + case DepthItemSemantic::kSegmentation: + return kItemSemanticSegmentation; + } +} + +DepthItemSemantic StringToItemSemantic(const string& semantic_str) { + string semantic_str_lower = semantic_str; + std::transform(semantic_str_lower.begin(), semantic_str_lower.end(), + semantic_str_lower.begin(), ::tolower); + if (kItemSemanticSegmentationLower == semantic_str_lower) { + return DepthItemSemantic::kSegmentation; + } + + return DepthItemSemantic::kDepth; +} + +string FormatToString(DepthFormat format) { + switch (format) { + case DepthFormat::kRangeInverse: + return kFormatRangeInverse; + case DepthFormat::kRangeLinear: + return kFormatRangeLinear; + case DepthFormat::kFormatNone: + return ""; + } +} + +// Case insensitive. +DepthFormat StringToFormat(const string& format_str) { + string format_str_lower = format_str; + std::transform(format_str_lower.begin(), format_str_lower.end(), + format_str_lower.begin(), ::tolower); + if (kFormatRangeInverseLower == format_str_lower) { + return DepthFormat::kRangeInverse; + } + + if (kFormatRangeLinearLower == format_str_lower) { + return DepthFormat::kRangeLinear; + } + + return DepthFormat::kFormatNone; +} + +string UnitsToString(DepthUnits units) { + switch (units) { + case DepthUnits::kMeters: + return kUnitsMeters; + case DepthUnits::kDiopters: + return kUnitsDiopters; + case DepthUnits::kUnitsNone: + return kUnitsNone; + } +} + +DepthUnits StringToUnits(const string& units_str) { + string units_str_lower = units_str; + std::transform(units_str_lower.begin(), units_str_lower.end(), + units_str_lower.begin(), ::tolower); + if (kUnitsMetersLower == units_str_lower) { + return DepthUnits::kMeters; + } + + if (kUnitsDioptersLower == units_str_lower) { + return DepthUnits::kDiopters; + } + + return DepthUnits::kUnitsNone; +} + +string MeasureTypeToString(DepthMeasureType measure_type) { + switch (measure_type) { + case DepthMeasureType::kOpticRay: + return kMeasureTypeOpticRay; + case DepthMeasureType::kOpticalAxis: + return kMeasureTypeOpticalAxis; + } +} + +DepthMeasureType StringToMeasureType(const string& measure_type_str) { + string measure_type_str_lower = measure_type_str; + std::transform(measure_type_str_lower.begin(), measure_type_str_lower.end(), + measure_type_str_lower.begin(), ::tolower); + if (kMeasureTypeOpticRayLower == measure_type_str_lower) { + return DepthMeasureType::kOpticRay; + } + + return DepthMeasureType::kOpticalAxis; +} + +} // namespace + +// Private constructor. +DepthMap::DepthMap(const DepthMapParams& params) : params_(params) {} + +// Private parser. +std::unique_ptr<DepthMap> DepthMap::ParseFields( + const Deserializer& deserializer) { + const string& prefix = DynamicDepthConst::DepthMap(); + string format_str; + float near; + float far; + string units_str; + string depth_uri; + string item_semantic_str; + + if (!deserializer.ParseString(prefix, kItemSemantic, &item_semantic_str) || + !deserializer.ParseString(prefix, kFormat, &format_str) || + !deserializer.ParseFloat(prefix, kNear, &near) || + !deserializer.ParseFloat(prefix, kFar, &far) || + !deserializer.ParseString(prefix, kUnits, &units_str) || + !deserializer.ParseString(prefix, kDepthUri, &depth_uri)) { + return nullptr; + } + + DepthMapParams params(StringToFormat(format_str), near, far, + StringToUnits(units_str), depth_uri); + params.item_semantic = StringToItemSemantic(item_semantic_str); + + string confidence_uri; + if (deserializer.ParseString(prefix, kConfidenceUri, &confidence_uri)) { + params.confidence_uri = confidence_uri; + } + + string measure_type_str; + if (deserializer.ParseString(prefix, kMeasureType, &measure_type_str)) { + params.measure_type = StringToMeasureType(measure_type_str); + } + + string software; + if (deserializer.ParseString(prefix, kSoftware, &software)) { + params.software = software; + } + + std::vector<float> focal_table; + int focal_table_entry_count; + if (deserializer.ParseFloatArrayBase64(prefix, kFocalTable, &focal_table) && + (!deserializer.ParseInt(prefix, kFocalTableEntryCount, + &focal_table_entry_count) && + focal_table.size() / 2 != focal_table_entry_count)) { + return nullptr; + } + params.focal_table = focal_table; + + return std::unique_ptr<DepthMap>(new DepthMap(params)); // NOLINT +} + +// Public methods. +void DepthMap::GetNamespaces( + std::unordered_map<string, string>* ns_name_href_map) { + if (ns_name_href_map == nullptr) { + LOG(ERROR) << "Namespace list or own namespace is null"; + return; + } + ns_name_href_map->emplace(DynamicDepthConst::DepthMap(), kNamespaceHref); +} + +std::unique_ptr<DepthMap> DepthMap::FromData( + const DepthMapParams& params, std::vector<std::unique_ptr<Item>>* items) { + if (params.format == DepthFormat::kFormatNone) { + LOG(ERROR) + << "Format must be specified, cannot be of type DepthFormat::NONE"; + return nullptr; + } + + if (params.depth_uri.empty() || params.depth_image_data.empty()) { + LOG(ERROR) << "Depth image data and URI must be provided"; + return nullptr; + } + + if (!params.focal_table.empty() && params.focal_table.size() % 2 != 0) { + LOG(ERROR) << "Focal table entries must consist of pairs"; + return nullptr; + } + + if (items == nullptr) { + LOG(ERROR) << "List of items is null"; + return nullptr; + } + + if (params.mime.empty()) { + LOG(ERROR) << "Depth image mime must be provided to DepthMapParams"; + return nullptr; + } + + ItemParams depth_item_params(params.mime, params.depth_image_data.size(), + params.depth_uri); + depth_item_params.payload_to_serialize = params.depth_image_data; + items->emplace_back(Item::FromData(depth_item_params)); + + bool available_confidence_uri_and_data = true; + if (!params.confidence_uri.empty() && !params.confidence_data.empty()) { + // Assumes that the confidence mime is the same as that of the depth map. + ItemParams confidence_item_params( + params.mime, params.confidence_data.size(), params.confidence_uri); + confidence_item_params.payload_to_serialize = params.confidence_data; + items->emplace_back(Item::FromData(confidence_item_params)); + } else if (!params.confidence_uri.empty() && params.confidence_data.empty()) { + LOG(ERROR) << "No confidence data provided, the URI will be set to empty " + "and not serialized"; + available_confidence_uri_and_data = false; + } + + auto depth_map = std::unique_ptr<DepthMap>(new DepthMap(params)); // NOLINT + if (!available_confidence_uri_and_data) { + // Ensure we don't serialize the confidence URI if no data has been + // provided. + depth_map->params_.confidence_uri = ""; + } + + return depth_map; +} + +std::unique_ptr<DepthMap> DepthMap::FromDeserializer( + const xml::Deserializer& parent_deserializer) { + std::unique_ptr<Deserializer> deserializer = + parent_deserializer.CreateDeserializer( + DynamicDepthConst::Namespace(DynamicDepthConst::DepthMap()), + DynamicDepthConst::DepthMap()); + if (deserializer == nullptr) { + LOG(ERROR) << "Deserializer must not be null"; + return nullptr; + } + + return ParseFields(*deserializer); +} + +DepthFormat DepthMap::GetFormat() const { return params_.format; } +float DepthMap::GetNear() const { return params_.near; } +float DepthMap::GetFar() const { return params_.far; } +DepthUnits DepthMap::GetUnits() const { return params_.units; } +const string DepthMap::GetDepthUri() const { return params_.depth_uri; } +DepthItemSemantic DepthMap::GetItemSemantic() const { + return params_.item_semantic; +} +const string DepthMap::GetConfidenceUri() const { + return params_.confidence_uri; +} + +DepthMeasureType DepthMap::GetMeasureType() const { + return params_.measure_type; +} + +const string DepthMap::GetSoftware() const { return params_.software; } +const std::vector<float>& DepthMap::GetFocalTable() const { + return params_.focal_table; +} + +size_t DepthMap::GetFocalTableEntryCount() const { + return params_.focal_table.size() / 2; +} + +bool DepthMap::Serialize(Serializer* serializer) const { + if (serializer == nullptr) { + LOG(ERROR) << "Serializer is null"; + return false; + } + if (params_.depth_uri.empty()) { + LOG(ERROR) << "Depth image URI is empty"; + return false; + } + + const string& prefix = DynamicDepthConst::DepthMap(); + // Error checking is already done in FromData. + if (!serializer->WriteProperty(prefix, kItemSemantic, + ItemSemanticToString(params_.item_semantic)) || + !serializer->WriteProperty(prefix, kFormat, + FormatToString(params_.format)) || + !serializer->WriteProperty(prefix, kUnits, + UnitsToString(params_.units)) || + !serializer->WriteProperty(prefix, kNear, std::to_string(params_.near)) || + !serializer->WriteProperty(prefix, kFar, std::to_string(params_.far)) || + !serializer->WriteProperty(prefix, kDepthUri, params_.depth_uri)) { + return false; + } + + serializer->WriteProperty(prefix, kMeasureType, + MeasureTypeToString(params_.measure_type)); + + if (!params_.confidence_uri.empty()) { + serializer->WriteProperty(prefix, kConfidenceUri, params_.confidence_uri); + } + + if (!params_.software.empty()) { + serializer->WriteProperty(prefix, kSoftware, params_.software); + } + + if (!params_.focal_table.empty()) { + string base64_encoded_focal_table; + if (!EncodeFloatArrayBase64(params_.focal_table, + &base64_encoded_focal_table)) { + LOG(ERROR) << "Focal table encoding failed"; + } else { + int focal_table_entry_count = + static_cast<int>(params_.focal_table.size() / 2); + if (!serializer->WriteProperty( + prefix, kFocalTableEntryCount, + ::dynamic_depth::strings::SimpleItoa(focal_table_entry_count)) || + !serializer->WriteProperty(prefix, kFocalTable, + base64_encoded_focal_table)) { + LOG(ERROR) << "Focal table or entry count could not be serialized"; + } + } + } + + return true; +} + +} // namespace dynamic_depth +} // namespace photos_editing_formats |