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,10 +166,10 @@ QVariant File::parse(const QString &value)
166 void File::set(const QString &key, const QString &value) 166 void File::set(const QString &key, const QString &value)
167 { 167 {
168 if (value.startsWith('[') && value.endsWith(']')) { 168 if (value.startsWith('[') && value.endsWith(']')) {
169 - QList<QVariant> variants; 169 + QVariantList variants;
170 foreach (const QString &value, QtUtils::parse(value.mid(1, value.size()-2))) 170 foreach (const QString &value, QtUtils::parse(value.mid(1, value.size()-2)))
171 variants.append(parse(value)); 171 variants.append(parse(value));
172 - set(key, QVariant(variants)); 172 + set(key, variants);
173 } else { 173 } else {
174 set(key, QVariant(parse(value))); 174 set(key, QVariant(parse(value)));
175 } 175 }
@@ -806,9 +806,7 @@ void Object::setProperty(const QString &amp;name, QVariant value) @@ -806,9 +806,7 @@ void Object::setProperty(const QString &amp;name, QVariant value)
806 value = v; 806 value = v;
807 } else if ((type.startsWith("QList<") && type.endsWith(">")) || (type == "QStringList") || (type == "QVariantList")) { 807 } else if ((type.startsWith("QList<") && type.endsWith(">")) || (type == "QStringList") || (type == "QVariantList")) {
808 QVariantList elements; 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 foreach (Transform *transform, value.value< QList<Transform*> >()) 810 foreach (Transform *transform, value.value< QList<Transform*> >())
813 elements.append(QVariant::fromValue(transform)); 811 elements.append(QVariant::fromValue(transform));
814 } else if (value.canConvert<QString>()) { 812 } else if (value.canConvert<QString>()) {
@@ -817,6 +815,8 @@ void Object::setProperty(const QString &amp;name, QVariant value) @@ -817,6 +815,8 @@ void Object::setProperty(const QString &amp;name, QVariant value)
817 qFatal("Expected a list to start with '[' and end with 'brackets']'."); 815 qFatal("Expected a list to start with '[' and end with 'brackets']'.");
818 foreach (const QString &element, parse(string.mid(1, string.size()-2))) 816 foreach (const QString &element, parse(string.mid(1, string.size()-2)))
819 elements.append(element); 817 elements.append(element);
  818 + } else if (value.canConvert<QVariantList>()) {
  819 + elements = value.value<QVariantList>();
820 } else { 820 } else {
821 qFatal("Expected a list."); 821 qFatal("Expected a list.");
822 } 822 }
@@ -825,8 +825,19 @@ void Object::setProperty(const QString &amp;name, QVariant value) @@ -825,8 +825,19 @@ void Object::setProperty(const QString &amp;name, QVariant value)
825 value.setValue(elements); 825 value.setValue(elements);
826 } else if ((type == "QList<QString>") || (type == "QStringList")) { 826 } else if ((type == "QList<QString>") || (type == "QStringList")) {
827 QStringList parsedValues; 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 value.setValue(parsedValues); 841 value.setValue(parsedValues);
831 } else if (type == "QList<float>") { 842 } else if (type == "QList<float>") {
832 QList<float> parsedValues; bool ok; 843 QList<float> parsedValues; bool ok;
openbr/plugins/stasm4.cpp
@@ -64,8 +64,10 @@ class StasmTransform : public UntrainableTransform @@ -64,8 +64,10 @@ class StasmTransform : public UntrainableTransform
64 BR_PROPERTY(bool, stasm3Format, false) 64 BR_PROPERTY(bool, stasm3Format, false)
65 Q_PROPERTY(bool clearLandmarks READ get_clearLandmarks WRITE set_clearLandmarks RESET reset_clearLandmarks STORED false) 65 Q_PROPERTY(bool clearLandmarks READ get_clearLandmarks WRITE set_clearLandmarks RESET reset_clearLandmarks STORED false)
66 BR_PROPERTY(bool, clearLandmarks, false) 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 Resource<StasmCascadeClassifier> stasmCascadeResource; 72 Resource<StasmCascadeClassifier> stasmCascadeResource;
71 73
@@ -91,51 +93,42 @@ class StasmTransform : public UntrainableTransform @@ -91,51 +93,42 @@ class StasmTransform : public UntrainableTransform
91 int nLandmarks = stasm_NLANDMARKS; 93 int nLandmarks = stasm_NLANDMARKS;
92 float landmarks[2 * stasm_NLANDMARKS]; 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 if (stasm3Format) { 133 if (stasm3Format) {
141 nLandmarks = 76; 134 nLandmarks = 76;