22#define VIEW_IO_META_FILE "meta.ini"
23#define VIEW_IO_BLOB_SIGNATURE "\211MVE_BLOB\n"
24#define VIEW_IO_BLOB_SIGNATURE_LEN 10
27#define VIEW_MVE_FILE_SIGNATURE "\211MVE\n"
28#define VIEW_MVE_FILE_SIGNATURE_LEN 5
33View::load_view (std::string
const& user_path)
37 this->deprecated_format_check(safe_path);
44 this->load_meta_data(safe_path);
45 this->populate_images_and_blobs(safe_path);
46 this->path = safe_path;
56View::load_view_from_mve_file (std::string
const& filename)
59 std::ifstream infile(filename.c_str(), std::ios::binary);
73 typedef std::pair<std::size_t, char*> ReadBuffer;
74 std::vector<ReadBuffer> embedding_buffers;
78 std::getline(infile, line);
84 if (line ==
"end_headers")
94 if (tokens[0] ==
"image" && tokens.size() == 6)
98 proxy.
name = tokens[1];
99 proxy.
width = util::string::convert<int64_t>(tokens[2]);
100 proxy.
height = util::string::convert<int64_t>(tokens[3]);
101 proxy.
channels = util::string::convert<int64_t>(tokens[4]);
106 this->images.push_back(proxy);
107 embedding_buffers.push_back(ReadBuffer(
108 proxy.
image->get_byte_size(),
109 proxy.
image->get_byte_pointer()));
111 else if (tokens[0] ==
"data" && tokens.size() == 3)
115 proxy.
name = tokens[1];
116 proxy.
size = util::string::convert<uint64_t>(tokens[2]);
119 this->blobs.push_back(proxy);
120 embedding_buffers.push_back(ReadBuffer(
121 proxy.
blob->get_byte_size(),
122 proxy.
blob->get_byte_pointer()));
124 else if (tokens[0] ==
"id" && tokens.size() == 2)
126 this->set_value(
"view.id", tokens[1]);
128 else if (tokens[0] ==
"name" && tokens.size() > 1)
130 this->set_value(
"view.name", tokens.
concat(1));
132 else if (tokens[0] ==
"camera-ext" && tokens.size() == 13)
134 this->set_value(
"camera.translation", tokens.
concat(1, 3));
135 this->set_value(
"camera.rotation", tokens.
concat(4, 9));
137 else if (tokens[0] ==
"camera-int"
138 && tokens.size() >= 2 && tokens.size() <= 7)
140 this->set_value(
"camera.focal_length", tokens[1]);
141 if (tokens.size() > 3)
142 this->set_value(
"camera.radial_distortion", tokens.
concat(2, 2));
143 if (tokens.size() > 4)
144 this->set_value(
"camera.pixel_aspect", tokens[4]);
145 if (tokens.size() > 6)
146 this->set_value(
"camera.principal_point", tokens.
concat(5, 2));
150 std::cerr <<
"Unrecognized header: " << line << std::endl;
155 for (std::size_t i = 0; i < embedding_buffers.size(); ++i)
158 std::getline(infile, line);
164 if (tokens.size() != 3)
167 ReadBuffer& buffer = embedding_buffers[i];
168 std::size_t byte_size = util::string::convert<std::size_t>(tokens[2]);
169 if (byte_size != buffer.first)
172 infile.read(buffer.second, buffer.first);
182View::reload_view (
void)
184 if (this->path.empty())
185 throw std::runtime_error(
"View not initialized");
186 this->load_view(this->path);
190View::save_view_as (std::string
const& user_path)
204 for (std::size_t i = 0; i < this->images.size(); ++i)
208 this->load_image(&this->images[i],
false);
209 this->images[i].is_dirty =
true;
211 for (std::size_t i = 0; i < this->blobs.size(); ++i)
213 this->load_blob(&this->blobs[i],
false);
214 this->blobs[i].is_dirty =
true;
218 this->save_meta_data(safe_path);
219 this->path = safe_path;
221 this->cache_cleanup();
225View::save_view (
void)
227 if (this->path.empty())
228 throw std::runtime_error(
"View not initialized");
232 if (this->meta_data.is_dirty)
234 this->save_meta_data(this->path);
239 for (std::size_t i = 0; i < this->images.size(); ++i)
241 if (this->images[i].is_dirty)
243 this->save_image_intern(&this->images[i]);
249 for (std::size_t i = 0; i < this->blobs.size(); ++i)
251 if (this->blobs[i].is_dirty)
253 this->save_blob_intern(&this->blobs[i]);
259 for (std::size_t i = 0; i < this->to_delete.size(); ++i)
268 std::cerr <<
"View: Error deleting " << fname
269 <<
": " << std::strerror(errno) << std::endl;
273 this->to_delete.clear();
283 this->images.clear();
285 this->to_delete.clear();
289View::is_dirty (
void)
const
291 if (this->meta_data.is_dirty)
293 if (!this->to_delete.empty())
295 for (std::size_t i = 0; i < this->images.size(); ++i)
296 if (this->images[i].is_dirty)
298 for (std::size_t i = 0; i < this->blobs.size(); ++i)
299 if (this->blobs[i].is_dirty)
305View::cache_cleanup (
void)
308 for (std::size_t i = 0; i < this->images.size(); ++i)
316 for (std::size_t i = 0; i < this->blobs.size(); ++i)
328View::get_byte_size (
void)
const
331 for (std::size_t i = 0; i < this->images.size(); ++i)
332 if (this->images[i].image !=
nullptr)
333 ret += this->images[i].image->get_byte_size();
334 for (std::size_t i = 0; i < this->blobs.size(); ++i)
335 if (this->blobs[i].blob !=
nullptr)
336 ret += this->blobs[i].blob->get_byte_size();
343View::get_value (std::string
const& key)
const
346 throw std::invalid_argument(
"Empty key");
347 if (key.find_first_of(
'.') == std::string::npos)
348 throw std::invalid_argument(
"Missing section identifier");
349 typedef MetaData::KeyValueMap::const_iterator KeyValueIter;
350 KeyValueIter iter = this->meta_data.data.find(key);
351 if (iter == this->meta_data.data.end())
352 return std::string();
357View::set_value (std::string
const& key, std::string
const& value)
360 throw std::invalid_argument(
"Empty key");
361 if (key.find_first_of(
'.') == std::string::npos)
362 throw std::invalid_argument(
"Missing section identifier");
363 this->meta_data.data[key] = value;
364 this->meta_data.is_dirty =
true;
368View::delete_value (std::string
const& key)
370 this->meta_data.data.erase(key);
376 this->meta_data.camera = camera;
377 this->meta_data.is_dirty =
true;
380 this->set_value(
"camera.focal_length",
382 this->set_value(
"camera.radial_distortion",
385 this->set_value(
"camera.pixel_aspect",
387 this->set_value(
"camera.principal_point",
397View::get_image (std::string
const& name,
ImageType type)
400 if (proxy !=
nullptr)
403 return this->load_image(proxy,
false);
404 this->initialize_image(proxy,
false);
405 if (proxy->
type == type)
406 return this->load_image(proxy,
false);
412View::get_image_proxy (std::string
const& name,
ImageType type)
415 if (proxy !=
nullptr)
417 this->initialize_image(proxy,
false);
425View::has_image (std::string
const& name,
ImageType type)
428 if (proxy ==
nullptr)
432 this->initialize_image(proxy,
false);
433 return proxy->
type == type;
439 if (image ==
nullptr)
440 throw std::invalid_argument(
"Null image");
446 proxy.
width = image->width();
447 proxy.
height = image->height();
449 proxy.
type = image->get_type();
452 for (std::size_t i = 0; i < this->images.size(); ++i)
453 if (this->images[i].name == name)
455 this->images[i] = proxy;
458 this->images.push_back(proxy);
462View::set_image_ref (std::string
const& filename, std::string name)
464 if (filename.empty() || name.empty())
465 throw std::invalid_argument(
"Empty argument");
473 for (std::size_t i = 0; i < this->images.size(); ++i)
474 if (this->images[i].name == name)
476 this->images[i] = proxy;
479 this->images.push_back(proxy);
483View::remove_image (std::string
const& name)
485 for (ImageProxies::iterator iter = this->images.begin();
486 iter != this->images.end(); ++iter)
488 if (iter->name == name)
490 this->to_delete.push_back(iter->filename);
491 this->images.erase(iter);
501View::get_blob (std::string
const& name)
503 BlobProxy* proxy = this->find_blob_intern(name);
504 if (proxy !=
nullptr)
505 return this->load_blob(proxy,
false);
510View::get_blob_proxy (std::string
const& name)
512 BlobProxy* proxy = this->find_blob_intern(name);
513 if (proxy !=
nullptr)
514 this->initialize_blob(proxy,
false);
519View::has_blob (std::string
const& name)
521 return this->find_blob_intern(name) !=
nullptr;
528 throw std::invalid_argument(
"Null blob");
534 proxy.
size = blob->get_byte_size();
537 for (std::size_t i = 0; i < this->blobs.size(); ++i)
538 if (this->blobs[i].name == name)
540 this->blobs[i] = proxy;
543 this->blobs.push_back(proxy);
547View::remove_blob (std::string
const& name)
549 for (BlobProxies::iterator iter = this->blobs.begin();
550 iter != this->blobs.end(); ++iter)
552 if (iter->name == name)
554 this->to_delete.push_back(iter->filename);
555 this->blobs.erase(iter);
565View::deprecated_format_check (std::string
const& path)
571 "The dataset contains views in a deprecated file format.\n"
572 "Please upgrade your datasets using the 'sceneupgrade' app.\n"
573 "See the GitHub wiki for more information about this change.";
575 std::cerr << std::endl <<
"NOTE: " << text << std::endl << std::endl;
576 throw std::invalid_argument(text);
581View::load_meta_data (std::string
const& path)
586 std::ifstream in(fname.c_str());
590 this->meta_data.is_dirty =
false;
594 std::string cam_fl = this->get_value(
"camera.focal_length");
595 std::string cam_dist = this->get_value(
"camera.radial_distortion");
596 std::string cam_pa = this->get_value(
"camera.pixel_aspect");
597 std::string cam_pp = this->get_value(
"camera.principal_point");
598 std::string cam_rot = this->get_value(
"camera.rotation");
599 std::string cam_trans = this->get_value(
"camera.translation");
601 this->meta_data.camera = CameraInfo();
603 this->meta_data.camera.flen = util::string::convert<float>(cam_fl);
604 if (!cam_dist.empty())
606 std::stringstream ss(cam_dist);
607 ss >> this->meta_data.camera.dist[0];
608 ss >> this->meta_data.camera.dist[1];
611 this->meta_data.camera.paspect = util::string::convert<float>(cam_pa);
614 std::stringstream ss(cam_pp);
615 ss >> this->meta_data.camera.ppoint[0];
616 ss >> this->meta_data.camera.ppoint[1];
618 if (!cam_rot.empty())
619 this->meta_data.camera.set_rotation_from_string(cam_rot);
620 if (!cam_trans.empty())
621 this->meta_data.camera.set_translation_from_string(cam_trans);
625View::save_meta_data (std::string
const& path)
629 std::string
const fname_new = fname +
".new";
631 std::ofstream out(fname_new.c_str(), std::ios::binary);
636 out <<
"# MVE view meta data is stored in INI-file syntax.\n";
637 out <<
"# This file is generated, formatting will get lost.\n";
651 this->replace_file(fname, fname_new);
652 this->meta_data.is_dirty =
false;
656View::populate_images_and_blobs (std::string
const& path)
659 for (std::size_t i = 0; i < dir.size(); ++i)
670 std::string name = file.
name.substr(0, file.
name.find_last_of(
'.'));
673 std::cerr <<
"View: Invalid file name "
674 << file.
name <<
", skipping." << std::endl;
679 if (ext4 ==
".png" || ext4 ==
".jpg" ||
680 ext5 ==
".jpeg" || ext5 ==
".mvei")
686 proxy.is_dirty =
false;
687 proxy.filename = file.
name;
689 this->images.push_back(proxy);
691 else if (ext5 ==
".blob")
697 proxy.is_dirty =
false;
698 proxy.filename = file.
name;
700 this->blobs.push_back(proxy);
702 else if (ext4 !=
".ply")
704 std::cerr <<
"View: Unrecognized extension "
705 << file.
name <<
", skipping." << std::endl;
711View::replace_file (std::string
const& old_fn, std::string
const& new_fn)
726View::find_image_intern (std::string
const& name)
728 for (std::size_t i = 0; i < this->images.size(); ++i)
729 if (this->images[i].name == name)
730 return &this->images[i];
735View::initialize_image (ImageProxy* proxy,
bool update)
737 if (proxy->is_initialized && !update)
739 this->load_image_intern(proxy,
true);
743View::load_image (ImageProxy* proxy,
bool update)
745 if (proxy->image !=
nullptr && !update)
747 this->load_image_intern(proxy,
false);
752View::load_image_intern (ImageProxy* proxy,
bool init_only)
755 throw std::runtime_error(
"View not initialized");
756 if (proxy->filename.empty())
757 throw std::runtime_error(
"Empty proxy filename");
758 if (proxy->name.empty())
759 throw std::runtime_error(
"Empty proxy name");
762 std::string filename;
764 filename = proxy->filename;
771 image::ImageHeaders headers = image::load_file_headers(filename);
772 proxy->width = headers.width;
773 proxy->height = headers.height;
774 proxy->channels = headers.channels;
775 proxy->type = headers.type;
776 proxy->is_initialized =
true;
777 proxy->is_dirty =
false;
786 if (ext4 ==
".png" || ext4 ==
".jpg" || ext5 ==
".jpeg")
787 proxy->image = image::load_file(filename);
788 else if (ext5 ==
".mvei")
789 proxy->image = image::load_mvei_file(filename);
791 throw std::runtime_error(
"Unexpected image type");
793 proxy->width = proxy->image->width();
794 proxy->height = proxy->image->height();
795 proxy->channels = proxy->image->channels();
796 proxy->type = proxy->image->get_type();
797 proxy->is_initialized =
true;
798 proxy->is_dirty =
false;
804 get_file_extension (std::string
const& filename)
806 std::size_t pos = filename.find_last_of(
'.');
807 if (pos == std::string::npos)
808 return std::string();
814View::save_image_intern (ImageProxy* proxy)
816 if (this->path.empty())
817 throw std::runtime_error(
"View not initialized");
818 if (proxy ==
nullptr)
819 throw std::runtime_error(
"Null proxy");
824 std::string ext = get_file_extension(proxy->filename);
825 std::string fname = proxy->name + ext;
829 proxy->filename = fname;
830 proxy->is_dirty =
false;
834 if (proxy->image ==
nullptr || proxy->width != proxy->image->width()
835 || proxy->height != proxy->image->height()
836 || proxy->channels != proxy->image->channels()
837 || proxy->type != proxy->image->get_type())
838 throw std::runtime_error(
"Image specification mismatch");
841 bool use_png_format =
false;
842 if (proxy->image->get_type() == IMAGE_TYPE_UINT8
843 && proxy->image->channels() <= 4)
844 use_png_format =
true;
846 std::string filename = proxy->name + (use_png_format ?
".png" :
".mvei");
849 std::string fname_new = fname_save +
".new";
854 image::save_png_file(
855 std::dynamic_pointer_cast<ByteImage>(proxy->image), fname_new);
857 image::save_mvei_file(proxy->image, fname_new);
860 this->replace_file(fname_save, fname_new);
863 if (!proxy->filename.empty() && fname_save != fname_orig)
872 proxy->filename = filename;
873 proxy->width = proxy->image->width();
874 proxy->height = proxy->image->height();
875 proxy->channels = proxy->image->channels();
876 proxy->type = proxy->image->get_type();
877 proxy->is_initialized =
true;
878 proxy->is_dirty =
false;
884View::find_blob_intern (std::string
const& name)
886 for (std::size_t i = 0; i < this->blobs.size(); ++i)
887 if (this->blobs[i].name == name)
888 return &this->blobs[i];
893View::initialize_blob (BlobProxy* proxy,
bool update)
895 if (proxy->is_initialized && !update)
897 this->load_blob_intern(proxy,
true);
901View::load_blob (BlobProxy* proxy,
bool update)
903 if (proxy->blob !=
nullptr && !update)
905 this->load_blob_intern(proxy,
false);
910View::load_blob_intern (BlobProxy* proxy,
bool init_only)
912 if (this->path.empty())
913 throw std::runtime_error(
"View not initialized");
914 if (proxy->name.empty())
919 std::ifstream in(filename.c_str(), std::ios::binary);
932 in.read(
reinterpret_cast<char*
>(&size),
sizeof(uint64_t));
940 proxy->is_initialized =
true;
947 ByteImage::Ptr blob = ByteImage::create(size, 1, 1);
948 in.read(blob->get_byte_pointer(), blob->get_byte_size());
954 proxy->is_initialized =
true;
958View::save_blob_intern (BlobProxy* proxy)
960 if (this->path.empty())
961 throw std::runtime_error(
"View not initialized");
962 if (proxy ==
nullptr || proxy->blob ==
nullptr)
963 throw std::runtime_error(
"Null proxy or data");
964 if (proxy->blob->get_byte_size() != proxy->size)
965 throw std::runtime_error(
"BLOB size mismatch");
968 if (proxy->filename.empty())
969 proxy->filename = proxy->name +
".blob";
973 std::string fname_new = fname_orig +
".new";
977 std::ofstream out(fname_new.c_str(), std::ios::binary);
982 out.write(
reinterpret_cast<char const*
>(&proxy->size),
sizeof(uint64_t));
983 out.write(proxy->blob->get_byte_pointer(), proxy->blob->get_byte_size());
989 this->replace_file(fname_orig, fname_new);
992 proxy->size = proxy->blob->get_byte_size();
993 proxy->is_initialized =
true;
994 proxy->is_dirty =
false;
1000View::debug_print (
void)
1002 for (std::size_t i = 0; i < this->images.size(); ++i)
1003 this->initialize_image(&this->images[i],
false);
1004 for (std::size_t i = 0; i < this->blobs.size(); ++i)
1005 this->initialize_blob(&this->blobs[i],
false);
1007 std::cout << std::endl;
1008 std::cout <<
"Path: " << this->path << std::endl;
1009 std::cout <<
"View Name: " << this->get_value(
"view.name") << std::endl;
1010 std::cout <<
"View key/value pairs:" << std::endl;
1012 typedef MetaData::KeyValueMap::const_iterator KeyValueIter;
1013 for (KeyValueIter iter = this->meta_data.data.begin();
1014 iter != this->meta_data.data.end(); iter++)
1015 std::cout <<
" " << iter->first <<
" = " << iter->second << std::endl;
1017 std::cout <<
"View images:" << std::endl;
1018 for (std::size_t i = 0; i < this->images.size(); ++i)
1021 std::cout <<
" " << proxy.
name <<
" (" << proxy.
filename <<
")"
1023 <<
", type " << proxy.
type
1024 << (proxy.
image !=
nullptr ?
" (in memory)" :
"") << std::endl;
1027 std::cout <<
"View BLOBs:" << std::endl;
1028 for (std::size_t i = 0; i < this->blobs.size(); ++i)
1030 BlobProxy const& proxy = this->blobs[i];
1031 std::cout <<
" " << proxy.
name <<
" (" << proxy.
filename <<
")"
1032 <<
", size " << proxy.
size << std::endl;
std::shared_ptr< ImageBase > Ptr
static ImageType get_type_for_string(std::string const &type_string)
Returns the type for a valid type string, otherwise UNKNOWN.
std::shared_ptr< Image< T > > Ptr
static Ptr create(void)
Smart pointer image constructor.
Universal, simple exception class.
Exception class for file exceptions with additional filename.
std::string concat(std::size_t pos, std::size_t num=0) const
Concatenates 'num' tokens with a space character starting from token at position 'pos'.
void split(std::string const &str, char delim=' ', bool keep_empty=false)
Very simple tokenziation at a given delimiter characater.
Directory abstraction to scan directory contents.
#define MVE_NAMESPACE_BEGIN
#define MVE_NAMESPACE_END
ImageBase::Ptr create_for_type(ImageType type, int64_t width, int64_t height, int64_t chans)
Creates an image instance for a given type.
ImageType
Identifiers for image types.
bool unlink(char const *pathname)
Unlinks (deletes) the given file.
std::string sanitize_path(std::string const &path)
Canonicalize slashes in the given path.
std::string abspath(std::string const &path)
Returns the absolute representation of the given path.
bool is_absolute(std::string const &path)
Checks whether the given path is absolute.
bool mkdir(char const *pathname)
Creates a new directory.
void copy_file(char const *src, char const *dst)
Copies a file from 'src' to 'dst', throws FileException on error.
bool dir_exists(char const *pathname)
Determines if the given path is a directory.
bool rename(char const *from, char const *to)
Renames the given file 'from' to new name 'to'.
std::string join_path(std::string const &path1, std::string const &path2)
Concatenate and canonicalize two paths.
bool file_exists(char const *pathname)
Determines if the given path is a file.
void clip_newlines(std::string *str)
Clips newlines from the end of the string, in-place.
void clip_whitespaces(std::string *str)
Clips whitespaces from the front and end of the string, in-place.
std::string get_digits(T const &value, int digits)
Returns string with 'digits' of precision.
std::string lowercase(std::string const &str)
Returns a lower-case version of the string.
std::string right(std::string const &str, std::size_t chars)
Returns the rightmost 'chars' characters of 'str'.
void write_ini(std::map< std::string, std::string > const &map, std::ostream &stream)
Writes an INI file for the key/value pairs in the map.
void parse_ini(std::istream &stream, std::map< std::string, std::string > *map)
Parses a file in INI format and places key/value pairs in the map.
Per-view camera information with various helper functions.
float paspect
Pixel aspect ratio pixel_width / pixel_height.
std::string get_translation_string(void) const
Retuns the translation in string format.
float ppoint[2]
Principal point in x- and y-direction.
std::string get_rotation_string(void) const
Retuns the rotation in string format.
float dist[2]
Image distortion parameters.
Proxy for BLOBs (Binary Large OBjects).
std::string filename
Filename is empty if the BLOB has not been saved yet, or relative if the BLOB is mapped to the view o...
bool is_dirty
Indicates if the BLOB is unsaved or has been changed.
std::string name
The name of the BLOB.
std::string filename
The filename is empty if the image has not been saved yet.
bool is_dirty
Indicates if the image is unsaved or has been changed.
std::string name
The name of the image.
#define VIEW_IO_BLOB_SIGNATURE_LEN
#define VIEW_IO_META_FILE
#define VIEW_MVE_FILE_SIGNATURE_LEN
#define VIEW_IO_BLOB_SIGNATURE
#define VIEW_MVE_FILE_SIGNATURE