forked from colmap/colmap
-
Notifications
You must be signed in to change notification settings - Fork 1
/
database.h
executable file
·390 lines (316 loc) · 15.5 KB
/
database.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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
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
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
// Copyright (c) 2018, ETH Zurich and UNC Chapel Hill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
#ifndef COLMAP_SRC_BASE_DATABASE_H_
#define COLMAP_SRC_BASE_DATABASE_H_
#include <mutex>
#include <unordered_map>
#include <vector>
#include <Eigen/Core>
#include "SQLite/sqlite3.h"
#include "base/camera.h"
#include "base/image.h"
#include "estimators/two_view_geometry.h"
#include "feature/types.h"
#include "util/types.h"
namespace colmap {
// Database class to read and write images, features, cameras, matches, etc.
// from a SQLite database. The class is not thread-safe and must not be accessed
// concurrently. The class is optimized for single-thread speed and for optimal
// performance, wrap multiple method calls inside a leading `BeginTransaction`
// and trailing `EndTransaction`.
class Database {
public:
const static int kSchemaVersion = 1;
// The maximum number of images, that can be stored in the database.
// This limitation arises due to the fact, that we generate unique IDs for
// image pairs manually. Note: do not change this to
// another type than `size_t`.
const static size_t kMaxNumImages;
Database();
explicit Database(const std::string& path);
~Database();
// Open and close database. The same database should not be opened
// concurrently in multiple threads or processes.
void Open(const std::string& path);
void Close();
// Check if entry already exists in database. For image pairs, the order of
// `image_id1` and `image_id2` does not matter.
bool ExistsCamera(const camera_t camera_id) const;
bool ExistsImage(const image_t image_id) const;
bool ExistsImageWithName(std::string name) const;
bool ExistsKeypoints(const image_t image_id) const;
bool ExistsDescriptors(const image_t image_id) const;
bool ExistsMatches(const image_t image_id1, const image_t image_id2) const;
bool ExistsInlierMatches(const image_t image_id1,
const image_t image_id2) const;
// Number of rows in `cameras` table.
size_t NumCameras() const;
// Number of rows in `images` table.
size_t NumImages() const;
// Sum of `rows` column in `keypoints` table, i.e. number of total keypoints.
size_t NumKeypoints() const;
// The number of keypoints for the image with most features.
size_t MaxNumKeypoints() const;
// Number of descriptors for specific image.
size_t NumKeypointsForImage(const image_t image_id) const;
// Sum of `rows` column in `descriptors` table,
// i.e. number of total descriptors.
size_t NumDescriptors() const;
// The number of descriptors for the image with most features.
size_t MaxNumDescriptors() const;
// Number of descriptors for specific image.
size_t NumDescriptorsForImage(const image_t image_id) const;
// Sum of `rows` column in `matches` table, i.e. number of total matches.
size_t NumMatches() const;
// Sum of `rows` column in `two_view_geometries` table,
// i.e. number of total inlier matches.
size_t NumInlierMatches() const;
// Number of rows in `matches` table.
size_t NumMatchedImagePairs() const;
// Number of rows in `two_view_geometries` table.
size_t NumVerifiedImagePairs() const;
// Each image pair is assigned an unique ID in the `matches` and
// `two_view_geometries` table. We intentionally avoid to store the pairs in a
// separate table by using e.g. AUTOINCREMENT, since the overhead of querying
// the unique pair ID is significant.
inline static image_pair_t ImagePairToPairId(const image_t image_id1,
const image_t image_id2);
inline static void PairIdToImagePair(const image_pair_t pair_id,
image_t* image_id1, image_t* image_id2);
// Return true if image pairs should be swapped. Used to enforce a specific
// image order to generate unique image pair identifiers independent of the
// order in which the image identifiers are used.
inline static bool SwapImagePair(const image_t image_id1,
const image_t image_id2);
// Read an existing entry in the database. The user is responsible for making
// sure that the entry actually exists. For image pairs, the order of
// `image_id1` and `image_id2` does not matter.
Camera ReadCamera(const camera_t camera_id) const;
std::vector<Camera> ReadAllCameras() const;
Image ReadImage(const image_t image_id) const;
Image ReadImageWithName(const std::string& name) const;
std::vector<Image> ReadAllImages() const;
FeatureKeypoints ReadKeypoints(const image_t image_id) const;
FeatureDescriptors ReadDescriptors(const image_t image_id) const;
FeatureMatches ReadMatches(const image_t image_id1,
const image_t image_id2) const;
std::vector<std::pair<image_pair_t, FeatureMatches>> ReadAllMatches() const;
TwoViewGeometry ReadTwoViewGeometry(const image_t image_id1,
const image_t image_id2) const;
void ReadTwoViewGeometries(
std::vector<image_pair_t>* image_pair_ids,
std::vector<TwoViewGeometry>* two_view_geometries) const;
// Read all image pairs that have an entry in the `NumVerifiedImagePairs`
// table with at least one inlier match and their number of inlier matches.
void ReadTwoViewGeometryNumInliers(
std::vector<std::pair<image_t, image_t>>* image_pairs,
std::vector<int>* num_inliers) const;
// Add new camera and return its database identifier. If `use_camera_id`
// is false a new identifier is automatically generated.
camera_t WriteCamera(const Camera& camera,
const bool use_camera_id = false) const;
// Add new image and return its database identifier. If `use_image_id`
// is false a new identifier is automatically generated.
image_t WriteImage(const Image& image, const bool use_image_id = false) const;
// Write a new entry in the database. The user is responsible for making sure
// that the entry does not yet exist. For image pairs, the order of
// `image_id1` and `image_id2` does not matter.
void WriteKeypoints(const image_t image_id,
const FeatureKeypoints& keypoints) const;
void WriteDescriptors(const image_t image_id,
const FeatureDescriptors& descriptors) const;
void WriteMatches(const image_t image_id1, const image_t image_id2,
const FeatureMatches& matches) const;
void WriteTwoViewGeometry(const image_t image_id1, const image_t image_id2,
const TwoViewGeometry& two_view_geometry) const;
// Update an existing camera in the database. The user is responsible for
// making sure that the entry already exists.
void UpdateCamera(const Camera& camera) const;
// Update an existing image in the database. The user is responsible for
// making sure that the entry already exists.
void UpdateImage(const Image& image) const;
// Delete matches of an image pair.
void DeleteMatches(const image_t image_id1, const image_t image_id2) const;
// Delete inlier matches of an image pair.
void DeleteInlierMatches(const image_t image_id1,
const image_t image_id2) const;
// Clear all database tables
void ClearAllTables() const;
// Clear the entire cameras table
void ClearCameras() const;
// Clear the entire images, keypoints, and descriptors tables
void ClearImages() const;
// Clear the entire descriptors table
void ClearDescriptors() const;
// Clear the entire keypoints table
void ClearKeypoints() const;
// Clear the entire matches table.
void ClearMatches() const;
// Clear the entire inlier matches table.
void ClearTwoViewGeometries() const;
// Merge two databases into a single, new database.
static void Merge(const Database& database1, const Database& database2,
Database* merged_database);
private:
friend class DatabaseTransaction;
// Combine multiple queries into one transaction by wrapping a code section
// into a `BeginTransaction` and `EndTransaction`. You can create a scoped
// transaction with `DatabaseTransaction` that ends when the transaction
// object is destructed. Combining queries results in faster transaction time
// due to reduced locking of the database etc.
void BeginTransaction() const;
void EndTransaction() const;
// Prepare SQL statements once at construction of the database, and reuse
// the statements for multiple queries by resetting their states.
void PrepareSQLStatements();
void FinalizeSQLStatements();
// Create database tables, if not existing, called when opening a database.
void CreateTables() const;
void CreateCameraTable() const;
void CreateImageTable() const;
void CreateKeypointsTable() const;
void CreateDescriptorsTable() const;
void CreateMatchesTable() const;
void CreateTwoViewGeometriesTable() const;
void UpdateSchema() const;
bool ExistsTable(const std::string& table_name) const;
bool ExistsColumn(const std::string& table_name,
const std::string& column_name) const;
bool ExistsRowId(sqlite3_stmt* sql_stmt, const sqlite3_int64 row_id) const;
bool ExistsRowString(sqlite3_stmt* sql_stmt,
const std::string& row_entry) const;
size_t CountRows(const std::string& table) const;
size_t CountRowsForEntry(sqlite3_stmt* sql_stmt,
const sqlite3_int64 row_id) const;
size_t SumColumn(const std::string& column, const std::string& table) const;
size_t MaxColumn(const std::string& column, const std::string& table) const;
sqlite3* database_ = nullptr;
// Ensure that only one database object at a time updates the schema of a
// database. Since the schema is updated every time a database is opened, this
// is to ensure that there are no race conditions ("database locked" error
// messages) when the user actually only intends to read from the database,
// which requires to open it.
static std::mutex update_schema_mutex_;
// Used to ensure that only one transaction is active at the same time.
std::mutex transaction_mutex_;
// A collection of all `sqlite3_stmt` objects for deletion in the destructor.
std::vector<sqlite3_stmt*> sql_stmts_;
// num_*
sqlite3_stmt* sql_stmt_num_keypoints_ = nullptr;
sqlite3_stmt* sql_stmt_num_descriptors_ = nullptr;
// exists_*
sqlite3_stmt* sql_stmt_exists_camera_ = nullptr;
sqlite3_stmt* sql_stmt_exists_image_id_ = nullptr;
sqlite3_stmt* sql_stmt_exists_image_name_ = nullptr;
sqlite3_stmt* sql_stmt_exists_keypoints_ = nullptr;
sqlite3_stmt* sql_stmt_exists_descriptors_ = nullptr;
sqlite3_stmt* sql_stmt_exists_matches_ = nullptr;
sqlite3_stmt* sql_stmt_exists_two_view_geometry_ = nullptr;
// add_*
sqlite3_stmt* sql_stmt_add_camera_ = nullptr;
sqlite3_stmt* sql_stmt_add_image_ = nullptr;
// update_*
sqlite3_stmt* sql_stmt_update_camera_ = nullptr;
sqlite3_stmt* sql_stmt_update_image_ = nullptr;
// read_*
sqlite3_stmt* sql_stmt_read_camera_ = nullptr;
sqlite3_stmt* sql_stmt_read_cameras_ = nullptr;
sqlite3_stmt* sql_stmt_read_image_id_ = nullptr;
sqlite3_stmt* sql_stmt_read_image_name_ = nullptr;
sqlite3_stmt* sql_stmt_read_images_ = nullptr;
sqlite3_stmt* sql_stmt_read_keypoints_ = nullptr;
sqlite3_stmt* sql_stmt_read_descriptors_ = nullptr;
sqlite3_stmt* sql_stmt_read_matches_ = nullptr;
sqlite3_stmt* sql_stmt_read_matches_all_ = nullptr;
sqlite3_stmt* sql_stmt_read_two_view_geometry_ = nullptr;
sqlite3_stmt* sql_stmt_read_two_view_geometries_ = nullptr;
sqlite3_stmt* sql_stmt_read_two_view_geometry_num_inliers_ = nullptr;
// write_*
sqlite3_stmt* sql_stmt_write_keypoints_ = nullptr;
sqlite3_stmt* sql_stmt_write_descriptors_ = nullptr;
sqlite3_stmt* sql_stmt_write_matches_ = nullptr;
sqlite3_stmt* sql_stmt_write_two_view_geometry_ = nullptr;
// delete_*
sqlite3_stmt* sql_stmt_delete_matches_ = nullptr;
sqlite3_stmt* sql_stmt_delete_two_view_geometry_ = nullptr;
// clear_*
sqlite3_stmt* sql_stmt_clear_cameras_ = nullptr;
sqlite3_stmt* sql_stmt_clear_images_ = nullptr;
sqlite3_stmt* sql_stmt_clear_descriptors_ = nullptr;
sqlite3_stmt* sql_stmt_clear_keypoints_ = nullptr;
sqlite3_stmt* sql_stmt_clear_matches_ = nullptr;
sqlite3_stmt* sql_stmt_clear_two_view_geometries_ = nullptr;
};
// This class automatically manages the scope of a database transaction by
// calling `BeginTransaction` and `EndTransaction` during construction and
// destruction, respectively.
class DatabaseTransaction {
public:
explicit DatabaseTransaction(Database* database);
~DatabaseTransaction();
private:
NON_COPYABLE(DatabaseTransaction)
NON_MOVABLE(DatabaseTransaction)
Database* database_;
std::unique_lock<std::mutex> database_lock_;
};
////////////////////////////////////////////////////////////////////////////////
// Implementation
////////////////////////////////////////////////////////////////////////////////
image_pair_t Database::ImagePairToPairId(const image_t image_id1,
const image_t image_id2) {
CHECK_GE(image_id1, 0);
CHECK_GE(image_id2, 0);
CHECK_LT(image_id1, kMaxNumImages);
CHECK_LT(image_id2, kMaxNumImages);
if (SwapImagePair(image_id1, image_id2)) {
return static_cast<image_pair_t>(kMaxNumImages) * image_id2 + image_id1;
} else {
return static_cast<image_pair_t>(kMaxNumImages) * image_id1 + image_id2;
}
}
void Database::PairIdToImagePair(const image_pair_t pair_id, image_t* image_id1,
image_t* image_id2) {
*image_id2 = static_cast<image_t>(pair_id % kMaxNumImages);
*image_id1 = static_cast<image_t>((pair_id - *image_id2) / kMaxNumImages);
CHECK_GE(*image_id1, 0);
CHECK_GE(*image_id2, 0);
CHECK_LT(*image_id1, kMaxNumImages);
CHECK_LT(*image_id2, kMaxNumImages);
}
// Return true if image pairs should be swapped. Used to enforce a specific
// image order to generate unique image pair identifiers independent of the
// order in which the image identifiers are used.
bool Database::SwapImagePair(const image_t image_id1, const image_t image_id2) {
return image_id1 > image_id2;
}
} // namespace colmap
#endif // COLMAP_SRC_BASE_DATABASE_H_