summaryrefslogtreecommitdiff
path: root/internal/dynamic_depth/depth_map.cc
diff options
context:
space:
mode:
Diffstat (limited to 'internal/dynamic_depth/depth_map.cc')
-rw-r--r--internal/dynamic_depth/depth_map.cc362
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