Commit 00700cc8c3d19df5ff08045ef1b19bacfbe22b25
Merge pull request #258 from biometrics/stasm_fix
Stasm fix
Showing
2 changed files
with
52 additions
and
48 deletions
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 &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 &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 &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; | ... | ... |