00001 #ifndef Impala_Core_Table_AnnotationTable_h
00002 #define Impala_Core_Table_AnnotationTable_h
00003
00004 #include "Util/QuickSort.h"
00005 #include "Util/SimpleMap.h"
00006 #include "Core/Table/SelectQuids.h"
00007 #include "Core/Table/Read.h"
00008 #include "Core/Table/Criterion.h"
00009 #include "Core/Table/CollectQuidObjects.h"
00010 #include "Core/Table/Select.h"
00011 #include "Core/Column/Find.h"
00012 #include "Core/Column/FindInAscending.h"
00013 #include "Core/VideoSet/Segmentation.h"
00014 #include "Util/QuasiRandomSequenceIterator.h"
00015
00016 namespace Impala
00017 {
00018 namespace Core
00019 {
00020 namespace Table
00021 {
00022
00023
00024 typedef TableTem<Column::ColumnTem<Quid>,
00025 Column::ColumnTem<Real64> >
00026 AnnotationTableBaseType;
00027
00028
00033 class AnnotationTable : public AnnotationTableBaseType
00034 {
00035 public:
00036
00037 typedef Column::ColumnTem<Real64> ColumnReal64;
00038 typedef Column::ColumnTem<Quid> ColumnQuid;
00039
00040 AnnotationTable() :
00041 AnnotationTableBaseType(ColumnQuid(0), ColumnReal64(0))
00042 {
00043 mLabel = "";
00044 mIsAscending = false;
00045 SetInfo("AnnotationTable");
00046 SetColName(1, "annotee");
00047 SetColName(2, "qualifier");
00048 }
00049
00050 AnnotationTable(String label, int tableSize) :
00051 AnnotationTableBaseType(ColumnQuid(tableSize), ColumnReal64(tableSize))
00052 {
00053 mLabel = label;
00054 mIsAscending = false;
00055 SetInfo("AnnotationTable : " + label);
00056 SetColName(1, "annotee");
00057 SetColName(2, "qualifier " + label);
00058 }
00059
00060 #ifndef REPOSITORY_USED // Here comes the deprecated stuff
00061 static AnnotationTable*
00062 MakeFromFile(String label, String fileName, Util::Database* db)
00063 {
00064 AnnotationTable* res = new AnnotationTable(label, 0);
00065 Read(res, fileName, db);
00066
00067 return res;
00068 }
00069 #endif // REPOSITORY_USED
00070
00071 String
00072 GetLabel() const
00073 {
00074 return mLabel;
00075 }
00076
00077 void
00078 SetLabel(String label)
00079 {
00080 mLabel = label;
00081 }
00082
00083 int
00084 GetQuidClass() const
00085 {
00086 if (Size() < 1)
00087 return QUID_CLASS_UNKNOWN;
00088 return QuidClass(Get1(0));
00089 }
00090
00091 bool
00092 ContainsFrames() const
00093 {
00094 return GetQuidClass() == QUID_CLASS_FRAME;
00095 }
00096
00097 bool
00098 ContainsShots() const
00099 {
00100 return GetQuidClass() == QUID_CLASS_SHOT;
00101 }
00102
00103 int
00104 GetNrPositive() const
00105 {
00106 int res = 0;
00107 for (int i=0 ; i<Size() ; i++)
00108 if (IsPositive(i))
00109 res++;
00110 return res;
00111 }
00112
00113 int
00114 GetNrNegative() const
00115 {
00116 int res = 0;
00117 for (int i=0 ; i<Size() ; i++)
00118 if (IsNegative(i))
00119 res++;
00120 return res;
00121 }
00122
00123 QuidTable*
00124 GetPositive() const
00125 {
00126 CriterionElement2Equals<AnnotationTableBaseType> c(1.);
00127 return SelectQuids(this, c);
00128 }
00129
00130 QuidTable*
00131 GetNegative() const
00132 {
00133 CriterionElement2Equals<AnnotationTableBaseType> c(-1.);
00134 return SelectQuids(this, c);
00135 }
00136
00137 QuidTable*
00138 GetAnnotatedQuids() const
00139 {
00140 CriterionElement2NotEquals<AnnotationTableBaseType> c(0.);
00141 return SelectQuids(this, c);
00142 }
00143
00144 int
00145 GetIndex(Quid annotee) const
00146 {
00147 int index = Size();
00148 if (mQuidMap.Get(annotee, index))
00149 return index;
00150 if (mIsAscending)
00151 return Column::FindInAscending(GetColumn1(), annotee, 0, Size());
00152 return Column::Find(GetColumn1(), annotee, 0, Size());
00153 }
00154
00155 bool
00156 IsAnnotated(Quid annotee) const
00157 {
00158 return (GetIndex(annotee) != Size());
00159 }
00160
00161 Real64
00162 GetQualification(Quid annotee) const
00163 {
00164 int index = GetIndex(annotee);
00165 if (index != Size())
00166 return Get2(index);
00167 return -2.0;
00168 }
00169
00170 bool
00171 IsPositive(int idx) const
00172 {
00173 return Get2(idx) == 1.0;
00174 }
00175
00176 bool
00177 IsPositive(Quid annotee) const
00178 {
00179 int index = GetIndex(annotee);
00180 if (index != Size())
00181 return IsPositive(index);
00182 return false;
00183 }
00184
00185 bool
00186 IsNegative(int idx) const
00187 {
00188 return Get2(idx) == -1.0;
00189 }
00190
00191 bool
00192 IsNegative(Quid annotee) const
00193 {
00194 int index = GetIndex(annotee);
00195 if (index != Size())
00196 return IsNegative(index);
00197 return false;
00198 }
00199
00200 bool
00201 IsSkip(int idx) const
00202 {
00203 return Get2(idx) == 0.0;
00204 }
00205
00206 bool
00207 IsSkip(Quid annotee) const
00208 {
00209 int index = GetIndex(annotee);
00210 if (index != Size())
00211 return IsSkip(index);
00212 return false;
00213 }
00214
00215 void
00216 AddPositive(Quid annotee)
00217 {
00218 Add(annotee, 1.0);
00219 }
00220
00221 void
00222 AddNegative(Quid annotee)
00223 {
00224 Add(annotee, -1.0);
00225 }
00226
00227 void
00228 AddSkip(Quid annotee)
00229 {
00230 Add(annotee, 0.0);
00231 }
00232
00233
00234 void
00235 SelectQuidObjectMaxId(int maxId)
00236 {
00237 if (maxId == -1)
00238 return;
00239
00240 CriterionQuidObjectMaxId<AnnotationTable> crit(maxId);
00241 Select(this, this, crit, true);
00242 }
00243
00244
00245 void
00246 SelectQuidObjectMaxPositive(int number)
00247 {
00248 if (number == -1)
00249 return;
00250
00251 CriterionQuidObjectMaxNumberElement2<AnnotationTable> crit(1.0, number);
00252 Select(this, this, crit, true);
00253 }
00254
00255
00256 void
00257 SelectQuidObjectMaxNegative(int number)
00258 {
00259 if (number == -1)
00260 return;
00261
00262 CriterionQuidObjectMaxNumberElement2<AnnotationTable> crit(-1.0, number);
00263 Select(this, this, crit, true);
00264 }
00265
00266 void
00267 UpdateQuidMap()
00268 {
00269 mIsAscending = true;
00270 for (int i=0 ; i<Size()-1 ; i++)
00271 {
00272 if (Get1(i+1) < Get1(i))
00273 {
00274 mIsAscending = false;
00275 break;
00276 }
00277 }
00278 if (!mIsAscending)
00279 {
00280 for (int i=0 ; i<Size() ; i++)
00281 mQuidMap.Add(Get1(i), i);
00282 }
00283 }
00284
00285 int
00286 Diff(AnnotationTable* arg) const
00287 {
00288 if (Size() != arg->Size())
00289 {
00290 ILOG_ERROR("Diff: Size differs: " << Size() << " vs " <<
00291 arg->Size());
00292 return 1;
00293 }
00294 int nDiff = 0;
00295 for (int i=0 ; i<Size() ; i++)
00296 {
00297 if (Get1(i) != arg->Get1(i))
00298 {
00299 ILOG_DEBUG("Quid " << i << " differs " << Get1(i) <<
00300 " vs " << arg->Get1(i));
00301 nDiff++;
00302 }
00303 else if (::fabs(Get2(i) -arg->Get2(i)) > 0.00001)
00304 {
00305 ILOG_DEBUG("Anno " << i << " differs " << Get2(i) <<
00306 " vs " << arg->Get2(i));
00307 nDiff++;
00308 }
00309 }
00310 if (nDiff > 0)
00311 ILOG_ERROR("Found " << nDiff << " differences");
00312 return nDiff;
00313 }
00314
00315 virtual void
00316 Dump(int from = 0, int to = -1)
00317 {
00318 if (to == -1 || to > Size())
00319 to = Size();
00320 if (to < from)
00321 to = from;
00322 if (to <= from)
00323 return ;
00324
00325 std::cout << "Dumping table from " << from << " to " << to
00326 << " (table size=" << Size() << ", capacity=" << Capacity()
00327 << ")" << std::endl;
00328 for (int i=0 ; i<2 ; i++)
00329 std::cout << i+1 << "=" << GetColName(i+1) << ", ";
00330 std::cout << std::endl;
00331 for (int i=from ; i<to ; i++)
00332 {
00333 std::cout << QuidObj(Get1(i)) << ", " << Get2(i) << std::endl;
00334 }
00335 std::cout << std::endl;
00336 }
00337
00338 virtual void
00339 Dump(Database::RawDataSet* dataSet, int from = 0, int to = -1)
00340 {
00341 if (dataSet == 0)
00342 return Dump(from, to);
00343
00344 if (to == -1 || to > Size())
00345 to = Size();
00346 if (to < from)
00347 to = from;
00348 if (to <= from)
00349 return ;
00350
00351 std::cout << "Dumping table from " << from << " to " << to
00352 << " (table size=" << Size() << ", capacity=" << Capacity()
00353 << ")" << std::endl;
00354 for (int i=0 ; i<2 ; i++)
00355 std::cout << i+1 << "=" << GetColName(i+1) << ", ";
00356 std::cout << std::endl;
00357 for (int i=from ; i<to ; i++)
00358 {
00359 Quid quid = Get1(i);
00360 std::cout << dataSet->QuidToString(quid, true) << ", " << Get2(i)
00361 << std::endl;
00362 }
00363 std::cout << std::endl;
00364 }
00365
00366 void
00367 DumpSummary()
00368 {
00369 int pos=0, neg=0, skip=0;
00370 for (int i=0 ; i<Size() ; ++i)
00371 {
00372 if (IsPositive(i))
00373 ++pos;
00374 else if (IsNegative(i))
00375 ++neg;
00376 else
00377 ++skip;
00378 }
00379 std::cout << GetLabel() << " : " << pos << " positive, " << neg
00380 << " negative, " << skip << " skip, " << Size() << " total"
00381 << std::endl;
00382 }
00383
00384 void
00385 DumpSummaryObject()
00386 {
00387 std::vector<int> objs = CollectQuidObjects(this);
00388 for (int i=0 ; i<objs.size() ; i++)
00389 {
00390 std::cout << " obj=" << objs[i] << " : ";
00391 std::vector<int> oneObj;
00392 oneObj.push_back(objs[i]);
00393 CriterionQuidObjectInSet<AnnotationTable> crit(oneObj);
00394 AnnotationTable* tmp = Select(this, crit);
00395 tmp->DumpSummary();
00396 delete tmp;
00397 }
00398 }
00399
00400
00405 std::vector<QuidTable*>
00406 MakeEpisodeFolds(int foldCount, int repetition)
00407 {
00408 ILOG_DEBUG("entering MakeEpisodeFolds");
00409
00410 int quidclass = GetQuidClass();
00411 if(quidclass != QUID_CLASS_SHOT &&
00412 quidclass != QUID_CLASS_KEYFRAME &&
00413 quidclass != QUID_CLASS_FRAME)
00414 {
00415 ILOG_WARNING_ONCE("annotees of wrong quidclass, cannot do episode " <<
00416 "constrained");
00417 return MakeRandomFolds(foldCount, repetition);
00418 }
00419
00420 if(foldCount <= 1)
00421 {
00422 ILOG_ERROR("we need at least 2 folds");
00423 return std::vector<QuidTable*>(1, GetAnnotatedQuids());
00424 }
00425
00426 QuidTable* positive = GetPositive();
00427 QuidTable* negative = GetNegative();
00428 ILOG_DEBUG_NODE("make episode folds: #annotations = " <<
00429 positive->Size() + negative->Size());
00430
00431
00432 std::vector<int> positiveVideos;
00433 std::vector<int> negativeVideos;
00434 GroupPerVideo(positive, negative, positiveVideos, negativeVideos);
00435 delete positive;
00436 delete negative;
00437
00438 std::vector<QuidTable*> folds;
00439 for(int i=0 ; i<foldCount ; i++)
00440 folds.push_back(new QuidTable(0));
00441
00442
00443 int lastFold=0;
00444 Util::QuasiRandomSequenceIterator pos(positiveVideos.size(),repetition);
00445 for(int i=0 ; i<positiveVideos.size() ; ++i)
00446 {
00447 CriterionQuidObjectEquals<AnnotationTable>
00448 c(positiveVideos[*pos]);
00449 SelectOneColumn(folds[lastFold], this, 1, c, false);
00450 ++pos;
00451 ++lastFold;
00452 if(lastFold >= foldCount)
00453 lastFold = 0;
00454 }
00455
00456
00457 Util::QuasiRandomSequenceIterator neg(negativeVideos.size(),repetition);
00458 for(int i=0 ; i<negativeVideos.size() ; ++i)
00459 {
00460 CriterionQuidObjectEquals<AnnotationTable>
00461 c(negativeVideos[*neg]);
00462 SelectOneColumn(folds[lastFold], this, 1, c, false);
00463 ++neg;
00464 ++lastFold;
00465 if(lastFold >= foldCount)
00466 lastFold = 0;
00467 }
00468
00469 ILOG_DEBUG("leaving MakeFolds");
00470 return folds;
00471 }
00472
00473 std::vector<QuidTable*>
00474 MakeRandomFolds(int foldCount, int repetition)
00475 {
00476 if(foldCount <= 1)
00477 {
00478 ILOG_ERROR("we need at least 2 folds");
00479 return std::vector<QuidTable*>(1, GetAnnotatedQuids());
00480 }
00481
00482 QuidTable* positive = GetPositive();
00483 QuidTable* negative = GetNegative();
00484 ILOG_DEBUG_NODE("make random folds: #annotations = " <<
00485 positive->Size() + negative->Size());
00486
00487 std::vector<QuidTable*> folds;
00488 for(int i=0 ; i<foldCount ; ++i)
00489 folds.push_back(new QuidTable(0));
00490
00491 int lastFold=0;
00492 Util::QuasiRandomSequenceIterator pos(positive->Size(), repetition);
00493 for(int i=0 ; i<positive->Size() ; ++i)
00494 {
00495 folds[lastFold]->Add(positive->Get1(*pos));
00496 ++pos;
00497 ++lastFold;
00498 if(lastFold >= foldCount)
00499 lastFold = 0;
00500 }
00501 for (int i=0 ; i<foldCount ; i++)
00502 {
00503 ILOG_DEBUG("fold "<< i <<" has "<< folds[i]->Size() <<" positives");
00504 if (folds[i]->Size() == 0)
00505 ILOG_ERROR("fold "<< i <<" has NO positives");
00506 }
00507
00508 Util::QuasiRandomSequenceIterator neg(negative->Size(), repetition);
00509 for(int i=0 ; i<negative->Size() ; ++i)
00510 {
00511 folds[lastFold]->Add(negative->Get1(*neg));
00512 ++neg;
00513 ++lastFold;
00514 if(lastFold >= foldCount)
00515 lastFold = 0;
00516 }
00517
00518 delete positive;
00519 delete negative;
00520 return folds;
00521 }
00522
00529 void Sort()
00530 {
00531 Util::QuickSortDescCo
00532 (GetColumn2()->GetData(), GetColumn1()->GetData(), 0, Size()-1);
00533
00534 int to;
00535 for(int i=0 ; i<Size() ; ++i)
00536 {
00537 to = i;
00538 if(Get2(i) != 1)
00539 break;
00540 }
00541 Util::QuickSort(GetColumn1()->GetData(), 0, to-1);
00542
00543 int from;
00544 for(int i=to ; i<Size() ; ++i)
00545 {
00546 from = i;
00547 if(Get2(i) == -1)
00548 break;
00549 }
00550 Util::QuickSort(GetColumn1()->GetData(), from, Size()-1);
00551 }
00552
00553 private:
00554
00555 String mLabel;
00556 bool mIsAscending;
00557 Util::SimpleMap<Quid, int> mQuidMap;
00558
00559
00560
00561
00562 void GroupPerVideo(const QuidTable* positive,
00563 const QuidTable* negative,
00564 std::vector<int>& positiveVideos,
00565 std::vector<int>& negativeVideos)
00566 {
00567 Quid lastQuid=0;
00568
00569 for(int i=0 ; i<positive->Size() ; i++)
00570 {
00571 Quid q = positive->Get1(i);
00572
00573
00574 if(!QuidObjectEqual(lastQuid,q))
00575 {
00576 lastQuid = q;
00577 int videoID = QuidObject(q);
00578 if(find(positiveVideos.begin(), positiveVideos.end(), videoID)
00579 == positiveVideos.end())
00580 {
00581 positiveVideos.push_back(videoID);
00582 }
00583 }
00584 }
00585
00586 lastQuid=0;
00587
00588
00589 for(int i=0 ; i<negative->Size() ; i++)
00590 {
00591 Quid q = negative->Get1(i);
00592 if(!QuidObjectEqual(lastQuid,q))
00593 {
00594 lastQuid = q;
00595 int videoID = QuidObject(q);
00596 if(find(positiveVideos.begin(), positiveVideos.end(), videoID)
00597 == positiveVideos.end())
00598 {
00599 if(find(negativeVideos.begin(), negativeVideos.end(),
00600 videoID) == negativeVideos.end())
00601 {
00602 negativeVideos.push_back(videoID);
00603 }
00604 }
00605 }
00606 }
00607 }
00608
00609
00610
00611 ILOG_VAR_DEC;
00612 };
00613
00614 ILOG_VAR_INIT(AnnotationTable, Impala.Core.Table);
00615
00616 }
00617 }
00618 }
00619
00620 #endif