ACloudViewer  3.9.4
A Modern Library for 3D Data Processing
workspace.cc
Go to the documentation of this file.
1 // Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 //
7 // * Redistributions of source code must retain the above copyright
8 // notice, this list of conditions and the following disclaimer.
9 //
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 //
14 // * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
15 // its contributors may be used to endorse or promote products derived
16 // from this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
22 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28 // POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
31 
32 #include "mvs/workspace.h"
33 
34 #include <numeric>
35 
36 #include "util/threading.h"
37 
38 namespace colmap {
39 namespace mvs {
40 
42  : options_(options) {
45  if (options_.max_image_size > 0) {
46  for (auto& image : model_.images) {
48  }
49  }
50 
51  depth_map_path_ = EnsureTrailingSlash(
53  normal_map_path_ = EnsureTrailingSlash(JoinPaths(
55 }
56 
57 std::string Workspace::GetFileName(const int image_idx) const {
58  const auto& image_name = model_.GetImageName(image_idx);
59  return StringPrintf("%s.%s.bin", image_name.c_str(),
60  options_.input_type.c_str());
61 }
62 
63 void Workspace::Load(const std::vector<std::string>& image_names) {
64  const size_t num_images = model_.images.size();
65  bitmaps_.resize(num_images);
66  depth_maps_.resize(num_images);
67  normal_maps_.resize(num_images);
68 
69  auto LoadWorkspaceData = [&, this](const int image_idx) {
70  const size_t width = model_.images.at(image_idx).GetWidth();
71  const size_t height = model_.images.at(image_idx).GetHeight();
72 
73  // Read and rescale bitmap
74  bitmaps_[image_idx].reset(new Bitmap());
75  bitmaps_[image_idx]->Read(GetBitmapPath(image_idx), options_.image_as_rgb);
76  if (options_.max_image_size > 0) {
77  bitmaps_[image_idx]->Rescale((int)width, (int)height);
78  }
79 
80  // Read and rescale depth map
81  depth_maps_[image_idx].reset(new DepthMap());
82  depth_maps_[image_idx]->Read(GetDepthMapPath(image_idx));
83  if (options_.max_image_size > 0) {
84  depth_maps_[image_idx]->Downsize(width, height);
85  }
86 
87  // Read and rescale normal map
88  normal_maps_[image_idx].reset(new NormalMap());
89  normal_maps_[image_idx]->Read(GetNormalMapPath(image_idx));
90  if (options_.max_image_size > 0) {
91  normal_maps_[image_idx]->Downsize(width, height);
92  }
93  };
94 
95  const int num_threads = GetEffectiveNumThreads(options_.num_threads);
96  ThreadPool thread_pool(num_threads);
97  Timer timer;
98  timer.Start();
99 
100  std::cout << StringPrintf("Loading workspace data with %d threads...",
101  num_threads)
102  << std::endl;
103  for (size_t i = 0; i < image_names.size(); ++i) {
104  const int image_idx = model_.GetImageIdx(image_names[i]);
105  if (HasBitmap(image_idx) && HasDepthMap(image_idx)) {
106  thread_pool.AddTask(LoadWorkspaceData, image_idx);
107  } else {
108  std::cout
109  << StringPrintf(
110  "WARNING: Ignoring image %s, because input does not exist.",
111  image_names[i].c_str())
112  << std::endl;
113  }
114  }
115  thread_pool.Wait();
116  timer.PrintMinutes();
117 }
118 
119 const Bitmap& Workspace::GetBitmap(const int image_idx) {
120  return *bitmaps_[image_idx];
121 }
122 
123 const DepthMap& Workspace::GetDepthMap(const int image_idx) {
124  return *depth_maps_[image_idx];
125 }
126 
127 const NormalMap& Workspace::GetNormalMap(const int image_idx) {
128  return *normal_maps_[image_idx];
129 }
130 
131 std::string Workspace::GetBitmapPath(const int image_idx) const {
132  return model_.images.at(image_idx).GetPath();
133 }
134 
135 std::string Workspace::GetDepthMapPath(const int image_idx) const {
136  return depth_map_path_ + GetFileName(image_idx);
137 }
138 
139 std::string Workspace::GetNormalMapPath(const int image_idx) const {
140  return normal_map_path_ + GetFileName(image_idx);
141 }
142 
143 bool Workspace::HasBitmap(const int image_idx) const {
144  return ExistsFile(GetBitmapPath(image_idx));
145 }
146 
147 bool Workspace::HasDepthMap(const int image_idx) const {
148  return ExistsFile(GetDepthMapPath(image_idx));
149 }
150 
151 bool Workspace::HasNormalMap(const int image_idx) const {
152  return ExistsFile(GetNormalMapPath(image_idx));
153 }
154 
155 CachedWorkspace::CachedImage::CachedImage(CachedImage&& other) {
156  num_bytes = other.num_bytes;
157  bitmap = std::move(other.bitmap);
158  depth_map = std::move(other.depth_map);
159  normal_map = std::move(other.normal_map);
160 }
161 
162 CachedWorkspace::CachedImage& CachedWorkspace::CachedImage::operator=(
163  CachedImage&& other) {
164  if (this != &other) {
165  num_bytes = other.num_bytes;
166  bitmap = std::move(other.bitmap);
167  depth_map = std::move(other.depth_map);
168  normal_map = std::move(other.normal_map);
169  }
170  return *this;
171 }
172 
174  : Workspace(options),
175  cache_((size_t)(1024.0 * 1024.0 * 1024.0 * options.cache_size),
176  [](const int) { return std::make_shared<CachedImage>(); }) {}
177 
178 const Bitmap& CachedWorkspace::GetBitmap(const int image_idx) {
179  auto cached_image = cache_.Get(image_idx);
180  std::lock_guard<std::mutex> lock(cached_image->mutex);
181  if (!cached_image->bitmap) {
182  cached_image->bitmap = std::make_unique<Bitmap>();
183  cached_image->bitmap->Read(GetBitmapPath(image_idx), options_.image_as_rgb);
184  if (options_.max_image_size > 0) {
185  cached_image->bitmap->Rescale(model_.images.at(image_idx).GetWidth(),
186  model_.images.at(image_idx).GetHeight());
187  }
188  cached_image->num_bytes += cached_image->bitmap->NumBytes();
189  cache_.UpdateNumBytes(image_idx);
190  }
191  return *cached_image->bitmap;
192 }
193 
194 const DepthMap& CachedWorkspace::GetDepthMap(const int image_idx) {
195  auto cached_image = cache_.Get(image_idx);
196  std::lock_guard<std::mutex> lock(cached_image->mutex);
197  if (!cached_image->depth_map) {
198  cached_image->depth_map = std::make_unique<DepthMap>();
199  cached_image->depth_map->Read(GetDepthMapPath(image_idx));
200  if (options_.max_image_size > 0) {
201  cached_image->depth_map->Downsize(model_.images.at(image_idx).GetWidth(),
202  model_.images.at(image_idx).GetHeight());
203  }
204  cached_image->num_bytes += cached_image->depth_map->GetNumBytes();
205  cache_.UpdateNumBytes(image_idx);
206  }
207  return *cached_image->depth_map;
208 }
209 
210 const NormalMap& CachedWorkspace::GetNormalMap(const int image_idx) {
211  auto cached_image = cache_.Get(image_idx);
212  std::lock_guard<std::mutex> lock(cached_image->mutex);
213  if (!cached_image->normal_map) {
214  cached_image->normal_map = std::make_unique<NormalMap>();
215  cached_image->normal_map->Read(GetNormalMapPath(image_idx));
216  if (options_.max_image_size > 0) {
217  cached_image->normal_map->Downsize(
218  model_.images.at(image_idx).GetWidth(),
219  model_.images.at(image_idx).GetHeight());
220  }
221  cached_image->num_bytes += cached_image->normal_map->GetNumBytes();
222  cache_.UpdateNumBytes(image_idx);
223  }
224  return *cached_image->normal_map;
225 }
226 
227 void ImportPMVSWorkspace(const Workspace& workspace,
228  const std::string& option_name) {
229  const std::string& workspace_path = workspace.GetOptions().workspace_path;
230  const std::string& stereo_folder = workspace.GetOptions().stereo_folder;
231 
232  CreateDirIfNotExists(JoinPaths(workspace_path, stereo_folder));
233  CreateDirIfNotExists(JoinPaths(workspace_path, stereo_folder, "depth_maps"));
234  CreateDirIfNotExists(JoinPaths(workspace_path, stereo_folder, "normal_maps"));
236  JoinPaths(workspace_path, stereo_folder, "consistency_graphs"));
237 
238  const auto option_lines =
239  ReadTextFileLines(JoinPaths(workspace_path, option_name));
240  for (const auto& line : option_lines) {
241  if (!StringStartsWith(line, "timages")) {
242  continue;
243  }
244 
245  const auto elems = StringSplit(line, " ");
246  int num_images = std::stoull(elems[1]);
247 
248  std::vector<int> image_idxs;
249  if (num_images == -1) {
250  CHECK_EQ(elems.size(), 4);
251  const int range_lower = std::stoull(elems[2]);
252  const int range_upper = std::stoull(elems[3]);
253  CHECK_LT(range_lower, range_upper);
254  num_images = range_upper - range_lower;
255  image_idxs.resize(num_images);
256  std::iota(image_idxs.begin(), image_idxs.end(), range_lower);
257  } else {
258  CHECK_EQ(num_images + 2, elems.size());
259  image_idxs.reserve(num_images);
260  for (size_t i = 2; i < elems.size(); ++i) {
261  const int image_idx = std::stoull(elems[i]);
262  image_idxs.push_back(image_idx);
263  }
264  }
265 
266  std::vector<std::string> image_names;
267  image_names.reserve(num_images);
268  for (const auto image_idx : image_idxs) {
269  const std::string image_name =
270  workspace.GetModel().GetImageName(image_idx);
271  image_names.push_back(image_name);
272  }
273 
274  const auto& overlapping_images =
276 
277  const auto patch_match_path =
278  JoinPaths(workspace_path, stereo_folder, "patch-match.cfg");
279  const auto fusion_path =
280  JoinPaths(workspace_path, stereo_folder, "fusion.cfg");
281  std::ofstream patch_match_file(patch_match_path, std::ios::trunc);
282  std::ofstream fusion_file(fusion_path, std::ios::trunc);
283  CHECK(patch_match_file.is_open()) << patch_match_path;
284  CHECK(fusion_file.is_open()) << fusion_path;
285  for (size_t i = 0; i < image_names.size(); ++i) {
286  const auto& ref_image_name = image_names[i];
287  patch_match_file << ref_image_name << std::endl;
288  if (overlapping_images.empty()) {
289  patch_match_file << "__auto__, 20" << std::endl;
290  } else {
291  for (const int image_idx : overlapping_images[i]) {
292  patch_match_file << workspace.GetModel().GetImageName(image_idx)
293  << ", ";
294  }
295  patch_match_file << std::endl;
296  }
297  fusion_file << ref_image_name << std::endl;
298  }
299  }
300 }
301 
302 } // namespace mvs
303 } // namespace colmap
std::shared_ptr< core::Tensor > image
int width
int height
std::shared_ptr< value_t > Get(const key_t &key)
Definition: cache.h:352
void UpdateNumBytes(const key_t &key)
Definition: cache.h:405
auto AddTask(func_t &&f, args_t &&... args) -> std::future< typename std::result_of< func_t(args_t...)>::type >
Definition: threading.h:299
void Start()
Definition: timer.cc:43
void PrintMinutes() const
Definition: timer.cc:93
const Bitmap & GetBitmap(const int image_idx) override
Definition: workspace.cc:178
const DepthMap & GetDepthMap(const int image_idx) override
Definition: workspace.cc:194
CachedWorkspace(const Options &options)
Definition: workspace.cc:173
const NormalMap & GetNormalMap(const int image_idx) override
Definition: workspace.cc:210
std::string GetFileName(const int image_idx) const
Definition: workspace.cc:57
virtual const NormalMap & GetNormalMap(const int image_idx)
Definition: workspace.cc:127
const Options & GetOptions() const
Definition: workspace.h:48
virtual const DepthMap & GetDepthMap(const int image_idx)
Definition: workspace.cc:123
virtual void Load(const std::vector< std::string > &image_names)
Definition: workspace.cc:63
std::string GetDepthMapPath(const int image_idx) const
Definition: workspace.cc:135
bool HasBitmap(const int image_idx) const
Definition: workspace.cc:143
Workspace(const Options &options)
Definition: workspace.cc:41
bool HasNormalMap(const int image_idx) const
Definition: workspace.cc:151
const Model & GetModel() const
Definition: workspace.h:50
bool HasDepthMap(const int image_idx) const
Definition: workspace.cc:147
std::string GetBitmapPath(const int image_idx) const
Definition: workspace.cc:131
virtual const Bitmap & GetBitmap(const int image_idx)
Definition: workspace.cc:119
std::string GetNormalMapPath(const int image_idx) const
Definition: workspace.cc:139
QTextStream & endl(QTextStream &stream)
Definition: QtCompat.h:718
void ImportPMVSWorkspace(const Workspace &workspace, const std::string &option_name)
Definition: workspace.cc:227
bool StringStartsWith(const std::string &str, const std::string &prefix)
Definition: string.cc:173
void StringToLower(std::string *str)
Definition: string.cc:193
std::vector< std::string > ReadTextFileLines(const std::string &path)
Definition: misc.cc:308
bool ExistsFile(const std::string &path)
Definition: misc.cc:100
void CreateDirIfNotExists(const std::string &path)
Definition: misc.cc:112
std::string JoinPaths(T const &... paths)
Definition: misc.h:128
std::string EnsureTrailingSlash(const std::string &str)
Definition: misc.cc:40
std::vector< std::string > StringSplit(const std::string &str, const std::string &delim)
Definition: string.cc:166
std::string StringPrintf(const char *format,...)
Definition: string.cc:131
int GetEffectiveNumThreads(const int num_threads)
Definition: threading.cc:269
std::string GetImageName(const int image_idx) const
Definition: model.cc:133
int GetImageIdx(const std::string &name) const
Definition: model.cc:127
std::vector< Image > images
Definition: model.h:72
void Read(const std::string &path, const std::string &format)
Definition: model.cc:44
const std::vector< std::vector< int > > & GetMaxOverlappingImagesFromPMVS() const
Definition: model.cc:191