LocalizationAnalysis.cpp 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. /**
  2. * @file LocalizationAnalysis.cpp
  3. * @brief Some methods for localization analysis
  4. * @author Erik Rodner
  5. * @date 09/01/2008
  6. */
  7. #include <iostream>
  8. #include "LocalizationAnalysis.h"
  9. using namespace OBJREC;
  10. using namespace std;
  11. using namespace NICE;
  12. double LocalizationAnalysis::calcAveragePrecision ( const vector<double> & recall,
  13. const vector<double> & precision )
  14. {
  15. // This is the PASCAL VOC version of computing
  16. // a kind of interpolated average precision
  17. // "The intention in interpolating the precision/recall curve
  18. // in this way is to reduce the impact of the “wiggles” in
  19. // the precision/recall curve, caused by small variations in the
  20. // ranking of examples"
  21. //
  22. // implementation:
  23. // \int_0^1 (max_{recall(t') >= t) precision(t')) dt
  24. //
  25. double avgp = 0.0;
  26. for (double t = 0.0 ; t <= 1.0 ; t+=0.1 )
  27. {
  28. double p = 0.0;
  29. for ( uint k = 0 ; k < recall.size() ; k++ )
  30. if ( recall[k] >= t ) {
  31. if ( precision[k] >= p )
  32. p = precision[k];
  33. }
  34. avgp += p / 11;
  35. }
  36. return avgp;
  37. }
  38. double LocalizationAnalysis::calcAveragePrecisionPrecise ( const vector<double> & recall,
  39. const vector<double> & precision )
  40. {
  41. // average precision is defined as:
  42. // int_0^1 precision(recall) drecall
  43. // = int_0^1 precision(t) recall'(t) dt
  44. double avgp = 0.0;
  45. double oldrec = recall[0];
  46. if ( (recall[0] != 0.0) || (recall[recall.size()-1] != 1.0) )
  47. fthrow(Exception, "Recall/Precision values have to include (0,x) and (1,y)");
  48. for (uint t = 1 ; t < recall.size(); t++ )
  49. {
  50. double prec = precision[t];
  51. double rec = recall[t];
  52. // dt of recall' and of the integral are
  53. // cancelling out
  54. double drec = rec - oldrec;
  55. avgp += prec * drec;
  56. oldrec = rec;
  57. }
  58. return avgp;
  59. }
  60. double LocalizationAnalysis::trapezoidArea ( double x1, double y1,
  61. double x2, double y2 )
  62. {
  63. return ( x2 - x1 ) * ( y1 + y2 ) / 2.0;
  64. }
  65. double LocalizationAnalysis::calcAreaUnderROC ( const vector<double> & fprate,
  66. const vector<double> & tprate )
  67. {
  68. if ( tprate.size() != fprate.size() )
  69. fthrow(Exception, "True positive rates and false positives rates do not match according to the" <<
  70. " size of their vectors.");
  71. double area = 0.0;
  72. double oldfpr = 0.0;
  73. double oldtpr = 0.0;
  74. for ( uint k = 0 ; k < tprate.size() ; k++ )
  75. {
  76. double fpr = fprate[k];
  77. double tpr = tprate[k];
  78. double newArea = trapezoidArea ( oldfpr, oldtpr, fpr, tpr );
  79. area += newArea;
  80. oldfpr = fpr;
  81. oldtpr = tpr;
  82. }
  83. return area;
  84. }
  85. void LocalizationAnalysis::matchResults ( LocalizationResult *l,
  86. const LocalizationResult *l_gt,
  87. vector< pair<double, int> > & results,
  88. double matchThreshold,
  89. bool rejectMultipleDetections )
  90. {
  91. if ( l == NULL ) return;
  92. // stat: tp fp tn fn
  93. set<SingleLocalizationResult *> matchedHypotheses;
  94. l->sortDescendingConfidence();
  95. double measureMax = 0.0;
  96. for ( LocalizationResult::const_iterator i = l->begin();
  97. i != l->end(); i++ )
  98. {
  99. SingleLocalizationResult *slr_i = *i;
  100. SingleLocalizationResult *matched_gt = NULL;
  101. int classno_i = slr_i->r->classno;
  102. double confidence = slr_i->r->confidence();
  103. if ( l_gt != NULL )
  104. for ( LocalizationResult::const_iterator j = l_gt->begin();
  105. j != l_gt->end(); j++ )
  106. {
  107. SingleLocalizationResult *slr_j = *j;
  108. if ( classno_i == slr_j->r->classno ) {
  109. double m = slr_i->getBBOverlapMeasure ( *slr_j );
  110. if ( m > measureMax ) measureMax = m;
  111. if ( m > matchThreshold )
  112. {
  113. if ( matched_gt != NULL )
  114. {
  115. fprintf (stderr, "Something strange happened: object hypothesis matched with two different ground truth annotations !! : Overlap issue\n");
  116. fprintf (stderr, "match score %f\n", m );
  117. fprintf (stderr, "match threshold %f\n", matchThreshold);
  118. fprintf (stderr, "sizes algorithm: %zd; sizes groundtruth: %zd\n", l->size(), l_gt->size() );
  119. int xi, yi, xa, ya;
  120. slr_i->getBoundingBox ( xi, yi, xa, ya );
  121. fprintf (stderr, "algorithm: %d %d %d %d\n", xi, yi, xa, ya );
  122. slr_j->getBoundingBox ( xi, yi, xa, ya );
  123. fprintf (stderr, "groundtruth: %d %d %d %d\n", xi, yi, xa, ya );
  124. }
  125. matched_gt = slr_j;
  126. }
  127. }
  128. }
  129. if ( matched_gt == NULL )
  130. {
  131. results.push_back ( pair<double, int> ( confidence, 0 ) );
  132. } else {
  133. if ( matchedHypotheses.find(matched_gt) == matchedHypotheses.end() )
  134. {
  135. matchedHypotheses.insert ( matched_gt );
  136. results.push_back ( pair<double, int> ( confidence, 1 ) );
  137. } else {
  138. // Multiple Detections
  139. if (rejectMultipleDetections)
  140. results.push_back ( pair<double, int> ( confidence, 0 ) );
  141. }
  142. }
  143. }
  144. }
  145. void LocalizationAnalysis::calcRecallPrecisionCurve ( const vector< pair<double, int> > & results_unsorted,
  146. int count_positives,
  147. vector<double> & thresholdsv,
  148. vector<double> & recallv,
  149. vector<double> & precisionv )
  150. {
  151. vector<pair<double, int> > results;
  152. for ( vector<pair< double, int > >::const_iterator i = results_unsorted.begin();
  153. i != results_unsorted.end(); i++ )
  154. results.push_back ( pair<double, int> ( - i->first, i->second ) );
  155. sort ( results.begin(), results.end() );
  156. thresholdsv.clear();
  157. recallv.clear();
  158. precisionv.clear();
  159. long fp = 0;
  160. long tp = 0;
  161. for ( vector<pair<double,int> >::const_iterator i = results.begin();
  162. i != results.end();
  163. i++ )
  164. {
  165. double confidence = - i->first;
  166. int ok = i->second;
  167. // at this step we have virtually defined a threshold of confidence-epsilon
  168. tp += ok;
  169. fp += 1-ok;
  170. // wikipedia.org
  171. // Recall in this context is defined as the number of true positives divided by the total number of elements that actually belong
  172. // to the positive class (i.e. the sum of true positives and false negatives, which are items which were not labeled as belonging to the positive class but should have been).
  173. double recall = tp / (double)count_positives;
  174. // In a statistical classification task, the Precision for a class is the number of true positives
  175. // (i.e. the number of items correctly labeled as belonging to the positive class) divided
  176. // by the total number of elements labeled as belonging to the positive class (i.e. the sum of true positives and false positives,
  177. // which are items incorrectly labeled as belonging to the class).
  178. double precision = tp / (double)(fp+tp);
  179. thresholdsv.push_back ( confidence );
  180. recallv.push_back ( recall );
  181. precisionv.push_back ( precision );
  182. }
  183. if ( recallv.size() > 0 )
  184. {
  185. if ( recallv[0] != 0.0 )
  186. {
  187. // label everything as negative
  188. recallv.insert ( recallv.begin(), 0.0 );
  189. precisionv.insert ( precisionv.begin(), 0.0 );
  190. thresholdsv.insert ( thresholdsv.begin(), std::numeric_limits<double>::max() );
  191. }
  192. if ( recallv[recallv.size() - 1] != 0.0 )
  193. {
  194. // label everything as positive
  195. // fp = count_negatives = results.size() - count_positives
  196. // tp = count_positives
  197. // recall = count_positives / count_positives = 1
  198. // precision = count_positives / ( results.size() - count_positives + count_positives );
  199. // = count_positives / results.size()
  200. recallv.insert ( recallv.end(), 1.0 );
  201. precisionv.insert ( precisionv.end(), count_positives / (double)results.size() );
  202. thresholdsv.insert ( thresholdsv.end(), - std::numeric_limits<double>::max() );
  203. }
  204. }
  205. }
  206. void LocalizationAnalysis::calcROCCurve ( const vector< pair<double, int> > & results_unsorted,
  207. int count_positives,
  208. int count_negatives,
  209. vector<double> & thresholdsv,
  210. vector<double> & fprates,
  211. vector<double> & tprates )
  212. {
  213. if ( (count_positives <= 0) )
  214. fthrow(Exception, "ROC Calculation: number of positive examples is zero");
  215. if ( (count_negatives <= 0) )
  216. fthrow(Exception, "ROC Calculation: number of negative examples is zero");
  217. vector<pair<double, int> > results;
  218. // sort the results descending
  219. for ( vector<pair< double, int > >::const_iterator i = results_unsorted.begin();
  220. i != results_unsorted.end(); i++ )
  221. results.push_back ( pair<double, int> ( - i->first, i->second ) );
  222. sort ( results.begin(), results.end() );
  223. long fp = 0;
  224. long tp = 0;
  225. double oldconfidence = - numeric_limits<double>::max();
  226. // descending order of the results !!
  227. for ( vector<pair<double,int> >::const_iterator i = results.begin();
  228. i != results.end();
  229. i++ )
  230. {
  231. // everything above the confidence
  232. // is regarded as positive
  233. double confidence = - i->first;
  234. int ok = i->second;
  235. if ( (ok != 1) && (ok != 0) )
  236. fthrow(Exception, "ROC Calculation: results should be labeled as 0 or 1 !");
  237. tp += ok;
  238. fp += 1-ok;
  239. // This test ensures that we wait for the end of a span of
  240. // equal probabilities before emitting a point.
  241. // Instead of computing a pessimistic version of the ROC curve,
  242. // we use the expected ROC curve (see Tom Fawcetts paper)
  243. // I changed this in 7/6/2011 to ensure the compability of ROC.pl
  244. if ( confidence == oldconfidence )
  245. continue;
  246. double tprate = tp / (double)count_positives;
  247. double fprate = fp / (double)count_negatives;
  248. thresholdsv.push_back ( confidence );
  249. fprates.push_back ( fprate );
  250. tprates.push_back ( tprate );
  251. oldconfidence = confidence;
  252. }
  253. if ( tprates.size() > 0 )
  254. {
  255. if ( tprates[0] != 0.0 )
  256. {
  257. // label everything as negative
  258. tprates.insert ( tprates.begin(), 0.0 );
  259. fprates.insert ( fprates.begin(), 0.0 );
  260. thresholdsv.insert ( thresholdsv.begin(), std::numeric_limits<double>::max() );
  261. }
  262. if ( tprates[tprates.size() - 1] != 1.0 )
  263. {
  264. // label everything as positive
  265. tprates.insert ( tprates.end(), 1.0 );
  266. fprates.insert ( fprates.end(), 1.0 );
  267. thresholdsv.insert ( thresholdsv.end(), - std::numeric_limits<double>::max() );
  268. }
  269. }
  270. }
  271. LocalizationAnalysis::LocalizationAnalysis()
  272. {
  273. }
  274. LocalizationAnalysis::~LocalizationAnalysis()
  275. {
  276. }