Commit 00700cc8c3d19df5ff08045ef1b19bacfbe22b25

Authored by Josh Klontz
2 parents 9a608d69 f3692eaa

Merge pull request #258 from biometrics/stasm_fix

Stasm fix
openbr/openbr_plugin.cpp
... ... @@ -166,10 +166,10 @@ QVariant File::parse(const QString &value)
166 166 void File::set(const QString &key, const QString &value)
167 167 {
168 168 if (value.startsWith('[') && value.endsWith(']')) {
169   - QList<QVariant> variants;
  169 + QVariantList variants;
170 170 foreach (const QString &value, QtUtils::parse(value.mid(1, value.size()-2)))
171 171 variants.append(parse(value));
172   - set(key, QVariant(variants));
  172 + set(key, variants);
173 173 } else {
174 174 set(key, QVariant(parse(value)));
175 175 }
... ... @@ -806,9 +806,7 @@ void Object::setProperty(const QString &amp;name, QVariant value)
806 806 value = v;
807 807 } else if ((type.startsWith("QList<") && type.endsWith(">")) || (type == "QStringList") || (type == "QVariantList")) {
808 808 QVariantList elements;
809   - if (value.canConvert<QVariantList>()) {
810   - elements = value.value<QVariantList>();
811   - } else if (value.canConvert< QList<Transform*> >()) {
  809 + if (value.canConvert< QList<Transform*> >()) {
812 810 foreach (Transform *transform, value.value< QList<Transform*> >())
813 811 elements.append(QVariant::fromValue(transform));
814 812 } else if (value.canConvert<QString>()) {
... ... @@ -817,6 +815,8 @@ void Object::setProperty(const QString &amp;name, QVariant value)
817 815 qFatal("Expected a list to start with '[' and end with 'brackets']'.");
818 816 foreach (const QString &element, parse(string.mid(1, string.size()-2)))
819 817 elements.append(element);
  818 + } else if (value.canConvert<QVariantList>()) {
  819 + elements = value.value<QVariantList>();
820 820 } else {
821 821 qFatal("Expected a list.");
822 822 }
... ... @@ -825,8 +825,19 @@ void Object::setProperty(const QString &amp;name, QVariant value)
825 825 value.setValue(elements);
826 826 } else if ((type == "QList<QString>") || (type == "QStringList")) {
827 827 QStringList parsedValues;
828   - foreach (const QVariant &element, elements)
829   - parsedValues.append(element.toString());
  828 + foreach (const QVariant &element, elements) {
  829 + if (element.canConvert<QString>()) {
  830 + parsedValues.append(element.toString());
  831 + } else if (element.canConvert<QPointF>()) {
  832 + const QPointF point = element.toPointF();
  833 + parsedValues.push_back(QString("(%1,%2)").arg(QString::number(point.x()), QString::number(point.y())));
  834 + } else if (element.canConvert<QRectF>()) {
  835 + const QRectF rect = element.toRectF();
  836 + parsedValues.push_back(QString("(%1,%2,%3,%4)").arg(QString::number(rect.x()), QString::number(rect.y()), QString::number(rect.width()), QString::number(rect.height())));
  837 + } else {
  838 + qFatal("Can't convert variant to string.");
  839 + }
  840 + }
830 841 value.setValue(parsedValues);
831 842 } else if (type == "QList<float>") {
832 843 QList<float> parsedValues; bool ok;
... ...
openbr/plugins/stasm4.cpp
... ... @@ -64,8 +64,10 @@ class StasmTransform : public UntrainableTransform
64 64 BR_PROPERTY(bool, stasm3Format, false)
65 65 Q_PROPERTY(bool clearLandmarks READ get_clearLandmarks WRITE set_clearLandmarks RESET reset_clearLandmarks STORED false)
66 66 BR_PROPERTY(bool, clearLandmarks, false)
67   - Q_PROPERTY(QVariantList pinEyes READ get_pinEyes WRITE set_pinEyes RESET reset_pinEyes STORED false)
68   - BR_PROPERTY(QVariantList, pinEyes, QVariantList())
  67 + Q_PROPERTY(QList<float> pinPoints READ get_pinPoints WRITE set_pinPoints RESET reset_pinPoints STORED false)
  68 + BR_PROPERTY(QList<float>, pinPoints, QList<float>())
  69 + Q_PROPERTY(QStringList pinLabels READ get_pinLabels WRITE set_pinLabels RESET reset_pinLabels STORED false)
  70 + BR_PROPERTY(QStringList, pinLabels, QStringList())
69 71  
70 72 Resource<StasmCascadeClassifier> stasmCascadeResource;
71 73  
... ... @@ -91,51 +93,42 @@ class StasmTransform : public UntrainableTransform
91 93 int nLandmarks = stasm_NLANDMARKS;
92 94 float landmarks[2 * stasm_NLANDMARKS];
93 95  
94   - if (!pinEyes.isEmpty()) {
95   - // Two use cases are accounted for:
96   - // 1. Pin eyes without normalization: in this case the string list should contain the KEYS for right then left eyes, respectively.
97   - // 2. Pin eyes with normalization: in this case the string list should contain the COORDINATES of the right then left eyes, respectively.
98   - // If both cases fail, we default to stasm_search_single.
99   -
100   - bool ok = false;
101   - QPointF rightEye;
102   - QPointF leftEye;
103   -
104   - QString r = pinEyes.at(0).toString();
105   - QString l = pinEyes.at(1).toString();
106   -
107   - if (src.file.contains("Affine_0") && src.file.contains("Affine_1")) {
108   - rightEye = QtUtils::toPoint(r);
109   - leftEye = QtUtils::toPoint(l);
110   - if (!rightEye.isNull() && !leftEye.isNull())
111   - ok = true;
112   - }
  96 + bool searchPinned = false;
  97 +
  98 + QPointF rightEye, leftEye;
  99 + /* Two use cases are accounted for:
  100 + * 1. Pin eyes without normalization: in this case the string list should contain the KEYS for right then left eyes, respectively.
  101 + * 2. Pin eyes with normalization: in this case the string list should contain the COORDINATES of the right then left eyes, respectively.
  102 + * Currently, we only support normalization with a transformation such that the src file contains Affine_0 and Affine_1. Checking for
  103 + * these keys prevents us from pinning eyes on a face that wasn't actually transformed (see AffineTransform).
  104 + * If both cases fail, we default to stasm_search_single. */
  105 +
  106 + if (!pinPoints.isEmpty() && src.file.contains("Affine_0") && src.file.contains("Affine_1")) {
  107 + rightEye = QPointF(pinPoints.at(0), pinPoints.at(1));
  108 + leftEye = QPointF(pinPoints.at(2), pinPoints.at(3));
  109 + searchPinned = true;
  110 + } else if (!pinLabels.isEmpty()) {
  111 + rightEye = src.file.get<QPointF>(pinLabels.at(0), QPointF());
  112 + leftEye = src.file.get<QPointF>(pinLabels.at(1), QPointF());
  113 + searchPinned = true;
  114 + }
  115 +
  116 + if (searchPinned) {
  117 + float pins[2 * stasm_NLANDMARKS];
113 118  
114   - if (!ok) {
115   - if (!r.isNull() && !l.isNull() && src.file.contains(r) && src.file.contains(l))
116   - {
117   - rightEye = src.file.get<QPointF>(r, QPointF());
118   - leftEye = src.file.get<QPointF>(l, QPointF());
119   - ok = true;
120   - }
  119 + for (int i = 0; i < nLandmarks; i++) {
  120 + if (i == 38) /*Stasm Right Eye*/ { pins[2*i] = rightEye.x(); pins[2*i+1] = rightEye.y(); }
  121 + else if (i == 39) /*Stasm Left Eye*/ { pins[2*i] = leftEye.x(); pins[2*i+1] = leftEye.y(); }
  122 + else { pins[2*i] = 0; pins[2*i+1] = 0; }
121 123 }
122 124  
123   - float eyes[2 * stasm_NLANDMARKS];
  125 + stasm_search_pinned(landmarks, pins, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, NULL);
124 126  
125   - if (ok) {
126   - for (int i = 0; i < nLandmarks; i++) {
127   - if (i == 38) /*Stasm Right Eye*/ { eyes[2*i] = rightEye.x(); eyes[2*i+1] = rightEye.y(); }
128   - else if (i == 39) /*Stasm Left Eye*/ { eyes[2*i] = leftEye.x(); eyes[2*i+1] = leftEye.y(); }
129   - else { eyes[2*i] = 0; eyes[2*i+1] = 0; }
130   - }
131   - stasm_search_pinned(landmarks, eyes, reinterpret_cast<const char*>(src.m().data), src.m().cols, src.m().rows, NULL);
132   -
133   - // The ASM in Stasm is guaranteed to converge in this case
134   - foundFace = 1;
135   - }
  127 + // The ASM in Stasm is guaranteed to converge in this case
  128 + foundFace = 1;
136 129 }
137 130  
138   - if (!foundFace) stasm_search_single(&foundFace, landmarks, reinterpret_cast<const char*>(src.m().data), src.m().cols, src.m().rows, *stasmCascade, NULL, NULL);
  131 + if (!foundFace) stasm_search_single(&foundFace, landmarks, reinterpret_cast<const char*>(stasmSrc.data), stasmSrc.cols, stasmSrc.rows, *stasmCascade, NULL, NULL);
139 132  
140 133 if (stasm3Format) {
141 134 nLandmarks = 76;
... ...