001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.image.processing.face.detection.benchmarking; 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.openimaj.image.processing.face.detection.DetectedFace; 036import org.openimaj.image.processing.face.detection.benchmarking.Matcher.Match; 037 038public class Results { 039 // / number of annotated regions (TP+FN) 040 int N; 041 042 // / threshold used for computing this result 043 double scoreThreshold; 044 045 // / True positives -- continuous 046 double TPCont; 047 048 // / True positives -- discrete 049 double TPDisc; 050 051 // / False positives -- discrete 052 double FP; 053 054 // / Name of the image 055 String imName; 056 057 Results() { 058 } 059 060 Results(Results r) { 061 if (r != null) { 062 N = r.N; 063 TPCont = r.TPCont; 064 TPDisc = r.TPDisc; 065 FP = r.FP; 066 scoreThreshold = r.scoreThreshold; 067 } 068 } 069 070 Results(Results r, int N2) { 071 if (r != null) { 072 imName = r.imName; 073 N = r.N + N2; 074 TPCont = r.TPCont; 075 TPDisc = r.TPDisc; 076 FP = r.FP; 077 scoreThreshold = r.scoreThreshold; 078 } 079 } 080 081 Results(Results r1, Results r2) { 082 N = 0; 083 TPDisc = 0; 084 TPCont = 0; 085 FP = 0; 086 scoreThreshold = Double.MAX_VALUE; 087 088 if (r1 != null) { 089 imName = r1.imName; 090 N += r1.N; 091 TPCont += r1.TPCont; 092 TPDisc += r1.TPDisc; 093 FP += r1.FP; 094 if (r1.scoreThreshold < scoreThreshold) 095 scoreThreshold = r1.scoreThreshold; 096 } 097 098 if (r2 != null) { 099 imName = r2.imName; 100 N += r2.N; 101 TPCont += r2.TPCont; 102 TPDisc += r2.TPDisc; 103 FP += r2.FP; 104 if (r2.scoreThreshold < scoreThreshold) 105 scoreThreshold = r2.scoreThreshold; 106 } 107 } 108 109 Results(String s, double scoreThresh, List<Match> mp, List<? extends DetectedFace> annot, 110 List<? extends DetectedFace> det) 111 { 112 imName = s; 113 scoreThreshold = scoreThresh; 114 115 N = annot.size(); 116 117 FP = det.size(); 118 119 TPCont = 0; 120 TPDisc = 0; 121 if (mp != null) 122 for (int i = 0; i < mp.size(); i++) { 123 final double score = mp.get(i).score; 124 TPCont += score; 125 if (score > 0.5) { 126 TPDisc++; 127 FP--; 128 } 129 } 130 131 } 132 133 static List<Results> merge(List<Results> rv1, List<Results> rv2) { 134 135 final List<Results> mergeV = new ArrayList<Results>(); 136 int n1 = 0; 137 if (rv1 != null) 138 n1 = rv1.size(); 139 int n2 = 0; 140 if (rv2 != null) 141 n2 = rv2.size(); 142 143 int nAnnot1 = 0, nAnnot2 = 0; 144 145 if (n1 > 0) { 146 nAnnot1 = rv1.get(0).getN(); 147 if (n2 > 0) 148 nAnnot2 = rv2.get(0).getN(); 149 150 int i1 = 0, i2 = 0; 151 double score1, score2; 152 153 Results r1 = null; 154 Results r2 = null; 155 156 while (i1 < n1) { 157 r1 = rv1.get(i1); 158 score1 = rv1.get(i1).scoreThreshold; 159 if (i2 < n2) { 160 r2 = rv2.get(i2); 161 score2 = rv2.get(i2).scoreThreshold; 162 final Results newR = new Results(r1, r2); 163 mergeV.add(newR); 164 if (score1 < score2) { 165 i1++; 166 } else if (score1 == score2) { 167 i1++; 168 i2++; 169 } else { 170 i2++; 171 } 172 } else { 173 while (i1 < n1) { 174 // add from rv1 175 r1 = rv1.get(i1); 176 177 final Results newR = new Results(r1, nAnnot2); 178 mergeV.add(newR); 179 i1++; 180 } 181 } 182 } 183 184 while (i2 < n2) { 185 // add from rv2 186 r2 = rv2.get(i2); 187 final Results newR = new Results(r2, nAnnot1); 188 mergeV.add(newR); 189 i2++; 190 } 191 } else { 192 if (n2 > 0) { 193 for (int i = 0; i < n2; i++) 194 mergeV.add(new Results(rv2.get(i))); 195 } 196 } 197 return mergeV; 198 } 199 200 @Override 201 public String toString() { 202 return imName + " Threshold = " + scoreThreshold + " N = " + N + " TP cont = " + TPCont + " TP disc = " + TPDisc 203 + " FP = " + FP; 204 } 205 206 public static String getROCData(List<Results> rv) { 207 String osc = ""; 208 String osd = ""; 209 210 for (int i = 0; i < rv.size(); i++) 211 { 212 final Results r = rv.get(i); 213 if (r.N > 0) 214 { 215 osc += (r.TPCont / r.N) + " " + r.FP + "\n"; 216 osd += (r.TPDisc / r.N) + " " + r.FP + " " + r.scoreThreshold + "\n"; 217 } 218 else 219 { 220 osc += "0 0" + "\n"; 221 osd += "0 0 " + r.scoreThreshold + "\n"; 222 } 223 } 224 return "DISCRETE:\n" + osd + "\nCONTINOUS:\n" + osc; 225 } 226 227 public int getN() { 228 return N; 229 } 230}