#include "dynamic_depth/imaging_model.h" #include #include "android-base/logging.h" #include "dynamic_depth/const.h" #include "strings/numbers.h" #include "xmpmeta/base64.h" namespace dynamic_depth { namespace { using ::dynamic_depth::xmpmeta::EncodeFloatArrayBase64; using ::dynamic_depth::xmpmeta::xml::Deserializer; using ::dynamic_depth::xmpmeta::xml::Serializer; constexpr char kFocalLengthX[] = "FocalLengthX"; constexpr char kFocalLengthY[] = "FocalLengthY"; constexpr char kImageWidth[] = "ImageWidth"; constexpr char kImageHeight[] = "ImageHeight"; constexpr char kPrincipalPointX[] = "PrincipalPointX"; constexpr char kPrincipalPointY[] = "PrincipalPointY"; constexpr char kSkew[] = "Skew"; constexpr char kPixelAspectRatio[] = "PixelAspectRatio"; constexpr char kDistortion[] = "Distortion"; constexpr char kDistortionCount[] = "DistortionCount"; constexpr char kNamespaceHref[] = "http://ns.google.com/photos/dd/1.0/imagingmodel/"; std::unique_ptr ParseFields(const Deserializer& deserializer) { Point focal_length(0, 0); Dimension image_size(0, 0); Point principal_point(0.5, 0.5); double skew = 0; double pixel_aspect_ratio = 1.0; const string& prefix = DynamicDepthConst::ImagingModel(); if (!deserializer.ParseDouble(prefix, kFocalLengthX, &focal_length.x) || !deserializer.ParseDouble(prefix, kFocalLengthY, &focal_length.y) || !deserializer.ParseInt(prefix, kImageWidth, &image_size.width) || !deserializer.ParseInt(prefix, kImageHeight, &image_size.height)) { return nullptr; } double temp1; double temp2; if (deserializer.ParseDouble(prefix, kPrincipalPointX, &temp1) && deserializer.ParseDouble(prefix, kPrincipalPointY, &temp2)) { principal_point.x = temp1; principal_point.y = temp2; } if (deserializer.ParseDouble(prefix, kSkew, &temp1)) { skew = temp1; } if (deserializer.ParseDouble(prefix, kPixelAspectRatio, &temp1)) { pixel_aspect_ratio = temp1; } int distortion_count = 0; std::vector distortion; if (deserializer.ParseInt(DynamicDepthConst::ImagingModel(), kDistortionCount, &distortion_count)) { if (distortion_count % 2 != 0) { LOG(ERROR) << "Parsed DistortionCount = " << distortion_count << " was expected to be even"; return nullptr; } deserializer.ParseFloatArrayBase64(DynamicDepthConst::ImagingModel(), kDistortion, &distortion); if (distortion.size() != distortion_count * 2) { LOG(ERROR) << "Parsed DistortionCount of " << distortion_count << " but should be " << distortion.size() << " when multiplied by 2"; return nullptr; } } ImagingModelParams params(focal_length, image_size); params.principal_point = principal_point; params.distortion = distortion; params.skew = skew; params.pixel_aspect_ratio = pixel_aspect_ratio; return ImagingModel::FromData(params); } } // namespace // Private constructor. ImagingModel::ImagingModel(const ImagingModelParams& params) : params_(params) {} // Public methods. void ImagingModel::GetNamespaces( std::unordered_map* 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::ImagingModel(), kNamespaceHref); } std::unique_ptr ImagingModel::FromData( const ImagingModelParams& params) { if (!params.distortion.empty() && params.distortion.size() % 2 != 0) { LOG(ERROR) << "Distortion must be empty or contain pairs of values, but an " << " odd number (size=" << params.distortion.size() << ") was found"; return nullptr; } return std::unique_ptr(new ImagingModel(params)); // NOLINT } std::unique_ptr ImagingModel::FromDeserializer( const Deserializer& parent_deserializer) { std::unique_ptr deserializer = parent_deserializer.CreateDeserializer( DynamicDepthConst::Namespace(DynamicDepthConst::ImagingModel()), DynamicDepthConst::ImagingModel()); if (deserializer == nullptr) { return nullptr; } return ParseFields(*deserializer); } Point ImagingModel::GetFocalLength() const { return params_.focal_length; } Point ImagingModel::GetPrincipalPoint() const { return params_.principal_point; } Dimension ImagingModel::GetImageSize() const { return params_.image_size; } double ImagingModel::GetSkew() const { return params_.skew; } double ImagingModel::GetPixelAspectRatio() const { return params_.pixel_aspect_ratio; } const std::vector& ImagingModel::GetDistortion() const { return params_.distortion; } int ImagingModel::GetDistortionCount() const { return static_cast(floor(params_.distortion.size() / 2)); } bool ImagingModel::Serialize(Serializer* serializer) const { if (serializer == nullptr) { LOG(ERROR) << "Serializer is null"; return false; } // Short-circuiting ensures unnecessary writes will not be performed. if (!serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kFocalLengthX, std::to_string(params_.focal_length.x)) || !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kFocalLengthY, std::to_string(params_.focal_length.y)) || // Image dimensions. !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kImageWidth, std::to_string(params_.image_size.width)) || !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kImageHeight, std::to_string(params_.image_size.height)) || // Principal point. !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kPrincipalPointX, std::to_string(params_.principal_point.x)) || !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kPrincipalPointY, std::to_string(params_.principal_point.y)) || // Skew, pixel aspect ratio. !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kSkew, std::to_string(params_.skew)) || !serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kPixelAspectRatio, std::to_string(params_.pixel_aspect_ratio))) { return false; } // Write distortion model only if needed. if (params_.distortion.empty()) { return true; } // No error-checking that there are an even number of values in // params_.distortion, because this is already done in the instantiator and // deserializer. string base64_encoded_distortion; if (!EncodeFloatArrayBase64(params_.distortion, &base64_encoded_distortion)) { LOG(ERROR) << "Distortion encoding failed"; return false; } int distortion_count = static_cast(floor(params_.distortion.size() / 2)); if (!serializer->WriteProperty( DynamicDepthConst::ImagingModel(), kDistortionCount, ::dynamic_depth::strings::SimpleItoa(distortion_count))) { return false; } if (!serializer->WriteProperty(DynamicDepthConst::ImagingModel(), kDistortion, base64_encoded_distortion)) { return false; } return true; } } // namespace dynamic_depth