Commit 3122cac3a97f03b34b0b1fab226e40aeb0c78cb8

Authored by Scott Klum
2 parents cb35ce83 d0310151

Merge pull request #310 from biometrics/eval_landmark_improvements

Eval landmark improvements
app/br/br.cpp
@@ -163,8 +163,8 @@ public: @@ -163,8 +163,8 @@ public:
163 check((parc >= 2) && (parc <= 6), "Incorrect parameter count for 'evalDetection'."); 163 check((parc >= 2) && (parc <= 6), "Incorrect parameter count for 'evalDetection'.");
164 br_eval_detection(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? atoi(parv[3]) : 0, parc >= 5 ? atoi(parv[4]) : 0, parc == 6 ? atoi(parv[5]) : 0); 164 br_eval_detection(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? atoi(parv[3]) : 0, parc >= 5 ? atoi(parv[4]) : 0, parc == 6 ? atoi(parv[5]) : 0);
165 } else if (!strcmp(fun, "evalLandmarking")) { 165 } else if (!strcmp(fun, "evalLandmarking")) {
166 - check((parc >= 2) && (parc <= 5), "Incorrect parameter count for 'evalLandmarking'.");  
167 - br_eval_landmarking(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? atoi(parv[3]) : 0, parc >= 5 ? atoi(parv[4]) : 1); 166 + check((parc >= 2) && (parc <= 7), "Incorrect parameter count for 'evalLandmarking'.");
  167 + br_eval_landmarking(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? atoi(parv[3]) : 0, parc >= 5 ? atoi(parv[4]) : 1, parc >= 6 ? atoi(parv[5]) : 0, parc >= 7 ? atoi(parv[6]) : 5);
168 } else if (!strcmp(fun, "evalRegression")) { 168 } else if (!strcmp(fun, "evalRegression")) {
169 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalRegression'."); 169 check(parc >= 2 && parc <= 4, "Incorrect parameter count for 'evalRegression'.");
170 br_eval_regression(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : ""); 170 br_eval_regression(parv[0], parv[1], parc >= 3 ? parv[2] : "", parc >= 4 ? parv[3] : "");
@@ -264,7 +264,7 @@ private: @@ -264,7 +264,7 @@ private:
264 "-evalClassification <predicted_gallery> <truth_gallery> <predicted property name> <ground truth proprty name>\n" 264 "-evalClassification <predicted_gallery> <truth_gallery> <predicted property name> <ground truth proprty name>\n"
265 "-evalClustering <clusters> <gallery>\n" 265 "-evalClustering <clusters> <gallery>\n"
266 "-evalDetection <predicted_gallery> <truth_gallery> [{csv}] [{normalize}] [{minSize}]\n" 266 "-evalDetection <predicted_gallery> <truth_gallery> [{csv}] [{normalize}] [{minSize}]\n"
267 - "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>]]\n" 267 + "-evalLandmarking <predicted_gallery> <truth_gallery> [{csv} [<normalization_index_a> <normalization_index_b>] [sample_index] [total_examples]]\n"
268 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n" 268 "-evalRegression <predicted_gallery> <truth_gallery> <predicted property name> <ground truth property name>\n"
269 "-assertEval <simmat> <mask> <accuracy>\n" 269 "-assertEval <simmat> <mask> <accuracy>\n"
270 "-plotDetection <file> ... <file> {destination}\n" 270 "-plotDetection <file> ... <file> {destination}\n"
openbr/core/eval.cpp
@@ -18,6 +18,7 @@ @@ -18,6 +18,7 @@
18 #include "eval.h" 18 #include "eval.h"
19 #include "openbr/core/common.h" 19 #include "openbr/core/common.h"
20 #include "openbr/core/qtutils.h" 20 #include "openbr/core/qtutils.h"
  21 +#include "openbr/core/opencvutils.h"
21 #include <QMapIterator> 22 #include <QMapIterator>
22 23
23 using namespace cv; 24 using namespace cv;
@@ -1068,16 +1069,25 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery @@ -1068,16 +1069,25 @@ float EvalDetection(const QString &amp;predictedGallery, const QString &amp;truthGallery
1068 return averageOverlap; 1069 return averageOverlap;
1069 } 1070 }
1070 1071
1071 -float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv, int normalizationIndexA, int normalizationIndexB) 1072 +static void projectAndWrite(Transform *t, const Template &src, const QString &filePath)
  1073 +{
  1074 + Template dst;
  1075 + t->project(src,dst);
  1076 + OpenCVUtils::saveImage(dst.m(),filePath);
  1077 +}
  1078 +
  1079 +float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv, int normalizationIndexA, int normalizationIndexB, int sampleIndex, int totalExamples)
