blob: 5c68011175074c0e9916e1a3ab779d390de9447d [file] [log] [blame]
#include "dynamic_depth/imaging_model.h"
#include <math.h>
#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<ImagingModel> ParseFields(const Deserializer& deserializer) {
Point<double> focal_length(0, 0);
Dimension image_size(0, 0);
Point<double> 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<float> 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<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::ImagingModel(), kNamespaceHref);
}
std::unique_ptr<ImagingModel> 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<ImagingModel>(new ImagingModel(params)); // NOLINT
}
std::unique_ptr<ImagingModel> ImagingModel::FromDeserializer(
const Deserializer& parent_deserializer) {
std::unique_ptr<Deserializer> deserializer =
parent_deserializer.CreateDeserializer(
DynamicDepthConst::Namespace(DynamicDepthConst::ImagingModel()),
DynamicDepthConst::ImagingModel());
if (deserializer == nullptr) {
return nullptr;
}
return ParseFields(*deserializer);
}
Point<double> ImagingModel::GetFocalLength() const {
return params_.focal_length;
}
Point<double> 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<float>& ImagingModel::GetDistortion() const {
return params_.distortion;
}
int ImagingModel::GetDistortionCount() const {
return static_cast<int>(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<int>(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