Commit 579362d55fb1f1442efb009697e55d95c125f705

Authored by Scott Klum
2 parents 4b927765 92de65c4

Merge branch 'csv'

openbr/core/evalutils.cpp
@@ -263,7 +263,7 @@ QStringList EvalUtils::computeDetectionResults(const QList<ResolvedDetection> &d @@ -263,7 +263,7 @@ QStringList EvalUtils::computeDetectionResults(const QList<ResolvedDetection> &d
263 debug << QString("|") << QString::number(FAR, 'f', 4).leftJustified(10, ' '); 263 debug << QString("|") << QString::number(FAR, 'f', 4).leftJustified(10, ' ');
264 debug << QString("|") << QString::number(TP / totalTrueDetections, 'f', 4).leftJustified(10, ' '); 264 debug << QString("|") << QString::number(TP / totalTrueDetections, 'f', 4).leftJustified(10, ' ');
265 debug << QString("|") << QString::number(detection.confidence, 'f', 4).leftJustified(10, ' '); 265 debug << QString("|") << QString::number(detection.confidence, 'f', 4).leftJustified(10, ' ');
266 - debug << QString("|") << QString::number(poseMatch / TP, 'f', 4).leftJustified(10, ' '); 266 + debug << QString("|") << QString::number(TP ? poseMatch / TP : 0., 'f', 4).leftJustified(10, ' ');
267 debug << QString("|") << endl; 267 debug << QString("|") << endl;
268 break; 268 break;
269 } 269 }
openbr/core/qtutils.cpp
@@ -172,12 +172,20 @@ QString find(const QString &amp;file, const QString &amp;alt) @@ -172,12 +172,20 @@ QString find(const QString &amp;file, const QString &amp;alt)
172 return ""; 172 return "";
173 } 173 }
174 174
175 -bool toBool(const QString &string) 175 +bool toBool(const QString &string, bool *ok)
176 { 176 {
177 - bool ok;  
178 - bool result = (string.toFloat(&ok) != 0.f);  
179 - if (ok) return result;  
180 - else return (string != "FALSE") && (string != "false") && (string != "F") && (string != "f"); 177 + bool floatOk;
  178 + bool result = (string.toFloat(&floatOk) != 0.f);
  179 + if (floatOk) {
  180 + if (ok) *ok = true;
  181 + return result;
  182 + } else {
  183 + if (ok) *ok = (string.compare("false", Qt::CaseInsensitive) == 0 ||
  184 + string.compare("true", Qt::CaseInsensitive) == 0 ||
  185 + string.compare("f", Qt::CaseInsensitive) == 0 ||
  186 + string.compare("t", Qt::CaseInsensitive) == 0);
  187 + return (string.compare("false", Qt::CaseInsensitive) != 0 && string.compare("f", Qt::CaseInsensitive) != 0);
  188 + }
181 } 189 }
182 190
183 int toInt(const QString &string) 191 int toInt(const QString &string)
@@ -245,10 +253,10 @@ QStringList parse(QString args, char split, bool *ok) @@ -245,10 +253,10 @@ QStringList parse(QString args, char split, bool *ok)
245 QStack<QChar> subexpressions; 253 QStack<QChar> subexpressions;
246 for (int i=0; i<args.size(); i++) { 254 for (int i=0; i<args.size(); i++) {
247 if (inQuote) { 255 if (inQuote) {
248 - if (args[i] == '\'') 256 + if (args[i] == '\'' || args[i] == '\"')
249 inQuote = false; 257 inQuote = false;
250 } else { 258 } else {
251 - if (args[i] == '\'') { 259 + if (args[i] == '\'' || args[i] == '\"') {
252 inQuote = true; 260 inQuote = true;
253 } else if ((args[i] == '(') || (args[i] == '[') || (args[i] == '<') || (args[i] == '{')) { 261 } else if ((args[i] == '(') || (args[i] == '[') || (args[i] == '<') || (args[i] == '{')) {
254 subexpressions.push(args[i]); 262 subexpressions.push(args[i]);
@@ -277,7 +285,10 @@ QStringList parse(QString args, char split, bool *ok) @@ -277,7 +285,10 @@ QStringList parse(QString args, char split, bool *ok)
277 return words; 285 return words;
278 } 286 }
279 } else if (subexpressions.isEmpty() && (args[i] == split)) { 287 } else if (subexpressions.isEmpty() && (args[i] == split)) {
280 - words.append(args.mid(start, i-start).trimmed()); 288 + QString word = args.mid(start, i-start).trimmed();
  289 + if (word.contains('\'') || word.contains('\"'))
  290 + word = word.mid(1, word.size()-2);
  291 + words.append(word);
281 start = i+1; 292 start = i+1;
282 } 293 }
283 } 294 }
@@ -512,6 +523,13 @@ QVariantMap fromJsonObject(const QJsonObject &amp;object) @@ -512,6 +523,13 @@ QVariantMap fromJsonObject(const QJsonObject &amp;object)
512 523
513 QVariant fromString(const QString &value) 524 QVariant fromString(const QString &value)
514 { 525 {
  526 + if (value.startsWith('[') && value.endsWith(']')) {
  527 + QVariantList variants;
  528 + foreach (const QString &value, QtUtils::parse(value.mid(1, value.size()-2)))
  529 + variants.append(fromString(value));
  530 + return variants;
  531 + }
  532 +
515 bool ok = false; 533 bool ok = false;
516 const QPointF point = QtUtils::toPoint(value, &ok); 534 const QPointF point = QtUtils::toPoint(value, &ok);
517 if (ok) return point; 535 if (ok) return point;
@@ -523,6 +541,8 @@ QVariant fromString(const QString &amp;value) @@ -523,6 +541,8 @@ QVariant fromString(const QString &amp;value)
523 if (ok) return i; 541 if (ok) return i;
524 const float f = value.toFloat(&ok); 542 const float f = value.toFloat(&ok);
525 if (ok) return f; 543 if (ok) return f;
  544 + const bool b = QtUtils::toBool(value, &ok);
  545 + if (ok) return b;
526 return value; 546 return value;
527 } 547 }
528 548
openbr/core/qtutils.h
@@ -56,7 +56,7 @@ namespace QtUtils @@ -56,7 +56,7 @@ namespace QtUtils
56 QString getAbsolutePath(const QString &filename); 56 QString getAbsolutePath(const QString &filename);
57 57
58 /**** String Utilities ****/ 58 /**** String Utilities ****/
59 - bool toBool(const QString &string); 59 + bool toBool(const QString &string, bool *ok = NULL);
60 int toInt(const QString &string); 60 int toInt(const QString &string);
61 float toFloat(const QString &string); 61 float toFloat(const QString &string);
62 QList<float> toFloats(const QStringList &strings); 62 QList<float> toFloats(const QStringList &strings);
openbr/openbr_plugin.cpp
@@ -156,30 +156,12 @@ QVariant File::value(const QString &amp;key) const @@ -156,30 +156,12 @@ QVariant File::value(const QString &amp;key) const
156 156
157 QVariant File::parse(const QString &value) 157 QVariant File::parse(const QString &value)
158 { 158 {
159 - bool ok = false;  
160 - const QPointF point = QtUtils::toPoint(value, &ok);  
161 - if (ok) return point;  
162 - const QRectF rect = QtUtils::toRect(value, &ok);  
163 - if (ok) return rect;  
164 - const cv::RotatedRect rotatedRect = OpenCVUtils::rotateRectFromString(value, &ok);  
165 - if (ok) return QVariant::fromValue(rotatedRect);  
166 - const int i = value.toInt(&ok);  
167 - if (ok) return i;  
168 - const float f = value.toFloat(&ok);  
169 - if (ok) return f;  
170 - return value; 159 + return QtUtils::fromString(value);
171 } 160 }
172 161
173 void File::set(const QString &key, const QString &value) 162 void File::set(const QString &key, const QString &value)
174 { 163 {
175 - if (value.startsWith('[') && value.endsWith(']')) {  
176 - QVariantList variants;  
177 - foreach (const QString &value, QtUtils::parse(value.mid(1, value.size()-2)))  
178 - variants.append(parse(value));  
179 - set(key, variants);  
180 - } else {  
181 - set(key, QVariant(parse(value)));  
182 - } 164 + set(key, QtUtils::fromString(value));
183 } 165 }
184 166
185 bool File::getBool(const QString &key, bool defaultValue) const 167 bool File::getBool(const QString &key, bool defaultValue) const
openbr/plugins/gallery/csv.cpp
@@ -16,10 +16,101 @@ @@ -16,10 +16,101 @@
16 16
17 #include <openbr/plugins/openbr_internal.h> 17 #include <openbr/plugins/openbr_internal.h>
18 #include <openbr/core/qtutils.h> 18 #include <openbr/core/qtutils.h>
  19 +#include <openbr/core/common.h>
