otbImageMetadata.cxx 17.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "otbImageMetadata.h"
Guillaume Pasero's avatar
Guillaume Pasero committed
22 23
namespace otb
{
24
// ---------------------- [ImageMetadataBase] ------------------------------
25

26 27 28 29 30 31 32 33 34 35 36
ImageMetadataBase::ImageMetadataBase()
{
}

ImageMetadataBase::ImageMetadataBase(DictType<MDGeom, boost::any> geometryKeys,
                                     DictType<MDNum, double> numericKeys,
                                     DictType<MDStr, std::string> stringKeys,
                                     DictType<MDL1D, MetaData::LUT1D> lut1DKeys,
                                     DictType<MDL2D, MetaData::LUT2D> lut2DKeys,
                                     DictType<MDTime, MetaData::Time> timeKeys,
                                     DictType<std::string, std::string> extraKeys)
37 38 39 40 41 42 43 44
  : GeometryKeys(std::move(geometryKeys)),
    NumericKeys(std::move(numericKeys)),
	StringKeys(std::move(stringKeys)),
	LUT1DKeys(std::move(lut1DKeys)),
	LUT2DKeys(std::move(lut2DKeys)),
	TimeKeys(std::move(timeKeys)),
	ExtraKeys(std::move(extraKeys))
{}
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65

bool ImageMetadataBase::HasSensorGeometry() const
{
  return Has(MDGeom::RPC) || Has(MDGeom::SAR) || Has(MDGeom::SensorGeometry);
}

bool ImageMetadataBase::HasProjectedGeometry() const
{
  return Has(MDGeom::ProjectionWKT) || Has(MDGeom::ProjectionEPSG) || Has(MDGeom::ProjectionProj);
}

size_t ImageMetadataBase::RemoveSensorGeometry()
{
  return Remove(MDGeom::RPC) + Remove(MDGeom::SAR) + Remove(MDGeom::SensorGeometry);
}

size_t ImageMetadataBase::RemoveProjectedGeometry()
{
  return Remove(MDGeom::ProjectionWKT) + Remove(MDGeom::ProjectionEPSG) + Remove(MDGeom::ProjectionProj);
}

66 67 68 69 70 71 72
const Projection::GCPParam & ImageMetadataBase::GetGCPParam() const
{
  return boost::any_cast<const Projection::GCPParam &>(GeometryKeys.at(MDGeom::GCP));
}

std::string ImageMetadataBase::GetProjectionWKT() const
{
73 74 75 76 77 78 79 80 81
  auto projWKT = GeometryKeys.find(MDGeom::ProjectionWKT);
  if (projWKT !=  GeometryKeys.end())
  {
    return boost::any_cast<std::string>(projWKT->second);
  }
  else
  {
    return "";
  }
82 83
}

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
// -------------------- Geom utility function ----------------------------
const boost::any & ImageMetadataBase::operator[](const MDGeom& key) const
{
  return GeometryKeys.at(key);
}

void ImageMetadataBase::Add(const MDGeom& key, const boost::any &value)
{
  GeometryKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDGeom& key)
{
  return GeometryKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDGeom& key) const
{
  return (GeometryKeys.find(key) != GeometryKeys.end());
}

// -------------------- Double utility function ----------------------------

const double & ImageMetadataBase::operator[](const MDNum& key) const
{
  return NumericKeys.at(key);
}

void ImageMetadataBase::Add(const MDNum& key, const double &value)
{
  NumericKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDNum& key)
{
  return NumericKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDNum& key) const
{
  return (NumericKeys.find(key) != NumericKeys.end());
}

// -------------------- String utility function ----------------------------

const std::string & ImageMetadataBase::operator[](const MDStr& key) const
{
  return StringKeys.at(key);
}

void ImageMetadataBase::Add(const MDStr& key, const std::string &value)
{
  StringKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDStr& key)
{
  return StringKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDStr& key) const
{
  return (StringKeys.find(key) != StringKeys.end());
}

// -------------------- LUT1D utility function ----------------------------

const MetaData::LUT1D & ImageMetadataBase::operator[](const MDL1D& key) const
{
  return LUT1DKeys.at(key);
}

void ImageMetadataBase::Add(const MDL1D& key, const MetaData::LUT1D &value)
{
  LUT1DKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDL1D& key)
{
  return LUT1DKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDL1D& key) const
{
  return (LUT1DKeys.find(key) != LUT1DKeys.end());
}

// -------------------- 2D LUT utility function ----------------------------

const MetaData::LUT2D & ImageMetadataBase::operator[](const MDL2D& key) const
{
  return LUT2DKeys.at(key);
}

void ImageMetadataBase::Add(const MDL2D& key, const MetaData::LUT2D &value)
{
  LUT2DKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDL2D& key)
{
  return LUT2DKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDL2D& key) const
189
{
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
  return (LUT2DKeys.find(key) != LUT2DKeys.end());
}

// -------------------- Time utility function ----------------------------

const MetaData::Time & ImageMetadataBase::operator[](const MDTime& key) const
{
  return TimeKeys.at(key);
}

void ImageMetadataBase::Add(const MDTime& key, const MetaData::Time &value)
{
  TimeKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const MDTime& key)
{
  return TimeKeys.erase(key);
}

bool ImageMetadataBase::Has(const MDTime& key) const
{
  return (TimeKeys.find(key) != TimeKeys.end());
}

// -------------------- Extra keys utility function --------------------------

const std::string & ImageMetadataBase::operator[](const std::string & key) const
{
  return ExtraKeys.at(key);
}

void ImageMetadataBase::Add(const std::string& key, const std::string &value)
{
  ExtraKeys[key] = value;
}

size_t ImageMetadataBase::Remove(const std::string& key)
{
  return ExtraKeys.erase(key);
}

bool ImageMetadataBase::Has(const std::string& key) const
{
  return (ExtraKeys.find(key) != ExtraKeys.end());
}

237
void ImageMetadataBase::ToKeywordlist(Keywordlist& kwl) const
238 239
{
  kwl.clear();
240
  std::ostringstream oss;
241 242 243 244

  // Converting the GeomKeys
  for (const auto& kv : GeometryKeys)
  {
245
    oss.str("");
246
    if (kv.first == MDGeom::RPC)
247
    {
248
      // To be completed by ImageIO
249
      oss << std::string("<RPCParam>");
250
    }
251
    else if (kv.first == MDGeom::ProjectionEPSG)
252
    {
253
      oss << std::to_string(boost::any_cast<int>(kv.second));
254 255 256
    }
    else if (kv.first == MDGeom::GCP)
    {
257
      // To be completed by ImageIO
258
      oss << std::string("<GCPParam>");
259
    }
260 261 262 263 264
    else if (kv.first == MDGeom::SensorGeometry)
    {
    // MDGeom::SensorGeometry should be exported as "<typeinfo>" where typeinfo is boost::any::type().name()
      oss << kv.second.type().name();
    }
265 266 267 268
    // TODO : MDGeom::SAR
    // TODO : MDGeom::Adjustment
    else
    {
269
      oss << boost::any_cast<std::string>(kv.second);
270
    }
271
    kwl.emplace(MetaData::MDGeomNames.left.at(kv.first), oss.str());
272 273 274 275
  }
  // Converting the StringKeys
  for (const auto& kv : StringKeys)
  {
276
    kwl.emplace(MetaData::MDStrNames.left.at(kv.first), kv.second);
277 278 279 280
  }
  // Converting the NumericKeys
  for (const auto& kv : NumericKeys)
  {
281
    oss.str("");
282
    oss << kv.second;
283
    kwl.emplace(MetaData::MDNumNames.left.at(kv.first), oss.str());
284 285
  }
  // Converting the LUT1DKeys
286 287
  for (const auto& kv : LUT1DKeys)
  {
288 289 290
    oss.str("");
    oss << kv.second.ToString();
    kwl.emplace(MetaData::MDL1DNames.left.at(kv.first), oss.str());
291
  }
292
  // Converting the LUT2DKeys
293 294
  for (const auto& kv : LUT2DKeys)
  {
295 296 297
    oss.str("");
    oss << kv.second.ToString();
    kwl.emplace(MetaData::MDL2DNames.left.at(kv.first), oss.str());
298
  }
299
  // Converting the TimeKeys
300
  for (const auto& kv : TimeKeys)
301
  {
302
    oss.str("");
303
    oss << kv.second;
304
    kwl.emplace(MetaData::MDTimeNames.left.at(kv.first), oss.str());
305 306
  }
  // Converting the ExtraKeys
307 308
  std::string prefix("Extra.");
  for (const auto& kv : ExtraKeys)
309
  {
310
    kwl.emplace(prefix + kv.first, kv.second);
311
  }
312
}
313

314
std::string ImageMetadataBase::ToJSON(bool multiline) const
315 316 317 318
{
  Keywordlist kwl;
  ToKeywordlist(kwl);
  std::ostringstream oss;
319 320 321 322 323
  std::string sep;
  if (multiline)
    {
    sep = "\n";
    }
324 325
  oss << "{";
  for (const auto& kv : kwl)
326
    {
327
    oss << "\""<< kv.first << "\": \"" << kv.second << "\"," << sep;
328
    }
329 330 331 332
  oss << "}";
  return oss.str();
}

333
bool ImageMetadataBase::FromKeywordlist(const Keywordlist& kwl)
334
{
335 336 337 338 339
  // Return value
  bool all_parsed = true;
  // search iterators
  for (const auto& kv : kwl)
  {
340 341 342 343
  // Converting the GeomKeys
    auto geomKey = MetaData::MDGeomNames.right.find(kv.first);
    if (geomKey != MetaData::MDGeomNames.right.end())
    {
344
      if (geomKey->second ==  MDGeom::ProjectionEPSG)
345 346 347 348 349
      {
        this->Add(geomKey->second, Utils::LexicalCast<int>(kv.second.c_str(), "Keywordlist.second.c_str()"));
      }
      // TODO : MDGeom::SAR
      // TODO : MDGeom::Adjustment
350
      else if (geomKey->second ==  MDGeom::ProjectionWKT ||geomKey->second ==  MDGeom:: ProjectionProj)
351 352 353
      {
        this->Add(geomKey->second, kv.second);
      }
354
      // skip MDGeom::SensorGeometry, MDGeom::RPC and MDGeom::GCP
355 356
      continue;
    }
357 358 359 360 361 362 363 364 365 366 367
  // Converting the StringKeys
    auto strKey = MetaData::MDStrNames.right.find(kv.first);
    if (strKey != MetaData::MDStrNames.right.end())
    {
      this->Add(strKey->second, kv.second);
      continue;
    }
  // Converting the NumericKeys
    auto numKey = MetaData::MDNumNames.right.find(kv.first);
    if (numKey != MetaData::MDNumNames.right.end())
    {
368
      this->Add(numKey->second, Utils::LexicalCast<double>(kv.second.c_str(), "Keywordlist.second.c_str()"));
369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386
      continue;
    }
  // Converting the LUT1DKeys
    auto lut1dKey = MetaData::MDL1DNames.right.find(kv.first);
    if (lut1dKey != MetaData::MDL1DNames.right.end())
    {
      MetaData::LUT1D lut;
      lut.FromString(kv.second);
      this->Add(lut1dKey->second, lut);
      continue;
    }
  // Converting the LUT2DKeys
    auto lut2dKey = MetaData::MDL2DNames.right.find(kv.first);
    if (lut2dKey != MetaData::MDL2DNames.right.end())
    {
      MetaData::LUT2D lut;
      lut.FromString(kv.second);
      this->Add(lut2dKey->second, lut);
387 388 389 390 391 392 393 394 395 396 397 398 399
      continue;
    }
  // Converting the TimeKeys
    auto timeKey = MetaData::MDTimeNames.right.find(kv.first);
    if (timeKey != MetaData::MDTimeNames.right.end())
    {
      MetaData::Time time;
      std::istringstream (kv.second) >> time;
      this->Add(timeKey->second, time);
      continue;
    }
  // Converting the ExtraKeys
    std::string prefix("Extra.");
400
    if (kv.first.compare(0, prefix.size(), prefix) == 0)
401 402 403 404
    {
      this->Add(kv.first.substr(prefix.size()), kv.second);
      continue;
    }
405 406
    otbLogMacro(Warning, << "The metadata named '" << kv.first << "' with value '" << kv.second << "' was not parsed.")
    all_parsed = false;
407 408
  }
  return all_parsed;
409 410
}

411 412 413 414 415 416 417 418 419 420 421 422 423 424

/** concatenate with an other ImageMetadata */
void ImageMetadataBase::Fuse(const ImageMetadataBase& imd)
{
  // Copy the keys
  this->GeometryKeys.insert(imd.GeometryKeys.begin(), imd.GeometryKeys.end());
  this->NumericKeys.insert(imd.NumericKeys.begin(), imd.NumericKeys.end());
  this->StringKeys.insert(imd.StringKeys.begin(), imd.StringKeys.end());
  this->LUT1DKeys.insert(imd.LUT1DKeys.begin(), imd.LUT1DKeys.end());
  this->LUT2DKeys.insert(imd.LUT2DKeys.begin(), imd.LUT2DKeys.end());
  this->TimeKeys.insert(imd.TimeKeys.begin(), imd.TimeKeys.end());
  this->ExtraKeys.insert(imd.ExtraKeys.begin(), imd.ExtraKeys.end());
}

425 426
// ----------------------- [ImageMetadata] ------------------------------

427 428 429 430 431 432 433 434 435 436 437 438
ImageMetadata::ImageMetadata()
{
}

ImageMetadata::ImageMetadata(DictType<MDGeom, boost::any> geometryKeys,
                             DictType<MDNum, double> numericKeys,
                             DictType<MDStr, std::string> stringKeys,
                             DictType<MDL1D, MetaData::LUT1D> lut1DKeys,
                             DictType<MDL2D, MetaData::LUT2D> lut2DKeys,
                             DictType<MDTime, MetaData::Time> timeKeys,
                             DictType<std::string, std::string> extraKeys,
                             ImageMetadataBandsType bands)
439 440 441
  : ImageMetadataBase(geometryKeys, numericKeys, stringKeys, lut1DKeys, lut2DKeys, timeKeys, extraKeys),
    Bands(std::move(bands))
{}
442

443
ImageMetadata ImageMetadata::slice(int start, int end) const
444
{
445 446 447 448
  assert(start <= end);

  auto first = this->Bands.cbegin() + start;
  auto last = this->Bands.cbegin() + end + 1;
449 450
  ImageMetadata imd(this->GeometryKeys, this->NumericKeys, this->StringKeys, this->LUT1DKeys,
                    this->LUT2DKeys, this->TimeKeys, this->ExtraKeys, ImageMetadataBandsType(first, last));
451
  return imd;
452 453 454
}

/** concatenate with an other ImageMetadata */
455
void ImageMetadata::append(const ImageMetadata& imd)
456
{
457 458
  ImageMetadataBase::Fuse(imd);
  
459 460
  // Copy the bands
  this->Bands.insert(this->Bands.end(), imd.Bands.begin(), imd.Bands.end());
461 462
}

463 464 465 466 467 468 469 470 471
void ImageMetadata::Merge(const ImageMetadata& imd)
{
  ImageMetadataBase::Fuse(imd);
  
  for (unsigned int i = 0; i < std::min(Bands.size(), imd.Bands.size()); i++)
  {
    Bands[i].Fuse(imd.Bands[i]);
  }
}
472 473 474
/** if all bands share the same value of a key, put it at top level */
void ImageMetadata::compact()
{
475 476 477 478
  if (this->Bands.size() < 2)
    return;
  bool compactVal;
  // TODO Compact the GeometryKeys when comparisons exists
479
  // Compact NumericKeys
480 481
  auto numKeys = this->Bands.front().NumericKeys;
  for (const auto& kv : numKeys)
482 483 484 485 486 487 488 489
  {
    compactVal = true;
    auto bandIt = this->Bands.cbegin();
    ++bandIt;
    for ( ; bandIt != this->Bands.cend() ; ++bandIt)
    {
      auto otherKey = bandIt->NumericKeys.find(kv.first);
      if ((otherKey == bandIt->NumericKeys.end())
490
       || !itk::Math::AlmostEquals(otherKey->second, kv.second))
491 492 493 494 495 496 497 498 499 500 501 502 503 504
      {
        compactVal = false;
        break;
      }
    }
    if (compactVal)
    {
      this->Add(kv.first, kv.second);
      for (auto& band : this->Bands)
      {
        band.NumericKeys.erase(kv.first);
      }
    }
  }
505
  // Compact StringKeys
506 507
  auto strKeys = this->Bands.front().StringKeys;
  for (const auto& kv : strKeys)
508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
  {
    compactVal = true;
    auto bandIt = this->Bands.cbegin();
    ++bandIt;
    for ( ; bandIt != this->Bands.cend() ; ++bandIt)
    {
      auto otherKey = bandIt->StringKeys.find(kv.first);
      if ((otherKey == bandIt->StringKeys.end())
       || !(otherKey->second == kv.second))
      {
        compactVal = false;
        break;
      }
    }
    if (compactVal)
    {
      this->Add(kv.first, kv.second);
      for (auto& band : this->Bands)
      {
        band.StringKeys.erase(kv.first);
      }
    }
  }
531 532
  // TODO Compact LUT1DKeys when comparisons exists
  // TODO Compact LUT2DKeys when comparisons exists
533
  // Compact TimeKeys
534 535
  auto timeKeys = this->Bands.front().TimeKeys;
  for (const auto& kv : timeKeys)
536 537 538 539 540 541 542 543
  {
    compactVal = true;
    auto bandIt = this->Bands.cbegin();
    ++bandIt;
    for ( ; bandIt != this->Bands.cend() ; ++bandIt)
    {
      auto otherKey = bandIt->TimeKeys.find(kv.first);
      if ((otherKey == bandIt->TimeKeys.end())
544
       || !itk::Math::AlmostEquals(otherKey->second.frac_sec, kv.second.frac_sec))
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559
      {
        compactVal = false;
        break;
      }
    }
    if (compactVal)
    {
      this->Add(kv.first, kv.second);
      for (auto& band : this->Bands)
      {
        band.TimeKeys.erase(kv.first);
      }
    }
  }
  // Compact ExtraKeys
560 561
  auto extraKeys = this->Bands.front().ExtraKeys;
  for (const auto& kv : extraKeys)
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584
  {
    compactVal = true;
    auto bandIt = this->Bands.cbegin();
    ++bandIt;
    for ( ; bandIt != this->Bands.cend() ; ++bandIt)
    {
      auto otherKey = bandIt->ExtraKeys.find(kv.first);
      if ((otherKey == bandIt->ExtraKeys.end())
       || !(otherKey->second == kv.second))
      {
        compactVal = false;
        break;
      }
    }
    if (compactVal)
    {
      this->Add(kv.first, kv.second);
      for (auto& band : this->Bands)
      {
        band.ExtraKeys.erase(kv.first);
      }
    }
  }
585 586
}

587
void ImageMetadata::AppendToKeywordlists(KeywordlistVector& kwlVect) const
588 589 590 591
{
  Keywordlist kwl;
  this->ToKeywordlist(kwl);
  kwlVect.push_back(kwl);
592
  this->AppendToBandKeywordlists(kwlVect);
593 594
}

595
void ImageMetadata::AppendToBandKeywordlists(KeywordlistVector& kwlVect) const
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
{
  Keywordlist kwl;
  for (const auto& band: this->Bands)
  {
    band.ToKeywordlist(kwl);
    kwlVect.push_back(kwl);
  }
}

bool ImageMetadata::FromKeywordlists(const KeywordlistVector& kwlVect)
{
  bool all_parsed = true;
  auto kwlIt = kwlVect.cbegin();
  all_parsed = this->FromKeywordlist(*kwlIt) && all_parsed;
  ++kwlIt;
611
  for ( ; kwlIt != kwlVect.cend() ; ++kwlIt)
612 613 614 615 616 617 618 619
  {
    ImageMetadataBase imb;
    all_parsed = imb.FromKeywordlist(*kwlIt) && all_parsed;
    this->Bands.push_back(imb);
  }
  return all_parsed;
}

620 621 622 623 624 625 626 627 628 629
void ImageMetadata::Add(const MDNum& key, const MetaDataKey::VariableLengthVectorType vlv)
{
  assert(this->Bands.size() == vlv.Size());
  const double* vlvIt = vlv.GetDataPointer();
  for(auto band = this->Bands.begin() ; band != this->Bands.end() ; ++band, ++vlvIt)
  {
    band->Add(key, *vlvIt);
  }
}

630 631 632 633 634 635 636 637 638 639 640 641 642
// printing
std::ostream& operator<<(std::ostream& os, const otb::ImageMetadataBase& imd)
{
  os << imd.ToJSON(true);
  return os;
}

std::ostream& operator<<(std::ostream& os, const otb::ImageMetadata& imd)
{
  os << "{";
  os << imd.ToJSON(true);
  os << "Bands[";
  for (auto &band : imd.Bands)
643
    {
644
    os << band.ToJSON(true) << ",";
645
    }
646 647 648
  os << "]\n";
  os << "}";

649 650
  return os;
}
Guillaume Pasero's avatar
Guillaume Pasero committed
651 652

}