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 263 debug << QString("|") << QString::number(FAR, 'f', 4).leftJustified(10, ' ');
264 264 debug << QString("|") << QString::number(TP / totalTrueDetections, 'f', 4).leftJustified(10, ' ');
265 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 267 debug << QString("|") << endl;
268 268 break;
269 269 }
... ...
openbr/core/qtutils.cpp
... ... @@ -172,12 +172,20 @@ QString find(const QString &amp;file, const QString &amp;alt)
172 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 191 int toInt(const QString &string)
... ... @@ -245,10 +253,10 @@ QStringList parse(QString args, char split, bool *ok)
245 253 QStack<QChar> subexpressions;
246 254 for (int i=0; i<args.size(); i++) {
247 255 if (inQuote) {
248   - if (args[i] == '\'')
  256 + if (args[i] == '\'' || args[i] == '\"')
249 257 inQuote = false;
250 258 } else {
251   - if (args[i] == '\'') {
  259 + if (args[i] == '\'' || args[i] == '\"') {
252 260 inQuote = true;
253 261 } else if ((args[i] == '(') || (args[i] == '[') || (args[i] == '<') || (args[i] == '{')) {
254 262 subexpressions.push(args[i]);
... ... @@ -277,7 +285,10 @@ QStringList parse(QString args, char split, bool *ok)
277 285 return words;
278 286 }
279 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 292 start = i+1;
282 293 }
283 294 }
... ... @@ -512,6 +523,13 @@ QVariantMap fromJsonObject(const QJsonObject &amp;object)
512 523  
513 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 533 bool ok = false;
516 534 const QPointF point = QtUtils::toPoint(value, &ok);
517 535 if (ok) return point;
... ... @@ -523,6 +541,8 @@ QVariant fromString(const QString &amp;value)
523 541 if (ok) return i;
524 542 const float f = value.toFloat(&ok);
525 543 if (ok) return f;
  544 + const bool b = QtUtils::toBool(value, &ok);
  545 + if (ok) return b;
526 546 return value;
527 547 }
528 548  
... ...
openbr/core/qtutils.h
... ... @@ -56,7 +56,7 @@ namespace QtUtils
56 56 QString getAbsolutePath(const QString &filename);
57 57  
58 58 /**** String Utilities ****/
59   - bool toBool(const QString &string);
  59 + bool toBool(const QString &string, bool *ok = NULL);
60 60 int toInt(const QString &string);
61 61 float toFloat(const QString &string);
62 62 QList<float> toFloats(const QStringList &strings);
... ...
openbr/openbr_plugin.cpp
... ... @@ -156,30 +156,12 @@ QVariant File::value(const QString &amp;key) const
156 156  
157 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 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 167 bool File::getBool(const QString &key, bool defaultValue) const
... ...
openbr/plugins/gallery/csv.cpp
... ... @@ -16,10 +16,101 @@
16 16  
17 17 #include <openbr/plugins/openbr_internal.h>
18 18 #include <openbr/core/qtutils.h>
  19 +#include <openbr/core/common.h>
19 20  
20 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 115 * \ingroup galleries
25 116 * \brief Treats each line as a file.
... ... @@ -35,10 +126,12 @@ class csvGallery : public FileGallery
35 126 Q_OBJECT
36 127 Q_PROPERTY(bool inPlace READ get_inPlace WRITE set_inPlace RESET reset_inPlace STORED false)
37 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 132 FileList files;
40   - QStringList headers;
41   -
  133 + CSVHeaderList headers;
  134 +
42 135 ~csvGallery()
43 136 {
44 137 f.close();
... ... @@ -53,9 +146,9 @@ class csvGallery : public FileGallery
53 146 lines.reserve(files.size()+1);
54 147  
55 148 // Make header
56   - headers = samples.values();
  149 + headers = CSVHeaderList(samples.values());
57 150 headers.sort();
58   - lines.append(QStringList(QStringList("File") + headers).join(","));
  151 + lines.append(QStringList(QStringList("File") + headers.keys()).join(","));
59 152  
60 153 // Make table
61 154 foreach (const File &file, files)
... ... @@ -64,6 +157,37 @@ class csvGallery : public FileGallery
64 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 191 TemplateList readBlock(bool *done)
68 192 {
69 193 readOpen();
... ... @@ -79,22 +203,41 @@ class csvGallery : public FileGallery
79 203 QByteArray lineBytes = f.readLine();
80 204 QString line = QString::fromLocal8Bit(lineBytes).trimmed();
81 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 241 return templates;
99 242 }
100 243  
... ... @@ -104,10 +247,10 @@ class csvGallery : public FileGallery
104 247 writeOpen();
105 248 if (headers.isEmpty()) {
106 249 foreach (const QString &key, t.file.localKeys())
107   - headers.append(key);
  250 + headers.append(CSVHeader(key));
108 251  
109 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 254 f.write(header.toLocal8Bit());
112 255 }
113 256 f.write(QString(lineFromFile(t.file) + "\n").toLocal8Bit());
... ... @@ -119,7 +262,7 @@ class csvGallery : public FileGallery
119 262 {
120 263 QStringList words;
121 264 words.append(file.name);
122   - foreach (const QString &key, headers) {
  265 + foreach (const QString &key, headers.keys()) {
123 266 QString value = QtUtils::toString(file.value(key));
124 267 if (value.contains(","))
125 268 value = '"' + value + '"';
... ... @@ -127,29 +270,6 @@ class csvGallery : public FileGallery
127 270 }
128 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 275 BR_REGISTER(Gallery, csvGallery)
... ...