19 20
20 namespace br 21 namespace br
21 { 22 {
22 23
  24 +struct CSVHeader
  25 +{
  26 + QList<int> indices;
  27 +
  28 + CSVHeader()
  29 + {}
  30 +
  31 + CSVHeader(const QString &key)
  32 + : key(key)
  33 + {}
  34 +
  35 + QString key;
  36 + QStringList subKeys;
  37 +};
  38 +
  39 +class CSVHeaderList : public QList<CSVHeader>
  40 +{
  41 +public:
  42 + CSVHeaderList()
  43 + {}
  44 +
  45 + CSVHeaderList(const QList<CSVHeader> &headers)
  46 + {
  47 + foreach (const CSVHeader &header, headers)
  48 + append(header);
  49 + }
  50 +
  51 + CSVHeaderList(const QStringList &keys)
  52 + {
  53 + foreach (const QString &key, keys)
  54 + append(CSVHeader(key));
  55 + }
  56 +
  57 + void sort()
  58 + {
  59 + typedef QPair<QString, int> IndexPair;
  60 + QList<IndexPair> sortedKeys = Common::Sort(keys());
  61 +
  62 + CSVHeaderList sortedList;
  63 + foreach (const IndexPair sortedKey, sortedKeys)
  64 + sortedList.append((*this)[sortedKey.second]);
  65 + *this = sortedList;
  66 + }
  67 +
  68 + QStringList keys() const
  69 + {
  70 + QStringList keys;
  71 + for (int i=0; i<this->size(); i++)
  72 + keys.append((*this)[i].key);
  73 + return keys;
  74 + }
  75 +
  76 + static CSVHeaderList fromHeaders(const QStringList &headers)
  77 + {
  78 + CSVHeaderList csvHeaders;
  79 + QStringList processedKeys;
  80 +
  81 + for (int i=0; i<headers.size(); i++) {
  82 + CSVHeader header;
  83 + if (headers[i].contains("_")) {
  84 + const QStringList subKeys = headers[i].split("_");
  85 + header.key = subKeys.first();
  86 +
  87 + if (processedKeys.contains(header.key))
  88 + continue;
  89 + else
  90 + processedKeys.append(header.key);
  91 +
  92 + header.subKeys.append(subKeys.last());
  93 + header.indices.append(i);
  94 +
  95 + // Look for other subheaders with the same key
  96 + for (int j=i+1; j<headers.size(); j++)
  97 + if (headers[j].contains("_")) {
  98 + const QStringList subKeys = headers[j].split("_");
  99 + if (subKeys.first() == header.key && !header.subKeys.contains(subKeys.last()) /* Check for ill-formed csvs */) {
  100 + header.indices.append(j);
  101 + header.subKeys.append(subKeys.last());
  102 + }
  103 + }
  104 + } else {
  105 + header.key = headers[i];
  106 + header.indices.append(i);
  107 + }
  108 + csvHeaders.append(header);
  109 + }
  110 + return csvHeaders;
  111 + }
  112 +};
  113 +
23 /*! 114 /*!
24 * \ingroup galleries 115 * \ingroup galleries
25 * \brief Treats each line as a file. 116 * \brief Treats each line as a file.
@@ -35,10 +126,12 @@ class csvGallery : public FileGallery @@ -35,10 +126,12 @@ class csvGallery : public FileGallery
35 Q_OBJECT 126 Q_OBJECT
36 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false) 127 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)
37 BR_PROPERTY(bool, inPlace, false) 128 BR_PROPERTY(bool, inPlace, false)
  129 + Q_PROPERTY(bool combineFiles READ get_combineFiles WRITE set_combineFiles RESET reset_combineFiles STORED false)
  130 + BR_PROPERTY(bool, combineFiles, false)
38 131
39 FileList files; 132 FileList files;
40 - QStringList headers;  
41 - 133 + CSVHeaderList headers;
  134 +
42 ~csvGallery() 135 ~csvGallery()
43 { 136 {
44 f.close(); 137 f.close();
@@ -53,9 +146,9 @@ class csvGallery : public FileGallery @@ -53,9 +146,9 @@ class csvGallery : public FileGallery
53 lines.reserve(files.size()+1); 146 lines.reserve(files.size()+1);
54 147
55 // Make header 148 // Make header
56 - headers = samples.values(); 149 + headers = CSVHeaderList(samples.values());
57 headers.sort(); 150 headers.sort();
58 - lines.append(QStringList(QStringList("File") + headers).join(",")); 151 + lines.append(QStringList(QStringList("File") + headers.keys()).join(","));
59 152
60 // Make table 153 // Make table
61 foreach (const File &file, files) 154 foreach (const File &file, files)
@@ -64,6 +157,37 @@ class csvGallery : public FileGallery @@ -64,6 +157,37 @@ class csvGallery : public FileGallery
64 QtUtils::writeFile(file, lines); 157 QtUtils::writeFile(file, lines);
65 } 158 }
66 159
  160 + void setValuesFromHeaders(File &f, const CSVHeaderList &headers, const QVariantList &values)
  161 + {
  162 + foreach (const CSVHeader &header, headers) {
  163 + if (header.indices.size() == 1) {
  164 + if (header.key == "Rects")
  165 + foreach(const QVariant &rect, values[header.indices.first()].toList())
  166 + f.appendRect(rect.toRectF());
  167 + else if (header.key == "Points")
  168 + foreach(const QVariant &point, values[header.indices.first()].toList())
  169 + f.appendPoint(point.toPointF());
  170 + else {
  171 + const QVariant value = values[header.indices.first()];
  172 + if (!value.canConvert<QString>() || !value.toString().isEmpty())
  173 + f.set(header.key, values[header.indices.first()]);
  174 + }
  175 + } else if (header.indices.size() == 2) { // QPointF
  176 + const QPointF point(values[header.indices[header.subKeys.indexOf("X")]].toFloat(),
  177 + values[header.indices[header.subKeys.indexOf("Y")]].toFloat());
  178 + f.set(header.key, point);
  179 + f.appendPoint(point);
  180 + } else if (header.indices.size() == 4) { // QRectF
  181 + const QRectF rect(values[header.indices[header.subKeys.indexOf("X")]].toFloat(),
  182 + values[header.indices[header.subKeys.indexOf("Y")]].toFloat(),
  183 + values[header.indices[header.subKeys.indexOf("Width")]].toFloat(),
  184 + values[header.indices[header.subKeys.indexOf("Height")]].toFloat());
  185 + f.set(header.key, rect);
  186 + f.appendRect(rect);
  187 + }
  188 + }
  189 + }
  190 +
67 TemplateList readBlock(bool *done) 191 TemplateList readBlock(bool *done)
68 { 192 {
69 readOpen(); 193 readOpen();
@@ -79,22 +203,41 @@ class csvGallery : public FileGallery @@ -79,22 +203,41 @@ class csvGallery : public FileGallery
79 QByteArray lineBytes = f.readLine(); 203 QByteArray lineBytes = f.readLine();
80 QString line = QString::fromLocal8Bit(lineBytes).trimmed(); 204 QString line = QString::fromLocal8Bit(lineBytes).trimmed();
81 QRegExp regexp("\\s*,\\s*"); 205 QRegExp regexp("\\s*,\\s*");
82 - headers = line.split(regexp); 206 + headers = CSVHeaderList::fromHeaders(line.split(regexp).mid(1));
83 } 207 }
84 208
85 - for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++) {  
86 - const QVariantList values = parseLine(f.readLine());  
87 - if (values.size() != headers.size()) continue; 209 + if (combineFiles) {
  210 + *done = true;
  211 + QMap<QString, File> combinedFiles;
  212 +
  213 + while (!f.atEnd()) {
  214 + QVariantList values;
  215 + foreach (const QString &value, QtUtils::parse(f.readLine(), ','))
  216 + values.append(QtUtils::fromString(value));
88 217
89 - File in;  
90 - for (int j=0; j<values.size(); j++) {  
91 - if (j == 0) in.name = values[j].toString();  
92 - else in.set(headers[j], values[j].toString());  
93 - }  
94 - in.set("progress", f.pos());  
95 - templates.append(in); 218 + const QString name = values.first().toString();
  219 + File &in = combinedFiles[name];
  220 + in.name = name;
  221 + setValuesFromHeaders(in, headers, values.mid(1));
  222 + }
  223 +
  224 + foreach (const File &in, combinedFiles.values())
  225 + templates.append(in);
  226 + } else {
  227 + for (qint64 i = 0; i < this->readBlockSize && !f.atEnd(); i++) {
  228 + QVariantList values;
  229 + foreach (const QString &value, QtUtils::parse(f.readLine(), ','))
  230 + values.append(QtUtils::fromString(value));
  231 +
  232 + File in;
  233 + in.name = values.first().toString();
  234 + setValuesFromHeaders(in, headers, values.mid(1));
  235 + in.set("progress", f.pos());
  236 + templates.append(in);
  237 + }
  238 + *done = f.atEnd();
96 } 239 }
97 - *done = f.atEnd(); 240 +
98 return templates; 241 return templates;
99 } 242 }
100 243
@@ -104,10 +247,10 @@ class csvGallery : public FileGallery @@ -104,10 +247,10 @@ class csvGallery : public FileGallery
104 writeOpen(); 247 writeOpen();
105 if (headers.isEmpty()) { 248 if (headers.isEmpty()) {
106 foreach (const QString &key, t.file.localKeys()) 249 foreach (const QString &key, t.file.localKeys())
107 - headers.append(key); 250 + headers.append(CSVHeader(key));
108 251
109 headers.sort(); 252 headers.sort();
110 - const QString header = QString(QStringList(QStringList("File") + headers).join(",") + "\n"); 253 + const QString header = QString(QStringList(QStringList("File") + headers.keys()).join(",") + "\n");
111 f.write(header.toLocal8Bit()); 254 f.write(header.toLocal8Bit());
112 } 255 }
113 f.write(QString(lineFromFile(t.file) + "\n").toLocal8Bit()); 256 f.write(QString(lineFromFile(t.file) + "\n").toLocal8Bit());
@@ -119,7 +262,7 @@ class csvGallery : public FileGallery @@ -119,7 +262,7 @@ class csvGallery : public FileGallery
119 { 262 {
120 QStringList words; 263 QStringList words;
121 words.append(file.name); 264 words.append(file.name);
122 - foreach (const QString &key, headers) { 265 + foreach (const QString &key, headers.keys()) {
123 QString value = QtUtils::toString(file.value(key)); 266 QString value = QtUtils::toString(file.value(key));
124 if (value.contains(",")) 267 if (value.contains(","))
125 value = '"' + value + '"'; 268 value = '"' + value + '"';
@@ -127,29 +270,6 @@ class csvGallery : public FileGallery @@ -127,29 +270,6 @@ class csvGallery : public FileGallery
127 } 270 }
128 return words.join(","); 271 return words.join(",");
129 } 272 }
130 -  
131 - static QVariantList parseLine(const QByteArray bytes)  
132 - {  
133 - bool inQuote(false);  
134 - QVariantList values;  
135 - QString value = QString();  
136 - const QString line = QString::fromLocal8Bit(bytes).trimmed();  
137 - for (int i=0; i<line.size(); i++) {  
138 - const QChar c = line[i];  
139 - if (c == '"') {  
140 - inQuote = !inQuote;  
141 - continue;  
142 - } else if (c == ',' && !inQuote) {  
143 - values.append(QVariant(value));  
144 - value = QString();  
145 - } else  
146 - value.append(c);  
147 - }  
148 - if (!value.isEmpty())  
149 - values.append(QVariant(value));  
150 -  
151 - return values;  
152 - }  
153 }; 273 };
154 274
155 BR_REGISTER(Gallery, csvGallery) 275 BR_REGISTER(Gallery, csvGallery)