00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "visual_database.h"
00021 #include <algorithm>
00022 #include <iostream>
00023
00024 using namespace std;
00025
00026 visual_object::visual_object(visual_database *vdb, sqlite3_int64 id, const char *comment, int flags)
00027 : sorted(false), obj_id(id), vdb(vdb), comment(comment), flags(flags)
00028 {
00029 M=0;
00030 }
00031
00032 visual_object::~visual_object() {
00033 if (M) cvReleaseMat(&M);
00034 }
00035
00036 void visual_object::add(db_keypoint &p)
00037 {
00038 points.insert(p);
00039
00040
00041
00042
00043 id_cluster::add(p.cid);
00044 }
00045
00046 void visual_object::prepare()
00047 {
00048
00049
00050
00051
00052
00053
00054 }
00055
00056 void visual_object::find(unsigned id, db_keypoint_vector::iterator &start, db_keypoint_vector::iterator &end)
00057 {
00058 prepare();
00059 db_keypoint k(id,0);
00060
00061 start = points.lower_bound(k);
00062 if (start == points.end()) {
00063 end = points.end();
00064 return;
00065 }
00066 end = points.upper_bound(k);
00067
00068 }
00069
00070
00071 visual_object *query_frame(id_cluster_collection &db, pyr_frame *frame, float *score)
00072 {
00073 id_cluster q;
00074
00075 for (tracks::keypoint_frame_iterator it=frame->points.begin(); !it.end(); ++it)
00076 {
00077 pyr_keypoint * p = (pyr_keypoint *) it.elem();
00078 if (p->cid) q.add(p->cid);
00079
00080 }
00081
00082 visual_object *r = (visual_object *) db.get_best_cluster(&q, score);
00083 return r;
00084 }
00085
00086
00087 struct zint {
00088 int v;
00089 zint() : v(0) {}
00090 };
00091
00092 void update_query_with_frame(incremental_query &query, kpt_tracker *tracker)
00093 {
00094
00095
00096 tframe *frame = tracker->frames;
00097 assert(frame!=0);
00098 #if 0
00099 map<unsigned, zint> updates;
00100 if (frame==0) return;
00101
00102 tframe *lf = frame->frames.prev;
00103
00104 for (ttrack *t=tracker->trk.all_tracks; t!=0; t = t->track_node.next)
00105 {
00106 assert(t->keypoints!=0);
00107 pyr_keypoint *k = (pyr_keypoint *)t->keypoints;
00108 pyr_keypoint *prev_k=0;
00109 if (k->matches.prev) prev_k = (pyr_keypoint *) k->matches.prev;
00110 if ((k->frame != frame && k->cid))
00111 {
00112 updates[k->cid].v--;
00113 }
00114 else if (k->frame==frame && prev_k && prev_k->cid != k->cid)
00115 {
00116 if (prev_k->cid)
00117 updates[prev_k->cid].v--;
00118 if (k->cid)
00119 updates[k->cid].v++;
00120 }
00121 else if (k->cid && k->frame==frame
00122 && prev_k==0)
00123 {
00124 updates[k->cid].v++;
00125 }
00126 }
00127 for (map<unsigned,zint>::iterator it(updates.begin()); it!=updates.end(); ++it)
00128 query.modify(it->first, it->second.v);
00129 #else
00130 id_cluster q;
00131
00132 for (tracks::keypoint_frame_iterator it=frame->points.begin(); !it.end(); ++it)
00133 {
00134 pyr_keypoint * p = (pyr_keypoint *) it.elem();
00135
00136 if (tracker->id_clusters==0) {
00137 if (p->id) q.add(p->id);
00138 } else {
00139 pyr_track *track = (pyr_track *) p->track;
00140 if (track ==0 || p->cid==0) continue;
00141
00142 for(incremental_query::iterator it(track->id_histo.begin()); it!=track->id_histo.end(); ++it)
00143 q.add(it->c->id);
00144 }
00145
00146 }
00147
00148 query.set(&q);
00149 #endif
00150
00151 }
00152
00153 void init_query_with_frame(incremental_query &query, pyr_frame *frame)
00154 {
00155 id_cluster q;
00156 kpt_tracker &tracker(*frame->tracker);
00157
00158 for (tracks::keypoint_frame_iterator it=frame->points.begin(); !it.end(); ++it)
00159 {
00160 pyr_keypoint * p = (pyr_keypoint *) it.elem();
00161 if (tracker.id_clusters) {
00162 if (p->cid) q.add(p->cid);
00163 } else {
00164 if (p->id) q.add(p->id);
00165 }
00166
00167 }
00168
00169 query.version = query.database->get_version();
00170
00171 query.clear();
00172 for (id_cluster::uumap::iterator it(q.histo.begin()); it!=q.histo.end(); ++it)
00173 query.modify(it->first, it->second);
00174 }
00175
00176 visual_database::visual_database(id_cluster_collection::query_flags flags) : id_cluster_collection(flags), db(0)
00177 {
00178 }
00179
00180 visual_database::~visual_database()
00181 {
00182 for (stmt_cache_map::iterator it(stmt_cache.begin()); it!=stmt_cache.end(); ++it)
00183 sqlite3_finalize(it->second);
00184
00185 for (image_cache_map::iterator it(image_cache.begin()); it!=image_cache.end(); ++it)
00186 cvReleaseImage(&it->second);
00187
00188 if (db) sqlite3_close(db);
00189 }
00190
00191 bool visual_database::open(const char *fn)
00192 {
00193 sqlite3 *sql3;
00194 int rc = sqlite3_open(fn, &sql3);
00195 if (rc) {
00196 cerr << "Can't open database: " << sqlite3_errmsg(sql3) << endl;
00197 sqlite3_close(sql3);
00198 return false;
00199 }
00200 return connect_to_db(sql3);
00201 }
00202
00203 bool visual_database::connect_to_db(sqlite3 *sql3db)
00204 {
00205 if (!sql3db) return false;
00206
00207 db = sql3db;
00208
00209
00210 char *errmsg;
00211 int rc = sqlite3_exec(db,
00212 "create table if not exists images ("
00213 "img_id integer primary key autoincrement,"
00214 "width integer,"
00215 "height integer,"
00216 "step integer,"
00217 "channels integer,"
00218 "data blob"
00219 ");\n"
00220 "create table if not exists Objects ("
00221 "obj_id integer primary key autoincrement,"
00222 "timestamp char(19) default CURRENT_TIMESTAMP,"
00223 "comment text,"
00224 "flags integer"
00225 ");\n"
00226 "create table if not exists Keypoints ( "
00227 "kpt_id integer primary key autoincrement,"
00228 "obj_id integer,"
00229 "cid integer,"
00230 "img_id integer,"
00231 "u real,"
00232 "v real,"
00233 "scale real,"
00234 "orient real,"
00235 "patch blob"
00236 ");\n"
00237 "CREATE INDEX IF NOT EXISTS keypoints_obj_idx on Keypoints (obj_id);",
00238 0, 0, &errmsg);
00239 if (rc != SQLITE_OK) {
00240 cerr << "Error while creating tables: " << errmsg << endl;
00241 sqlite3_free(errmsg);
00242 sqlite3_close(db);
00243 db=0;
00244 return false;
00245 }
00246
00247
00248
00249 const char *query="select obj_id,comment,flags from Objects";
00250 sqlite3_stmt *stmt=0;
00251 const char *tail=0;
00252 rc = sqlite3_prepare_v2(db, query, -1, &stmt, &tail);
00253
00254 if (rc != SQLITE_OK) {
00255 cerr << "Error: " << sqlite3_errmsg(db) << endl;
00256 cerr << "While compiling: " << query << endl;
00257 return false;
00258 }
00259
00260 while (sqlite3_step(stmt) == SQLITE_ROW) {
00261 sqlite3_int64 oid = sqlite3_column_int64(stmt, 0);
00262 visual_object *vo = new visual_object(this, oid, (const char *)sqlite3_column_text(stmt,1), sqlite3_column_int(stmt,2));
00263
00264 sqlite3_stmt *kpt_stmt = get_cached_stmt("select cid, img_id, u, v, scale, orient, patch from Keypoints where obj_id=?");
00265 assert(kpt_stmt!=0);
00266 sqlite3_bind_int64(kpt_stmt, 1, oid);
00267
00268 while (sqlite3_step(kpt_stmt) == SQLITE_ROW) {
00269 db_keypoint kpt( sqlite3_column_int(kpt_stmt, 0),
00270 sqlite3_column_int64(kpt_stmt, 1));
00271 kpt.u = sqlite3_column_double(kpt_stmt, 2);
00272 kpt.v = sqlite3_column_double(kpt_stmt, 3);
00273 kpt.scale = sqlite3_column_double(kpt_stmt, 4);
00274 kpt.descriptor.orientation = sqlite3_column_double(kpt_stmt, 5);
00275
00276 const unsigned length = sizeof(kpt.descriptor._rotated);
00277 assert((unsigned)sqlite3_column_bytes(kpt_stmt, 6) == length);
00278 memcpy(kpt.descriptor._rotated, sqlite3_column_blob(kpt_stmt, 6), length);
00279 vo->representative_image = kpt.image;
00280 vo->add(kpt);
00281 }
00282 vo->prepare();
00283 add_to_index(vo);
00284
00285 kpt_stmt = get_cached_stmt("select rowid, x, y, type, descr from annotations where obj=?", false);
00286 if (kpt_stmt!=0) {
00287 sqlite3_bind_int64(kpt_stmt, 1, oid);
00288 while (sqlite3_step(kpt_stmt) == SQLITE_ROW) {
00289 vo->annotations.push_back(visual_object::annotation(
00290 sqlite3_column_int64(kpt_stmt, 0),
00291 sqlite3_column_double(kpt_stmt, 1),
00292 sqlite3_column_double(kpt_stmt, 2),
00293 (const char *)sqlite3_column_text(kpt_stmt, 4),
00294 sqlite3_column_int(kpt_stmt, 3)));
00295 }
00296 }
00297 }
00298
00299 sqlite3_finalize(stmt);
00300
00301 version++;
00302 return true;
00303 }
00304
00305 img_id visual_database::add_image(IplImage *_im)
00306 {
00307 assert(_im!=0);
00308 IplImage *im = cvCloneImage(_im);
00309
00310 const char *query = "insert into images (width, height, step, channels, data) values (?,?,?,?,?)";
00311 sqlite3_stmt *stmt=get_cached_stmt(query);
00312 assert(stmt!=0);
00313
00314 int rc = sqlite3_bind_int(stmt, 1, im->width);
00315 assert(rc == SQLITE_OK);
00316 rc = sqlite3_bind_int(stmt, 2, im->height);
00317 assert(rc == SQLITE_OK);
00318 rc = sqlite3_bind_int(stmt, 3, im->widthStep);
00319 assert(rc == SQLITE_OK);
00320 rc = sqlite3_bind_int(stmt, 4, im->nChannels);
00321 assert(rc == SQLITE_OK);
00322 rc = sqlite3_bind_blob(stmt, 5, im->imageData, im->height*im->widthStep, SQLITE_STATIC);
00323 assert(rc == SQLITE_OK);
00324
00325 if(sqlite3_step(stmt)!=SQLITE_DONE) {
00326 printf("Error message: %s\n", sqlite3_errmsg(db));
00327 }
00328 img_id id = sqlite3_last_insert_rowid(db);
00329 image_cache[id] = im;
00330 return id;
00331 }
00332
00333 IplImage *visual_database::get_image(img_id img)
00334 {
00335 image_cache_map::iterator it = image_cache.find(img);
00336 if (it != image_cache.end())
00337 return it->second;
00338
00339 const char *query = "select width,height,step,channels,data from images where img_id = ?";
00340 sqlite3_stmt *stmt= get_cached_stmt(query);
00341 assert(stmt!=0);
00342
00343 IplImage *result=0;
00344
00345 int rc = sqlite3_bind_int64(stmt, 1, img);
00346 assert(rc == SQLITE_OK);
00347
00348 rc = sqlite3_step(stmt);
00349 if (rc == SQLITE_ROW) {
00350 CvMat m;
00351 int width = sqlite3_column_int(stmt, 0);
00352 int height = sqlite3_column_int(stmt, 1);
00353 int step = sqlite3_column_int(stmt, 2);
00354 int channels = sqlite3_column_int(stmt, 3);
00355 void *data = const_cast<void *>(sqlite3_column_blob(stmt, 4));
00356
00357 assert(sqlite3_column_bytes(stmt, 4) == step*height);
00358
00359 cvInitMatHeader(&m, height, width,
00360 CV_MAKETYPE(CV_8U, channels),
00361 data, step);
00362
00363 IplImage header;
00364 result = cvCloneImage(cvGetImage(&m,&header));
00365 image_cache[img] = result;
00366 } else if (rc == SQLITE_DONE) {
00367
00368 cerr << "Image " << img << " not found !\n";
00369 } else {
00370 cerr << "Error while searching for image " << img << ": " << sqlite3_errmsg(db) << endl;
00371 }
00372 return result;
00373 }
00374
00375 visual_object *visual_database::create_object(const char *comment, int flags)
00376 {
00377 const char *query = "insert into Objects (comment, flags) values (?,?)";
00378 sqlite3_stmt *stmt= get_cached_stmt(query);
00379 assert(stmt != 0);
00380
00381 sqlite3_bind_text(stmt, 1, (comment? comment:""), -1, SQLITE_TRANSIENT);
00382 sqlite3_bind_int(stmt, 2, flags);
00383 if (sqlite3_step(stmt) != SQLITE_DONE) {
00384 printf("Error message: %s\n", sqlite3_errmsg(db));
00385 return 0;
00386 }
00387 visual_object *obj = new visual_object(this, sqlite3_last_insert_rowid(db), comment, flags);
00388 version++;
00389 return obj;
00390 }
00391
00392 bool visual_database::remove_object(visual_object *obj)
00393 {
00394
00395
00396 exec_sql("begin");
00397
00398 sqlite3_stmt *stmt= get_cached_stmt("delete from objects where obj_id=?");
00399 assert(stmt != 0);
00400 sqlite3_bind_int64(stmt, 1, obj->obj_id);
00401
00402 if (sqlite3_step(stmt) != SQLITE_DONE) {
00403 printf("Error message: %s\n", sqlite3_errmsg(db));
00404 return false;
00405 }
00406
00407 stmt= get_cached_stmt("delete from keypoints where obj_id=?");
00408 assert(stmt != 0);
00409 sqlite3_bind_int64(stmt, 1, obj->obj_id);
00410
00411 if (sqlite3_step(stmt) != SQLITE_DONE) {
00412 printf("Error message: %s\n", sqlite3_errmsg(db));
00413 return false;
00414 }
00415
00416 stmt= get_cached_stmt("delete from images where img_id=?");
00417 assert(stmt != 0);
00418 sqlite3_bind_int64(stmt, 1, obj->representative_image);
00419
00420 if (sqlite3_step(stmt) != SQLITE_DONE) {
00421 printf("Error message: %s\n", sqlite3_errmsg(db));
00422 return false;
00423 }
00424
00425 exec_sql("commit");
00426
00427
00428 remove_cluster(obj);
00429
00430
00431 obj->obj_id = -1;
00432 obj->representative_image=-1;
00433 obj->clear();
00434
00435 return true;
00436 }
00437
00438
00439 sqlite3_stmt *visual_database::get_cached_stmt(const char *query, bool verbose)
00440 {
00441 assert(db!=0);
00442 stmt_cache_map::iterator it(stmt_cache.find(query));
00443 if (it != stmt_cache.end()) {
00444 sqlite3_reset(it->second);
00445 sqlite3_clear_bindings(it->second);
00446 return it->second;
00447 }
00448
00449 sqlite3_stmt *stmt=0;
00450 const char *tail;
00451
00452 int rc = sqlite3_prepare_v2(db, query, -1, &stmt, &tail);
00453
00454 if (rc != SQLITE_OK) {
00455 if (verbose) {
00456 cerr << "Error: " << sqlite3_errmsg(db) << endl;
00457 cerr << "While compiling: " << query << endl;
00458 }
00459 return 0;
00460 }
00461 stmt_cache[query] = stmt;
00462
00463 return stmt;
00464 }
00465
00466 bool visual_database::exec_sql(const char *query)
00467 {
00468 sqlite3_stmt *stmt = get_cached_stmt(query);
00469 if (stmt==0) return false;
00470
00471 if (sqlite3_step(stmt) != SQLITE_DONE) {
00472 printf("Error message: %s\n", sqlite3_errmsg(db));
00473 return false;
00474 }
00475 return true;
00476 }
00477
00478 db_keypoint *visual_object::add_keypoint(pyr_keypoint *p, img_id img)
00479 {
00480 if (!p) return 0;
00481 assert(this!=0);
00482
00483 db_keypoint db_p(*p, img);
00484
00485 if (p->frame && ((pyr_frame*)p->frame)->tracker->id_clusters == 0)
00486 db_p.cid = p->id;
00487
00488 if (db_p.cid ==0) return 0;
00489
00490
00491 vdb->update_cluster(this, db_p.cid, 1);
00492 db_keypoint *ret = const_cast<db_keypoint *>(&(*points.insert(db_p)));
00493
00494 sqlite3_stmt *stmt= vdb->get_cached_stmt(
00495 "insert into Keypoints (obj_id, cid, img_id, u, v, scale, orient, patch) values (?,?,?,?,?,?,?,?)");
00496 assert(stmt != 0);
00497 int rc = sqlite3_bind_int64(stmt, 1, obj_id);
00498 assert(rc==SQLITE_OK);
00499 rc = sqlite3_bind_int(stmt, 2, db_p.cid);
00500 assert(rc==SQLITE_OK);
00501 rc = sqlite3_bind_int64(stmt, 3, img);
00502 assert(rc==SQLITE_OK);
00503 rc = sqlite3_bind_double(stmt, 4, db_p.u);
00504 assert(rc==SQLITE_OK);
00505 rc = sqlite3_bind_double(stmt, 5, db_p.v);
00506 assert(rc==SQLITE_OK);
00507 rc = sqlite3_bind_double(stmt, 6, db_p.scale);
00508 assert(rc==SQLITE_OK);
00509 rc = sqlite3_bind_double(stmt, 7, db_p.descriptor.orientation);
00510 assert(rc==SQLITE_OK);
00511 sqlite3_bind_blob(stmt, 8, p->descriptor._rotated, sizeof(p->descriptor._rotated), SQLITE_TRANSIENT);
00512
00513 if (sqlite3_step(stmt) != SQLITE_DONE) {
00514 printf("Error message: %s\n", sqlite3_errmsg(vdb->db));
00515 }
00516 return ret;
00517 }
00518
00519 unsigned visual_object::add_frame(pyr_frame *frame)
00520 {
00521 unsigned r=0;
00522 vdb->exec_sql("begin");
00523 img_id img = vdb->add_image(frame->pyr->images[0]);
00524 representative_image = img;
00525
00526 for (tracks::keypoint_frame_iterator it=frame->points.begin(); !it.end(); ++it)
00527 {
00528 pyr_keypoint * p = (pyr_keypoint *) it.elem();
00529 add_keypoint(p,img);
00530 }
00531 vdb->exec_sql("commit");
00532 vdb->version++;
00533 return r;
00534 }
00535
00536 float visual_object::get_correspondences(pyr_frame *frame, correspondence_vector &corresp)
00537 {
00538 float r = get_correspondences_std(frame, corresp);
00539 if (flags & (VERIFY_HOMOGRAPHY | VERIFY_FMAT))
00540 r = verify(frame, corresp);
00541 return r;
00542 }
00543
00544 float visual_object::get_correspondences_std(pyr_frame *frame, correspondence_vector &corresp)
00545 {
00546 corresp.clear();
00547 corresp.reserve(frame->points.size()*4);
00548
00549 double score=0;
00550 double max_score=0;
00551
00552 int npts=0;
00553
00554
00555
00556
00557 for (uumap::iterator i(histo.begin()); i!=histo.end(); ++i) {
00558 max_score += vdb->idf(i->first);
00559 }
00560
00561 std::set<unsigned> matched_cids;
00562
00563 for (tracks::keypoint_frame_iterator it(frame->points.begin()); !it.end(); ++it) {
00564 pyr_keypoint *k = (pyr_keypoint *) it.elem();
00565
00566 if (((pyr_frame *)k->frame)->tracker->id_clusters==0) {
00567
00568 db_keypoint_vector::iterator begin, end;
00569 find(k->id,begin,end);
00570 for (db_keypoint_vector::iterator i(begin); i!=end; i++) {
00571 corresp.push_back(correspondence(const_cast<db_keypoint *>(&(*i)), k, 1));
00572 if (matched_cids.insert(k->id).second) {
00573 id_cluster_collection::id2cluster_map::iterator id_it = vdb->id2cluster.find(k->id);
00574 if (id_it != vdb->id2cluster.end())
00575 score += vdb->idf(id_it);
00576 }
00577 }
00578 } else {
00579
00580
00581 pyr_track *track = (pyr_track *) k->track;
00582 if (track ==0 || k->cid==0) continue;
00583
00584 npts++;
00585
00586 bool added=false;
00587 track->id_histo.sort_results_min_ratio(.7);
00588 for(incremental_query::iterator it(track->id_histo.begin()); it!=track->id_histo.end(); ++it)
00589 {
00590 int cid = it->c->id;
00591 db_keypoint_vector::iterator begin, end;
00592 find(cid,begin,end);
00593
00594 if (begin == end) continue;
00595
00596 float idf=1;
00597 id_cluster_collection::id2cluster_map::iterator id_it = vdb->id2cluster.find(cid);
00598 if (id_it != vdb->id2cluster.end())
00599 idf = vdb->idf(id_it);
00600
00601 for (db_keypoint_vector::iterator i(begin); i!=end; i++)
00602 {
00603 corresp.push_back(correspondence(const_cast<db_keypoint *>(&(*i)), k, 1));
00604 if (!added) {
00605 added=true;
00606 if (matched_cids.insert(cid).second)
00607 score += idf;
00608 }
00609 }
00610 }
00611 }
00612 }
00613
00614
00615 return score/max_score;
00616 }
00617
00618 float visual_object::verify(pyr_frame *, correspondence_vector &corresp)
00619 {
00620
00621 if ((flags & (VERIFY_HOMOGRAPHY | VERIFY_FMAT)) == 0) return 0;
00622 if (corresp.size() < 16) return 0;
00623
00624 CvMat *frame_pts = cvCreateMat(corresp.size(), 3, CV_32FC1);
00625 CvMat *obj_pts = cvCreateMat(corresp.size(), 3, CV_32FC1);
00626 CvMat *mask = cvCreateMat(1, corresp.size(), CV_8UC1);
00627
00628
00629 float *f = frame_pts->data.fl;
00630 float *o = obj_pts->data.fl;
00631 for (correspondence_vector::iterator it(corresp.begin()); it!=corresp.end(); ++it) {
00632 *f++ = it->frame_kpt->u;
00633 *f++ = it->frame_kpt->v;
00634 *f++ = 1;
00635 *o++ = it->obj_kpt->u;
00636 *o++ = it->obj_kpt->v;
00637 *o++ = 1;
00638 }
00639
00640 if (M==0) M = cvCreateMat(3,3,CV_64FC1);
00641
00642 int r = 0;
00643 if (flags & VERIFY_HOMOGRAPHY) {
00644 r = cvFindHomography(obj_pts, frame_pts, M, CV_RANSAC, 5, mask);
00645 } else {
00646 r = cvFindFundamentalMat(obj_pts, frame_pts, M, CV_FM_RANSAC, 5, .99, mask);
00647 }
00648 if (r!=1) {
00649 cvReleaseMat(&mask);
00650 cvReleaseMat(&frame_pts);
00651 cvReleaseMat(&obj_pts);
00652 corresp.clear();
00653 return 0;
00654 }
00655
00656 unsigned char *c = mask->data.ptr;
00657 int cnt=0;
00658 for (unsigned i=0; i<corresp.size(); i++)
00659 if (c[i]) cnt++;
00660 correspondence_vector filtered;
00661 filtered.reserve(cnt);
00662 correspondence_vector::iterator it = corresp.begin();
00663
00664 for (unsigned i=0; i<corresp.size(); ++i, ++it)
00665 if (c[i]) filtered.push_back(*it);
00666
00667 cout << "Filtered: " << filtered.size() << ", initial: " << corresp.size() << endl;
00668 filtered.swap(corresp);
00669
00670 cvReleaseMat(&mask);
00671 cvReleaseMat(&frame_pts);
00672 cvReleaseMat(&obj_pts);
00673 return cnt / (float)filtered.size();
00674 }
00675
00676
00677 void visual_object::add_annotation(float x, float y, int type, const std::string &descr)
00678 {
00679 sqlite3_stmt *stmt=vdb->get_cached_stmt("create table if not exists annotations (obj integer, x real, y real, type integer, descr text)");
00680 if(sqlite3_step(stmt)!=SQLITE_DONE) {
00681 printf("Error message: %s\n", sqlite3_errmsg(vdb->db));
00682 return;
00683 }
00684
00685 assert(stmt!=0);
00686 const char *query = "insert into annotations (obj, x, y, type, descr) values (?,?,?,?,?)";
00687 stmt=vdb->get_cached_stmt(query);
00688 assert(stmt!=0);
00689
00690 sqlite3_bind_int64(stmt, 1, obj_id);
00691 sqlite3_bind_double(stmt, 2, x);
00692 sqlite3_bind_double(stmt, 3, y);
00693 sqlite3_bind_int(stmt, 4, type);
00694 sqlite3_bind_text(stmt, 5, descr.c_str(), -1, SQLITE_TRANSIENT);
00695
00696 if(sqlite3_step(stmt)!=SQLITE_DONE) {
00697 printf("Error message: %s\n", sqlite3_errmsg(vdb->db));
00698 }
00699
00700 annotations.push_back(annotation(sqlite3_last_insert_rowid(vdb->db), x, y, descr, type));
00701 }
00702