1072 { 1080 {
1073 qDebug("Evaluating landmarking of %s against %s", qPrintable(predictedGallery), qPrintable(truthGallery)); 1081 qDebug("Evaluating landmarking of %s against %s", qPrintable(predictedGallery), qPrintable(truthGallery));
1074 - const TemplateList predicted(TemplateList::fromGallery(predictedGallery));  
1075 - const TemplateList truth(TemplateList::fromGallery(truthGallery));  
1076 - const QStringList predictedNames = File::get<QString>(predicted, "name");  
1077 - const QStringList truthNames = File::get<QString>(truth, "name"); 1082 + TemplateList predicted(TemplateList::fromGallery(predictedGallery));
  1083 + TemplateList truth(TemplateList::fromGallery(truthGallery));
  1084 + QStringList predictedNames = File::get<QString>(predicted, "name");
  1085 + QStringList truthNames = File::get<QString>(truth, "name");
1078 1086
1079 int skipped = 0; 1087 int skipped = 0;
1080 QList< QList<float> > pointErrors; 1088 QList< QList<float> > pointErrors;
  1089 + QList<float> imageErrors;
  1090 + QList<float> normalizedLengths;
1081 for (int i=0; i<predicted.size(); i++) { 1091 for (int i=0; i<predicted.size(); i++) {
1082 const QString &predictedName = predictedNames[i]; 1092 const QString &predictedName = predictedNames[i];
1083 const int truthIndex = truthNames.indexOf(predictedName); 1093 const int truthIndex = truthNames.indexOf(predictedName);
@@ -1085,39 +1095,94 @@ float EvalLandmarking(const QString &amp;predictedGallery, const QString &amp;truthGalle @@ -1085,39 +1095,94 @@ float EvalLandmarking(const QString &amp;predictedGallery, const QString &amp;truthGalle
1085 const QList<QPointF> predictedPoints = predicted[i].file.points(); 1095 const QList<QPointF> predictedPoints = predicted[i].file.points();
1086 const QList<QPointF> truthPoints = truth[truthIndex].file.points(); 1096 const QList<QPointF> truthPoints = truth[truthIndex].file.points();
1087 if (predictedPoints.size() != truthPoints.size() || truthPoints.contains(QPointF(-1,-1))) { 1097 if (predictedPoints.size() != truthPoints.size() || truthPoints.contains(QPointF(-1,-1))) {
1088 - skipped++; 1098 + predicted.removeAt(i);
  1099 + predictedNames.removeAt(i);
  1100 + truth.removeAt(i);
  1101 + truthNames.removeAt(i);
  1102 + i--; skipped++;
1089 continue; 1103 continue;
1090 } 1104 }
  1105 +
1091 while (pointErrors.size() < predictedPoints.size()) 1106 while (pointErrors.size() < predictedPoints.size())
1092 pointErrors.append(QList<float>()); 1107 pointErrors.append(QList<float>());
  1108 +
  1109 + // Want to know error for every image.
  1110 +
1093 if (normalizationIndexA >= truthPoints.size()) qFatal("Normalization index A is out of range."); 1111 if (normalizationIndexA >= truthPoints.size()) qFatal("Normalization index A is out of range.");
1094 if (normalizationIndexB >= truthPoints.size()) qFatal("Normalization index B is out of range."); 1112 if (normalizationIndexB >= truthPoints.size()) qFatal("Normalization index B is out of range.");
1095 const float normalizedLength = QtUtils::euclideanLength(truthPoints[normalizationIndexB] - truthPoints[normalizationIndexA]); 1113 const float normalizedLength = QtUtils::euclideanLength(truthPoints[normalizationIndexB] - truthPoints[normalizationIndexA]);
1096 - for (int j=0; j<predictedPoints.size(); j++)  
1097 - pointErrors[j].append(QtUtils::euclideanLength(predictedPoints[j] - truthPoints[j])/normalizedLength); 1114 + normalizedLengths.append(normalizedLength);
  1115 + float totalError = 0;
  1116 + for (int j=0; j<predictedPoints.size(); j++) {
  1117 + float error = QtUtils::euclideanLength(predictedPoints[j] - truthPoints[j])/normalizedLength;
  1118 + totalError += error;
  1119 + pointErrors[j].append(error);
  1120 + }
  1121 + imageErrors.append(totalError/predictedPoints.size());
1098 } 1122 }
1099 - qDebug() << "Skipped " << skipped << " files due to point size mismatch."; 1123 +
  1124 + qDebug() << "Skipped" << skipped << "files due to point size mismatch.";
1100 1125
1101 QList<float> averagePointErrors; averagePointErrors.reserve(pointErrors.size()); 1126 QList<float> averagePointErrors; averagePointErrors.reserve(pointErrors.size());
1102 - for (int i=0; i<pointErrors.size(); i++) {  
1103 - std::sort(pointErrors[i].begin(), pointErrors[i].end());  
1104 - averagePointErrors.append(Common::Mean(pointErrors[i]));  
1105 - }  
1106 - const float averagePointError = Common::Mean(averagePointErrors);  
1107 1127
1108 QStringList lines; 1128 QStringList lines;
1109 lines.append("Plot,X,Y"); 1129 lines.append("Plot,X,Y");
  1130 +
  1131 + QtUtils::touchDir(QDir("landmarking_examples_truth"));
  1132 + QtUtils::touchDir(QDir("landmarking_examples_predicted"));
  1133 +
  1134 + // Example
  1135 + {
  1136 + QScopedPointer<Transform> t(Transform::make("Open+Draw(verbose,rects=false,location=false)",NULL));
  1137 +
  1138 + QString filePath = "landmarking_examples_truth/"+truth[sampleIndex].file.fileName();
  1139 + projectAndWrite(t.data(), truth[sampleIndex],filePath);
  1140 + lines.append("Sample,"+filePath+","+QString::number(truth[sampleIndex].file.points().size()));
  1141 + }
  1142 +
  1143 + // Get best and worst performing examples
  1144 + QList< QPair<float,int> > exampleIndices = Common::Sort(imageErrors,true);
  1145 +
  1146 + QScopedPointer<Transform> t(Transform::make("Open+Draw(rects=false)",NULL));
  1147 +
  1148 + for (int i=0; i<totalExamples; i++) {
  1149 + QString filePath = "landmarking_examples_truth/"+truth[exampleIndices[i].second].file.fileName();
  1150 + projectAndWrite(t.data(), truth[exampleIndices[i].second],filePath);
  1151 + lines.append("EXT,"+filePath+","+QString::number(exampleIndices[i].first));
  1152 +
  1153 + filePath = "landmarking_examples_predicted/"+predicted[exampleIndices[i].second].file.fileName();
  1154 + projectAndWrite(t.data(), predicted[exampleIndices[i].second],filePath);
  1155 + lines.append("EXP,"+filePath+","+QString::number(exampleIndices[i].first));
  1156 + }
  1157 +
  1158 + for (int i=exampleIndices.size()-1; i>exampleIndices.size()-totalExamples-1; i--) {
  1159 + QString filePath = "landmarking_examples_truth/"+truth[exampleIndices[i].second].file.fileName();
  1160 + projectAndWrite(t.data(), truth[exampleIndices[i].second],filePath);
  1161 + lines.append("EXT,"+filePath+","+QString::number(exampleIndices[i].first));
  1162 +
  1163 + filePath = "landmarking_examples_predicted/"+predicted[exampleIndices[i].second].file.fileName();
  1164 + projectAndWrite(t.data(), predicted[exampleIndices[i].second],filePath);
  1165 + lines.append("EXP,"+filePath+","+QString::number(exampleIndices[i].first));
  1166 + }
  1167 +
1110 for (int i=0; i<pointErrors.size(); i++) { 1168 for (int i=0; i<pointErrors.size(); i++) {
  1169 + std::sort(pointErrors[i].begin(), pointErrors[i].end());
  1170 + averagePointErrors.append(Common::Mean(pointErrors[i]));
1111 const QList<float> &pointError = pointErrors[i]; 1171 const QList<float> &pointError = pointErrors[i];
1112 const int keep = qMin(Max_Points, pointError.size()); 1172 const int keep = qMin(Max_Points, pointError.size());
1113 for (int j=0; j<keep; j++) 1173 for (int j=0; j<keep; j++)
1114 lines.append(QString("Box,%1,%2").arg(QString::number(i), QString::number(pointError[j*(pointError.size()-1)/(keep-1)]))); 1174 lines.append(QString("Box,%1,%2").arg(QString::number(i), QString::number(pointError[j*(pointError.size()-1)/(keep-1)])));
1115 } 1175 }
1116 1176
  1177 + const float averagePointError = Common::Mean(averagePointErrors);
  1178 +
1117 lines.append(QString("AvgError,0,%1").arg(averagePointError)); 1179 lines.append(QString("AvgError,0,%1").arg(averagePointError));
  1180 + lines.append(QString("NormLength,0,%1").arg(Common::Mean(normalizedLengths)));
1118 1181
1119 QtUtils::writeFile(csv, lines); 1182 QtUtils::writeFile(csv, lines);
1120 - qDebug("Average Error: %.3f", averagePointError); 1183 +
  1184 + qDebug("Average Error for all Points: %.3f", averagePointError);
  1185 +
1121 return averagePointError; 1186 return averagePointError;
1122 } 1187 }
1123 1188
openbr/core/eval.h
@@ -31,7 +31,7 @@ namespace br @@ -31,7 +31,7 @@ namespace br
31 31
32 void EvalClassification(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = ""); 32 void EvalClassification(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = "");
33 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", bool normalize = false, int minSize = 0, int maxSize = 0); // Return average overlap 33 float EvalDetection(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", bool normalize = false, int minSize = 0, int maxSize = 0); // Return average overlap
34 - float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", int normalizationIndexA = 0, int normalizationIndexB = 1); // Return average error 34 + float EvalLandmarking(const QString &predictedGallery, const QString &truthGallery, const QString &csv = "", int normalizationIndexA = 0, int normalizationIndexB = 1, int sampleIndex = 0, int totalExamples = 5); // Return average error
35 void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = ""); 35 void EvalRegression(const QString &predictedGallery, const QString &truthGallery, QString predictedProperty = "", QString truthProperty = "");
36 } 36 }
37 37
openbr/core/plot.cpp
@@ -482,16 +482,115 @@ bool PlotLandmarking(const QStringList &amp;files, const File &amp;destination, bool sho @@ -482,16 +482,115 @@ bool PlotLandmarking(const QStringList &amp;files, const File &amp;destination, bool sho
482 qDebug("Plotting %d landmarking file(s) to %s", files.size(), qPrintable(destination)); 482 qDebug("Plotting %d landmarking file(s) to %s", files.size(), qPrintable(destination));
483 RPlot p(files, destination, false); 483 RPlot p(files, destination, false);
484 484
485 - p.file.write("# Split data into individual plots\n"  
486 - "plot_index = which(names(data)==\"Plot\")\n"  
487 - "Box <- data[grep(\"Box\",data$Plot),-c(1)]\n"  
488 - "rm(data)\n"  
489 - "\n");  
490 -  
491 - p.file.write(qPrintable(QString("ggplot(Box, aes(Y,%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) + 485 + p.file.write(qPrintable(QString("# Split data into individual plots\n"
  486 + "plot_index = which(names(data)==\"Plot\")\n"
  487 + "Box <- data[grep(\"Box\",data$Plot),-c(1)]\n"
  488 + "Box$X <- factor(Box$X, levels = Box$X, ordered = TRUE)\n"
  489 + "Sample <- data[grep(\"Sample\",data$Plot),-c(1)]\n"
  490 + "Sample$X <- as.character(Sample$X)\n"
  491 + "EXT <- data[grep(\"EXT\",data$Plot),-c(1)]\n"
  492 + "EXT$X <- as.character(EXT$X)\n"
  493 + "EXP <- data[grep(\"EXP\",data$Plot),-c(1)]\n"
  494 + "EXP$X <- as.character(EXP$X)\n"
  495 + "NormLength <- data[grep(\"NormLength\",data$Plot),-c(1)]\n"
  496 + "rm(data)\n"
  497 + "\n")));
  498 +
  499 + p.file.write(qPrintable(QString("summarySE <- function(data=NULL, measurevar, groupvars=NULL, na.rm=FALSE, conf.interval=.95, .drop=TRUE) {\n\t"
  500 + "require(plyr)\n\n\tlength2 <- function (x, na.rm=FALSE) {\n\t\tif (na.rm) sum(!is.na(x))\n\t\telse length(x)"
  501 + "\n\t}\n\n\tdatac <- ddply(data, groupvars, .drop=.drop, .fun = function(xx, col) {\n\t\t"
  502 + "c(N=length2(xx[[col]], na.rm=na.rm), mean=mean(xx[[col]], na.rm=na.rm), sd=sd(xx[[col]], na.rm=na.rm))\n\t\t},"
  503 + "\n\t\tmeasurevar\n\t)\n\n\tdatac <- rename(datac, c(\"mean\" = measurevar))\n\tdatac$se <- datac$sd / sqrt(datac$N)"
  504 + "\n\tciMult <- qt(conf.interval/2 + .5, datac$N-1)\n\tdatac$ci <- datac$se * ciMult\n\n\treturn(datac)\n}\n")));
  505 +
  506 +
  507 + p.file.write(qPrintable(QString("\nreadData <- function(data) {\n\texamples <- list()\n"
  508 + "\tfor (i in 1:nrow(data)) {\n"
  509 + "\t\tpath <- data[i,1]\n"
  510 + "\t\tvalue <- data[i,2]\n"
  511 + "\t\tfile <- unlist(strsplit(path, \"[.]\"))[1]\n"
  512 + "\t\text <- unlist(strsplit(path, \"[.]\"))[2]\n"
  513 + "\t\tif (ext == \"jpg\" || ext == \"JPEG\" || ext == \"jpeg\" || ext == \"JPG\") {\n"
  514 + "\t\t\timg <- readJPEG(path)\n"
  515 + "\t\t} else if (ext == \"PNG\" || ext == \"png\") {\n"
  516 + "\t\t\timg <- readPNG(path)\n"
  517 + "\t\t} else if (ext == \"TIFF\" || ext == \"tiff\" || ext == \"TIF\" || ext == \"tif\") { \n"
  518 + "\t\t\timg <- readTIFF(path)\n"
  519 + "}else {\n"
  520 + "\t\t\tnext\n"
  521 + "\t\t}\n"
  522 + "\t\texample <- list(file = file, value = value, image = img)\n"
  523 + "\t\texamples[[i]] <- example\n"
  524 + "\t}\n"
  525 + "\treturn(examples)\n"
  526 + "}\n")));
  527 +
  528 + p.file.write(qPrintable(QString("\nlibrary(jpeg)\n"
  529 + "library(png)\n"
  530 + "library(grid)\n"
  531 + "multiplot <- function(..., plotlist=NULL, cols) {\n"
  532 + "\trequire(grid)\n"
  533 + "\t# Make a list from the ... arguments and plotlist\n"
  534 + "\tplots <- c(list(...), plotlist)\n"
  535 + "\tnumPlots = length(plots)\n"
  536 + "\t# Make the panel\n"
  537 + "\tplotCols = cols\n"
  538 + "\tplotRows = ceiling(numPlots/plotCols)\n"
  539 + "\t# Set up the page\n"
  540 + "\tgrid.newpage()\n"
  541 + "\tpushViewport(viewport(layout = grid.layout(plotRows, plotCols)))\n"
  542 + "\tvplayout <- function(x, y)\n"
  543 + "\tviewport(layout.pos.row = x, layout.pos.col = y)\n"
  544 + "\t# Make each plot, in the correct location\n"
  545 + "\tfor (i in 1:numPlots) {\n"
  546 + "\t\tcurRow = ceiling(i/plotCols)\n"
  547 + "\t\tcurCol = (i-1) %% plotCols + 1\n"
  548 + "\t\tprint(plots[[i]], vp = vplayout(curRow, curCol))\n"
  549 + "\t}\n"
  550 + "}\n")));
  551 +
  552 + p.file.write(qPrintable(QString("\nplotImage <- function(image, title=NULL, label=NULL) { \n"
  553 + "\tp <- qplot(1:10, 1:10, geom=\"blank\") + annotation_custom(rasterGrob(image$image), xmin=-Inf, xmax=Inf, ymin=-Inf, ymax=Inf) + theme(axis.line=element_blank(), axis.title.y=element_blank(), axis.text.x=element_blank(), axis.text.y=element_blank(), line=element_blank(), axis.ticks=element_blank(), panel.background=element_blank()) + labs(title=title) + xlab(label)\n"
  554 + "\treturn(p)"
  555 + "}\n")));
  556 +
  557 + p.file.write(qPrintable(QString("\nsample <- readData(Sample) \n"
  558 + "rows <- sample[[1]]$value\n"
  559 + "algs <- unique(Box$%1)\n"
  560 + "algs <- algs[!duplicated(algs)]\n"
  561 + "print(plotImage(sample[[1]],\"Sample Landmarks\",sprintf(\"Total Landmarks: %s\",sample[[1]]$value))) \n"
  562 + "if (nrow(EXT) != 0 && nrow(EXP)) {\n"
  563 + "\tfor (j in 1:length(algs)) {\n"
  564 + "\ttruthSample <- readData(EXT[EXT$. == algs[[j]],])\n"
  565 + "\tpredictedSample <- readData(EXP[EXP$. == algs[[j]],])\n"
  566 + "\t\tfor (i in 1:length(predictedSample)) {\n"
  567 + "\t\t\tmultiplot(plotImage(predictedSample[[i]],sprintf(\"%s\\nPredicted Landmarks\",algs[[j]]),sprintf(\"Average Landmark Error: %.3f\",predictedSample[[i]]$value)),plotImage(truthSample[[i]],\"Ground Truth\\nLandmarks\",\"\"),cols=2)\n"
  568 + "\t\t}\n"
  569 + "\t}\n"
  570 + "}\n").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header))));
  571 +
  572 + p.file.write(qPrintable(QString("\n"
  573 + "# Code to format error table\n"
  574 + "StatBox <- summarySE(Box, measurevar=\"Y\", groupvars=c(\"%1\",\"X\"))\n"
  575 + "OverallStatBox <- summarySE(Box, measurevar=\"Y\", groupvars=c(\"%1\"))\n"
  576 + "mat <- matrix(paste(as.character(round(StatBox$Y, 3)), round(StatBox$ci, 3), sep=\" \\u00b1 \"),nrow=rows,ncol=length(algs),byrow=FALSE)\n"
  577 + "mat <- rbind(mat, paste(as.character(round(OverallStatBox$Y, 3)), round(OverallStatBox$ci, 3), sep=\" \\u00b1 \"))\n"
  578 + "mat <- rbind(mat, as.character(round(NormLength$Y, 3)))\n"
  579 + "colnames(mat) <- algs\n"
  580 + "rownames(mat) <- c(seq(0,rows-1),\"Aggregate\",\"Average IPD\")\n"
  581 + "ETable <- as.table(mat)\n").arg(p.major.size > 1 ? p.major.header : (p.minor.header.isEmpty() ? p.major.header : p.minor.header))));
  582 +
  583 + p.file.write(qPrintable(QString("\n"
  584 + "print(textplot(ETable))\n"
  585 + "print(title(\"Landmarking Error Rates\"))\n")));
  586 +
  587 + p.file.write(qPrintable(QString("ggplot(Box, aes(Y,%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(),
  588 + p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
492 QString(" + annotation_logticks(sides=\"b\") + stat_ecdf() + scale_x_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10)) + scale_y_continuous(\"Cumulative Density\", label=percent) + theme_minimal()\n\n"))); 589 QString(" + annotation_logticks(sides=\"b\") + stat_ecdf() + scale_x_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10)) + scale_y_continuous(\"Cumulative Density\", label=percent) + theme_minimal()\n\n")));
  590 +
