00001 #include <kidnapped_robot/place_database.h>
00002 #include <opencv/highgui.h>
00003 #include <cassert>
00004
00005 namespace kidnapped_robot {
00006
00007
00008 template<typename T>
00009 void PlaceDatabase::bindVector(sqlite3_stmt *stmt, int col, const std::vector<T>& vec)
00010 {
00011 checkErr(sqlite3_bind_blob(stmt, col, &vec[0], vec.size() * sizeof(T), SQLITE_TRANSIENT),
00012 "Couldn't bind vector data");
00013 }
00014
00015 template<typename T>
00016 void extractVector(sqlite3_stmt *stmt, int col, std::vector<T>& vec, int num_items = -1)
00017 {
00018 const void* data = sqlite3_column_blob(stmt, col);
00019 int bytes = sqlite3_column_bytes(stmt, col);
00020 if (num_items == -1)
00021 num_items = bytes / sizeof(T);
00022 assert(bytes == num_items * (int)sizeof(T));
00023 vec.resize(num_items);
00024 memcpy(&vec[0], data, bytes);
00025 }
00026
00027 PlaceDatabase::PlaceDatabase()
00028 : persistent_db_(NULL),
00029 insert_stmt_(NULL), select_transforms_stmt_(NULL), select_frame_stmt_(NULL),
00030 select_spatial_stmt_(NULL), select_images_stmt_(NULL)
00031 {
00032 }
00033
00034 PlaceDatabase::PlaceDatabase(const std::string& db_file, const std::string& tree_file, const std::string& weights_file)
00035 : persistent_db_(NULL),
00036 insert_stmt_(NULL), select_transforms_stmt_(NULL), select_frame_stmt_(NULL),
00037 select_spatial_stmt_(NULL), select_images_stmt_(NULL)
00038 {
00039 load(db_file, tree_file, weights_file);
00040 }
00041
00042 PlaceDatabase::~PlaceDatabase()
00043 {
00044
00045 checkErr(sqlite3_finalize(insert_stmt_), "Couldn't finalize INSERT statement");
00046 checkErr(sqlite3_finalize(select_transforms_stmt_), "Couldn't finalize SELECT transforms statement");
00047 checkErr(sqlite3_finalize(select_frame_stmt_), "Couldn't finalize SELECT frame statement");
00048 checkErr(sqlite3_finalize(select_spatial_stmt_), "Couldn't finalize SELECT spatial statement");
00049 checkErr(sqlite3_finalize(select_images_stmt_), "Couldn't finalize SELECT images statement");
00050
00051
00052 checkErr(sqlite3_close(persistent_db_), "Couldn't close database");
00053 }
00054
00055 void PlaceDatabase::load(const std::string& db_file, const std::string& tree_file, const std::string& weights_file)
00056 {
00057 loadPersistentDatabase(db_file);
00058 voctree_.load(tree_file);
00059 loadDocumentDatabase(weights_file);
00060 prepareReusedStatements();
00061 }
00062
00063 void PlaceDatabase::loadPersistentDatabase(const std::string& db_file)
00064 {
00065
00066 checkErr(sqlite3_open(db_file.c_str(), &persistent_db_), "Couldn't open database");
00067
00068
00069 static const char CREATE_TABLE_SQL[] =
00070 "CREATE TABLE IF NOT EXISTS places"
00071
00072 "(id INTEGER PRIMARY KEY,"
00073
00074 " stamp INTEGER,"
00075
00076 " map_position_x DOUBLE, map_position_y DOUBLE, map_position_z DOUBLE,"
00077 " map_orientation_x DOUBLE, map_orientation_y DOUBLE, map_orientation_z DOUBLE, map_orientation_w DOUBLE,"
00078
00079 " optical_position_x DOUBLE, optical_position_y DOUBLE, optical_position_z DOUBLE,"
00080 " optical_orientation_x DOUBLE, optical_orientation_y DOUBLE,"
00081 " optical_orientation_z DOUBLE, optical_orientation_w DOUBLE,"
00082
00083 " cam_fx DOUBLE, cam_fy DOUBLE, cam_cx DOUBLE, cam_cy DOUBLE, cam_tx DOUBLE,"
00084
00085 " disparities BLOB, good_points BLOB,"
00086
00087 " num_keypoints INTEGER, keypoints BLOB, descriptor_length INTEGER, descriptor_data BLOB,"
00088
00089 " document BLOB,"
00090
00091 " left_image BLOB, right_image BLOB)";
00092 checkErr(sqlite3_exec(persistent_db_, CREATE_TABLE_SQL, NULL, NULL, NULL), "Couldn't CREATE TABLE");
00093
00094
00096 static const char CREATE_INDEX_SQL[] = "CREATE INDEX IF NOT EXISTS place_index ON places(map_position_x)";
00097 checkErr(sqlite3_exec(persistent_db_, CREATE_INDEX_SQL, NULL, NULL, NULL), "Couldn't CREATE INDEX");
00098 }
00099
00100 void PlaceDatabase::loadDocumentDatabase(const std::string& weights_file)
00101 {
00102 document_db_.loadWeights(weights_file);
00103
00104
00105 static const char SELECT_DOC_SQL[] = "SELECT id, document FROM places";
00106 sqlite3_stmt *stmt = NULL;
00107 checkErr(sqlite3_prepare_v2(persistent_db_, SELECT_DOC_SQL, sizeof(SELECT_DOC_SQL), &stmt, NULL),
00108 "Couldn't prepare SELECT documents statement");
00109
00110 vt::Document words;
00111 int err;
00112 int64_t id = 0;
00113 while ((err = sqlite3_step(stmt)) == SQLITE_ROW) {
00114 id = sqlite3_column_int(stmt, 0);
00115 extractVector(stmt, 1, words);
00116 vt::DocId doc_id = document_db_.insert(words);
00117 doc_to_place_id_[doc_id] = id;
00118 }
00119 printf("Last loaded document id = %d\n", (int)id);
00120 checkErr(err, "Error executing spatial query", SQLITE_DONE);
00121
00122 checkErr(sqlite3_finalize(stmt), "Couldn't finalize SELECT documents statement");
00123 }
00124
00125 void PlaceDatabase::prepareReusedStatements()
00126 {
00127
00128 static const char INSERT_SQL[] =
00129 "INSERT INTO places VALUES "
00130 "($id, $stamp,"
00131 " $map_pos_x, $map_pos_y, $map_pos_z, $map_ori_x, $map_ori_y, $map_ori_z, $map_ori_w,"
00132 " $opt_pos_x, $opt_pos_y, $opt_pos_z, $opt_ori_x, $opt_ori_y, $opt_ori_z, $opt_ori_w,"
00133 " $fx, $fy, $cx, $cy, $tx, $disps, $good_pts,"
00134 " $num_pts, $keypts, $desc_len, $desc_data, $document, $left, $right)";
00135 checkErr(sqlite3_prepare_v2(persistent_db_, INSERT_SQL, sizeof(INSERT_SQL), &insert_stmt_, NULL),
00136 "Couldn't prepare INSERT statement");
00137
00138 map_pose_param_index_ = sqlite3_bind_parameter_index(insert_stmt_, "$map_pos_x");
00139 optical_transform_param_index_ = sqlite3_bind_parameter_index(insert_stmt_, "$opt_pos_x");
00140 camera_param_index_ = sqlite3_bind_parameter_index(insert_stmt_, "$fx");
00141 disparities_param_index_ = sqlite3_bind_parameter_index(insert_stmt_, "$disps");
00142 keypoints_param_index_ = sqlite3_bind_parameter_index(insert_stmt_, "$num_pts");
00143
00144 assert(map_pose_param_index_ != 0);
00145 assert(optical_transform_param_index_ != 0);
00146 assert(camera_param_index_ != 0);
00147 assert(disparities_param_index_ != 0);
00148 assert(keypoints_param_index_ != 0);
00149
00150
00151 static const char SELECT_TRANSFORMS_SQL[] =
00152 "SELECT map_position_x, map_position_y, map_position_z,"
00153 " map_orientation_x, map_orientation_y, map_orientation_z, map_orientation_w,"
00154 " optical_position_x, optical_position_y, optical_position_z,"
00155 " optical_orientation_x, optical_orientation_y, optical_orientation_z, optical_orientation_w "
00156 "FROM places WHERE id = ?";
00157 checkErr(sqlite3_prepare_v2(persistent_db_, SELECT_TRANSFORMS_SQL, sizeof(SELECT_TRANSFORMS_SQL),
00158 &select_transforms_stmt_, NULL),
00159 "Couldn't prepare SELECT transforms statement");
00160
00161
00162 static const char SELECT_FRAME_SQL[] =
00163 "SELECT cam_fx, cam_fy, cam_cx, cam_cy, cam_tx, disparities, good_points,"
00164 " num_keypoints, keypoints, descriptor_length, descriptor_data "
00165 "FROM places WHERE id = ?";
00166 checkErr(sqlite3_prepare_v2(persistent_db_, SELECT_FRAME_SQL, sizeof(SELECT_FRAME_SQL),
00167 &select_frame_stmt_, NULL),
00168 "Couldn't prepare SELECT frame statement");
00169
00170
00171 static const char SELECT_SPATIAL_SQL[] =
00172 "SELECT id FROM places WHERE map_position_x BETWEEN $min_x AND $max_x AND"
00173 " map_position_y BETWEEN $min_y AND $max_y"
00174 " ORDER BY id";
00175 checkErr(sqlite3_prepare_v2(persistent_db_, SELECT_SPATIAL_SQL, sizeof(SELECT_SPATIAL_SQL),
00176 &select_spatial_stmt_, NULL),
00177 "Couldn't prepare SELECT spatial statement");
00178
00179 static const char SELECT_IMAGES_SQL[] = "SELECT left_image, right_image FROM places WHERE id = ?";
00180 checkErr(sqlite3_prepare_v2(persistent_db_, SELECT_IMAGES_SQL, sizeof(SELECT_IMAGES_SQL),
00181 &select_images_stmt_, NULL),
00182 "Couldn't prepare SELECT images statement");
00183 }
00184
00185 int64_t PlaceDatabase::add(ros::Time stamp, const tf::Pose& pose_in_map, const tf::Transform& optical_transform,
00186 const frame_common::Frame& frame, int64_t id)
00187 {
00188 assert((int)frame.kpts.size() == frame.dtors.rows);
00189
00190
00191 vt::Document words(frame.dtors.rows);
00192 for (int i = 0; i < frame.dtors.rows; ++i)
00193 words[i] = voctree_.quantize(frame.dtors.row(i));
00194 vt::DocId doc_id = document_db_.insert(words);
00195
00196
00197 if (id == AUTO_ID)
00198 id = doc_id;
00199 doc_to_place_id_[doc_id] = id;
00200
00202 checkErr(sqlite3_bind_int64(insert_stmt_, 1, id), "Couldn't bind row id");
00203
00204
00205 sqlite3_int64 time = stamp.toNSec();
00206 checkErr(sqlite3_bind_int64(insert_stmt_, 2, time), "Couldn't bind stamp");
00207
00208
00209 bindTransform(pose_in_map, map_pose_param_index_);
00210 bindTransform(optical_transform, optical_transform_param_index_);
00211
00212
00213 bindCameraParams(frame.cam);
00214
00215
00216 int disp_index = disparities_param_index_;
00217 bindVector(insert_stmt_, disp_index, frame.disps);
00218 bindVector(insert_stmt_, disp_index + 1, frame.goodPts);
00219
00220
00221 int keypt_index = keypoints_param_index_;
00222 checkErr(sqlite3_bind_int(insert_stmt_, keypt_index, frame.kpts.size()), "Couldn't bind num_keypoints");
00223 bindVector(insert_stmt_, keypt_index + 1, frame.kpts);
00224
00225
00226 checkErr(sqlite3_bind_int(insert_stmt_, keypt_index + 2, frame.dtors.cols), "Couldn't bind descriptor_length");
00227 checkErr(sqlite3_bind_blob(insert_stmt_, keypt_index + 3, frame.dtors.data,
00228 frame.dtors.rows * frame.dtors.step, SQLITE_TRANSIENT),
00229 "Couldn't bind descriptor data");
00230
00231
00232 bindVector(insert_stmt_, keypt_index + 4, words);
00233
00234
00235 bindImage(keypt_index + 5, frame.img);
00236 bindImage(keypt_index + 6, frame.imgRight);
00237
00238
00239 checkErr(sqlite3_step(insert_stmt_), "INSERT statement not done", SQLITE_DONE);
00240
00241
00242 checkErr(sqlite3_reset(insert_stmt_), "Couldn't reset INSERT statement");
00243 checkErr(sqlite3_clear_bindings(insert_stmt_), "Couldn't clear bindings on INSERT statement");
00244
00245
00246 return id;
00247 }
00248
00249 void PlaceDatabase::findMatching(const frame_common::Frame& query_frame, size_t N, vt::Matches& matches) const
00250 {
00252 vt::Document words(query_frame.dtors.rows);
00253 for (int i = 0; i < query_frame.dtors.rows; ++i)
00254 words[i] = voctree_.quantize(query_frame.dtors.row(i));
00255 document_db_.find(words, N, matches);
00256
00257 for (int i = 0; i < (int)matches.size(); ++i)
00258 {
00259 vt::DocId &id = matches[i].id;
00260 IdMap::const_iterator iter = doc_to_place_id_.find(id);
00261 assert(iter != doc_to_place_id_.end());
00262 id = iter->second;
00263 }
00264 }
00265
00266 void PlaceDatabase::findInRegion(cv::Rect_<double> bounding_box, std::vector<int64_t>& ids) const
00267 {
00268
00269 checkErr(sqlite3_bind_double(select_spatial_stmt_, 1, bounding_box.x), "Bind error");
00270 checkErr(sqlite3_bind_double(select_spatial_stmt_, 2, bounding_box.x + bounding_box.width), "Bind error");
00271 checkErr(sqlite3_bind_double(select_spatial_stmt_, 3, bounding_box.y), "Bind error");
00272 checkErr(sqlite3_bind_double(select_spatial_stmt_, 4, bounding_box.y + bounding_box.height), "Bind error");
00273
00274 ids.clear();
00275 int err;
00276 while ((err = sqlite3_step(select_spatial_stmt_)) == SQLITE_ROW)
00277 ids.push_back( sqlite3_column_int(select_spatial_stmt_, 0) );
00278
00279 checkErr(err, "Error executing spatial query", SQLITE_DONE);
00280
00281
00282 checkErr(sqlite3_reset(select_spatial_stmt_), "Couldn't reset SELECT spatial statement");
00283 checkErr(sqlite3_clear_bindings(select_spatial_stmt_), "Couldn't clear bindings on SELECT spatial statment");
00284 }
00285
00286 void PlaceDatabase::getFrame(int64_t id, frame_common::Frame& frame) const
00287 {
00288 checkErr(sqlite3_bind_int64(select_frame_stmt_, 1, id), "Couldn't bind row id");
00289 checkErr(sqlite3_step(select_frame_stmt_), "SELECT frame didn't return data", SQLITE_ROW);
00290
00291
00292 frame_common::CamParams cam;
00293 cam.fx = sqlite3_column_double(select_frame_stmt_, 0);
00294 cam.fy = sqlite3_column_double(select_frame_stmt_, 1);
00295 cam.cx = sqlite3_column_double(select_frame_stmt_, 2);
00296 cam.cy = sqlite3_column_double(select_frame_stmt_, 3);
00297 cam.tx = sqlite3_column_double(select_frame_stmt_, 4);
00298 frame.setCamParams(cam);
00299
00300
00301 int num_keypoints = sqlite3_column_int(select_frame_stmt_, 7);
00302 extractVector(select_frame_stmt_, 5, frame.disps, num_keypoints);
00303 extractVector(select_frame_stmt_, 6, frame.goodPts, num_keypoints);
00304
00305
00306 extractVector(select_frame_stmt_, 8, frame.kpts, num_keypoints);
00307 int descriptor_length = sqlite3_column_int(select_frame_stmt_, 9);
00308 assert(descriptor_length > 0);
00309 const void* desc_data = sqlite3_column_blob(select_frame_stmt_, 10);
00310 int desc_bytes = sqlite3_column_bytes(select_frame_stmt_, 10);
00311 int step = desc_bytes / num_keypoints;
00312 assert(step >= descriptor_length * (int)sizeof(float));
00313 const cv::Mat tmp(num_keypoints, descriptor_length, cv::DataType<float>::type,
00314 const_cast<void*>(desc_data), step);
00315 tmp.copyTo(frame.dtors);
00316
00317
00318 frame.pts.resize(num_keypoints);
00319 for (int i = 0; i < num_keypoints; ++i) {
00320 if (frame.goodPts[i]) {
00321 Eigen::Vector3d pt(frame.kpts[i].pt.x, frame.kpts[i].pt.y, frame.disps[i]);
00322 frame.pts[i].head<3>() = frame.pix2cam(pt);
00323 frame.pts[i](3) = 1.0;
00324 }
00325 }
00326
00327 checkErr(sqlite3_step(select_frame_stmt_), "SELECT frame returned more than one row", SQLITE_DONE);
00328 checkErr(sqlite3_reset(select_frame_stmt_), "Couldn't reset SELECT frame statement");
00329 }
00330
00331 void PlaceDatabase::getTransforms(int64_t id, tf::Pose& pose_in_map, tf::Transform& optical_transform) const
00332 {
00333 checkErr(sqlite3_bind_int64(select_transforms_stmt_, 1, id), "Couldn't bind row id");
00334 checkErr(sqlite3_step(select_transforms_stmt_), "SELECT transforms didn't return data", SQLITE_ROW);
00335
00336 extractTransform(pose_in_map, 0);
00337 extractTransform(optical_transform, 7);
00338
00339 checkErr(sqlite3_step(select_transforms_stmt_), "SELECT transforms returned more than one row", SQLITE_DONE);
00340 checkErr(sqlite3_reset(select_transforms_stmt_), "Couldn't reset SELECT transforms statement");
00341 }
00342
00343 void PlaceDatabase::getImages(int64_t id, cv::Mat& left, cv::Mat& right)
00344 {
00345 checkErr(sqlite3_bind_int64(select_images_stmt_, 1, id), "Couldn't bind row id");
00346 checkErr(sqlite3_step(select_images_stmt_), "SELECT images didn't return data", SQLITE_ROW);
00347
00348 extractImage(left, 0);
00349 extractImage(right, 1);
00350
00351 checkErr(sqlite3_step(select_images_stmt_), "SELECT images returned more than one row", SQLITE_DONE);
00352 checkErr(sqlite3_reset(select_images_stmt_), "Couldn't reset SELECT images statement");
00353 }
00354
00355 void PlaceDatabase::checkErr(int returned_code, const char* msg, int expected_code) const
00356 {
00357 if (returned_code != expected_code) {
00358 char full_msg[512];
00359 snprintf(full_msg, sizeof(full_msg), "%s: %s\n", msg, sqlite3_errmsg(persistent_db_));
00360 throw std::runtime_error(full_msg);
00361 }
00362 }
00363
00364 void PlaceDatabase::extractTransform(btTransform& xfm, int start_index) const
00365 {
00366 xfm.getOrigin().setValue(sqlite3_column_double(select_transforms_stmt_, start_index),
00367 sqlite3_column_double(select_transforms_stmt_, start_index + 1),
00368 sqlite3_column_double(select_transforms_stmt_, start_index + 2));
00369
00370 btQuaternion q(sqlite3_column_double(select_transforms_stmt_, start_index + 3),
00371 sqlite3_column_double(select_transforms_stmt_, start_index + 4),
00372 sqlite3_column_double(select_transforms_stmt_, start_index + 5),
00373 sqlite3_column_double(select_transforms_stmt_, start_index + 6));
00374 xfm.setRotation(q);
00375 }
00376
00377 void PlaceDatabase::bindTransform(const btTransform& xfm, int param_index)
00378 {
00379
00380 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 0, xfm.getOrigin().x()), "Bind error");
00381 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 1, xfm.getOrigin().y()), "Bind error");
00382 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 2, xfm.getOrigin().z()), "Bind error");
00383
00384
00385 btQuaternion q = xfm.getRotation();
00386 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 3, q.x()), "Bind error");
00387 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 4, q.y()), "Bind error");
00388 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 5, q.z()), "Bind error");
00389 checkErr(sqlite3_bind_double(insert_stmt_, param_index + 6, q.w()), "Bind error");
00390 }
00391
00392 void PlaceDatabase::bindCameraParams(const frame_common::CamParams& cam)
00393 {
00394 int idx = camera_param_index_;
00395 checkErr(sqlite3_bind_double(insert_stmt_, idx + 0, cam.fx), "Bind error");
00396 checkErr(sqlite3_bind_double(insert_stmt_, idx + 1, cam.fy), "Bind error");
00397 checkErr(sqlite3_bind_double(insert_stmt_, idx + 2, cam.cx), "Bind error");
00398 checkErr(sqlite3_bind_double(insert_stmt_, idx + 3, cam.cy), "Bind error");
00399 checkErr(sqlite3_bind_double(insert_stmt_, idx + 4, cam.tx), "Bind error");
00400 }
00401
00402 void PlaceDatabase::extractImage(cv::Mat& image, int col) const
00403 {
00404 std::vector<uchar> buf;
00405 extractVector(select_images_stmt_, col, buf);
00406 if (buf.size() == 0)
00407 image = cv::Mat();
00408 else {
00409 cv::Mat mat(1, buf.size(), CV_8UC1, &buf[0]);
00410 image = cv::imdecode(mat, CV_LOAD_IMAGE_ANYCOLOR);
00411 }
00412 }
00413
00414 void PlaceDatabase::bindImage(int col, const cv::Mat& image)
00415 {
00416 if (image.empty()) return;
00417
00418 std::vector<uchar> buf;
00419 std::vector<int> params(2);
00420 params[0] = CV_IMWRITE_JPEG_QUALITY;
00421 params[1] = 80;
00422 cv::imencode(".jpeg", image, buf, params);
00423 bindVector(insert_stmt_, col, buf);
00424 }
00425
00426 }