493 p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) + 591 p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
494 - QString("+ annotation_logticks(sides=\"l\") + geom_boxplot(alpha=0.5) + geom_jitter(size=1, alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.01,0.1,1,10)) + theme_minimal()\n\n"))); 592 + QString("+ annotation_logticks(sides=\"l\") + geom_boxplot(alpha=0.5) + geom_jitter(size=1, alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10)) + theme_minimal()\n\n")));
  593 +
495 p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) + 594 p.file.write(qPrintable(QString("ggplot(Box, aes(factor(X), Y%1%2))").arg(p.major.size > 1 ? QString(", colour=%1").arg(p.major.header) : QString(), p.minor.size > 1 ? QString(", linetype=%1").arg(p.minor.header) : QString()) +
496 QString("+ annotation_logticks(sides=\"l\") + geom_violin(alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10))\n\n"))); 595 QString("+ annotation_logticks(sides=\"l\") + geom_violin(alpha=0.5) + scale_x_discrete(\"Landmark\") + scale_y_log10(\"Normalized Error\", breaks=c(0.001,0.01,0.1,1,10))\n\n")));
497 596
openbr/openbr.cpp
@@ -134,9 +134,9 @@ float br_eval_detection(const char *predicted_gallery, const char *truth_gallery @@ -134,9 +134,9 @@ float br_eval_detection(const char *predicted_gallery, const char *truth_gallery
134 return EvalDetection(predicted_gallery, truth_gallery, csv, normalize, minSize, maxSize); 134 return EvalDetection(predicted_gallery, truth_gallery, csv, normalize, minSize, maxSize);
135 } 135 }
136 136
137 -float br_eval_landmarking(const char *predicted_gallery, const char *truth_gallery, const char *csv, int normalization_index_a, int normalization_index_b) 137 +float br_eval_landmarking(const char *predicted_gallery, const char *truth_gallery, const char *csv, int normalization_index_a, int normalization_index_b, int sample_index, int total_examples)
138 { 138 {
139 - return EvalLandmarking(predicted_gallery, truth_gallery, csv, normalization_index_a, normalization_index_b); 139 + return EvalLandmarking(predicted_gallery, truth_gallery, csv, normalization_index_a, normalization_index_b, sample_index, total_examples);
140 } 140 }
141 141
142 void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property, const char *truth_property) 142 void br_eval_regression(const char *predicted_gallery, const char *truth_gallery, const char *predicted_property, const char *truth_property)
openbr/openbr.h
@@ -214,8 +214,10 @@ BR_EXPORT float br_eval_detection(const char *predicted_gallery, const char *tru @@ -214,8 +214,10 @@ BR_EXPORT float br_eval_detection(const char *predicted_gallery, const char *tru
214 * \param csv Optional \c .csv file to contain performance metrics. 214 * \param csv Optional \c .csv file to contain performance metrics.
215 * \param normalization_index_a Optional first index in the list of points to use for normalization. 215 * \param normalization_index_a Optional first index in the list of points to use for normalization.
216 * \param normalization_index_b Optional second index in the list of points to use for normalization. 216 * \param normalization_index_b Optional second index in the list of points to use for normalization.
  217 + * \param sample_index Optional index for sample landmark image in ground truth gallery.
  218 + * \param total_examples Optional number of accurate and inaccurate examples to display.
217 */ 219 */
218 -BR_EXPORT float br_eval_landmarking(const char *predicted_gallery, const char *truth_gallery, const char *csv = "", int normalization_index_a = 0, int normalization_index_b = 1); 220 +BR_EXPORT float br_eval_landmarking(const char *predicted_gallery, const char *truth_gallery, const char *csv = "", int normalization_index_a = 0, int normalization_index_b = 1, int sample_index = 0, int total_examples = 5);
219 221
220 /*! 222 /*!
221 * \brief Evaluates regression accuracy to disk. 223 * \brief Evaluates regression accuracy to disk.
openbr/plugins/draw.cpp
@@ -42,11 +42,15 @@ class DrawTransform : public UntrainableTransform @@ -42,11 +42,15 @@ class DrawTransform : public UntrainableTransform
42 Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false) 42 Q_PROPERTY(bool rects READ get_rects WRITE set_rects RESET reset_rects STORED false)
43 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) 43 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)
44 Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false) 44 Q_PROPERTY(int lineThickness READ get_lineThickness WRITE set_lineThickness RESET reset_lineThickness STORED false)
  45 + Q_PROPERTY(bool named READ get_named WRITE set_named RESET reset_named STORED false)
  46 + Q_PROPERTY(bool location READ get_location WRITE set_location RESET reset_location STORED false)
45 BR_PROPERTY(bool, verbose, false) 47 BR_PROPERTY(bool, verbose, false)
46 BR_PROPERTY(bool, points, true) 48 BR_PROPERTY(bool, points, true)
47 BR_PROPERTY(bool, rects, true) 49 BR_PROPERTY(bool, rects, true)
48 BR_PROPERTY(bool, inPlace, false) 50 BR_PROPERTY(bool, inPlace, false)
49 BR_PROPERTY(int, lineThickness, 1) 51 BR_PROPERTY(int, lineThickness, 1)
  52 + BR_PROPERTY(bool, named, true)
  53 + BR_PROPERTY(bool, location, true)
50 54
51 void project(const Template &src, Template &dst) const 55 void project(const Template &src, Template &dst) const
52 { 56 {
@@ -55,11 +59,12 @@ class DrawTransform : public UntrainableTransform @@ -55,11 +59,12 @@ class DrawTransform : public UntrainableTransform
55 dst.m() = inPlace ? src.m() : src.m().clone(); 59 dst.m() = inPlace ? src.m() : src.m().clone();
56 60
57 if (points) { 61 if (points) {
58 - const QList<Point2f> pointsList = OpenCVUtils::toPoints(src.file.namedPoints() + src.file.points()); 62 + const QList<Point2f> pointsList = (named) ? OpenCVUtils::toPoints(src.file.points()+src.file.namedPoints()) : OpenCVUtils::toPoints(src.file.points());
59 for (int i=0; i<pointsList.size(); i++) { 63 for (int i=0; i<pointsList.size(); i++) {
60 const Point2f &point = pointsList[i]; 64 const Point2f &point = pointsList[i];
61 circle(dst, point, 3, color, -1); 65 circle(dst, point, 3, color, -1);
62 - if (verbose) putText(dst, QString("%1,(%2,%3)").arg(QString::number(i),QString::number(point.x),QString::number(point.y)).toStdString(), point, FONT_HERSHEY_SIMPLEX, 0.5, verboseColor, 1); 66 + QString label = (location) ? QString("%1,(%2,%3)").arg(QString::number(i),QString::number(point.x),QString::number(point.y)) : QString("%1").arg(QString::number(i));
  67 + if (verbose) putText(dst, label.toStdString(), point, FONT_HERSHEY_SIMPLEX, 0.5, verboseColor, 1);
63 } 68 }
64 } 69 }
65 if (rects) { 70 if (rects) {