Commit 16f41d0221a1028627eda7c367a87fea0c2222c7
1 parent
897b65bd
remove synthesizekeypoints
Showing
1 changed file
with
0 additions
and
245 deletions
openbr/plugins/imgproc/synthesizekeypoints.cpp deleted
| 1 | -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * | |
| 2 | - * Copyright 2015 Noblis * | |
| 3 | - * * | |
| 4 | - * Licensed under the Apache License, Version 2.0 (the "License"); * | |
| 5 | - * you may not use this file except in compliance with the License. * | |
| 6 | - * You may obtain a copy of the License at * | |
| 7 | - * * | |
| 8 | - * http://www.apache.org/licenses/LICENSE-2.0 * | |
| 9 | - * * | |
| 10 | - * Unless required by applicable law or agreed to in writing, software * | |
| 11 | - * distributed under the License is distributed on an "AS IS" BASIS, * | |
| 12 | - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * | |
| 13 | - * See the License for the specific language governing permissions and * | |
| 14 | - * limitations under the License. * | |
| 15 | - * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ | |
| 16 | - | |
| 17 | -#include <opencv2/imgproc/imgproc.hpp> | |
| 18 | -#include "openbr/plugins/openbr_internal.h" | |
| 19 | -#include "openbr/core/qtutils.h" | |
| 20 | -#include "openbr/core/opencvutils.h" | |
| 21 | -#include "openbr/core/eigenutils.h" | |
| 22 | -#include "openbr/core/common.h" | |
| 23 | -#include <QString> | |
| 24 | -#include <Eigen/SVD> | |
| 25 | -#include <Eigen/Dense> | |
| 26 | - | |
| 27 | -using namespace std; | |
| 28 | -using namespace cv; | |
| 29 | -using namespace Eigen; | |
| 30 | - | |
| 31 | -namespace br | |
| 32 | -{ | |
| 33 | - | |
| 34 | -// SynthesizePointsTransform helper class | |
| 35 | -struct TriangleIndicies | |
| 36 | -{ | |
| 37 | - int indicies[3]; | |
| 38 | - | |
| 39 | - TriangleIndicies() | |
| 40 | - { | |
| 41 | - indicies[0] = 0; | |
| 42 | - indicies[1] = 0; | |
| 43 | - indicies[2] = 0; | |
| 44 | - } | |
| 45 | - | |
| 46 | - TriangleIndicies(QList<int> indexList) | |
| 47 | - { | |
| 48 | - assert(indexList.size() == 3); | |
| 49 | - qSort(indexList); | |
| 50 | - indicies[0] = indexList[0]; | |
| 51 | - indicies[1] = indexList[1]; | |
| 52 | - indicies[2] = indexList[2]; | |
| 53 | - } | |
| 54 | -}; | |
| 55 | - | |
| 56 | -inline bool operator==(const TriangleIndicies &a, const TriangleIndicies &b) | |
| 57 | -{ | |
| 58 | - return (a.indicies[0] == b.indicies[0]) && (a.indicies[1] == b.indicies[1]) && (a.indicies[2] == b.indicies[2]); | |
| 59 | -} | |
| 60 | - | |
| 61 | -inline uint qHash(const TriangleIndicies &key) | |
| 62 | -{ | |
| 63 | - return ::qHash(key.indicies[0]) ^ ::qHash(key.indicies[1]) ^ ::qHash(key.indicies[2]); | |
| 64 | -} | |
| 65 | - | |
| 66 | -QDataStream &operator<<(QDataStream &stream, const TriangleIndicies &ti) | |
| 67 | -{ | |
| 68 | - return stream << ti.indicies[0] << ti.indicies[1] << ti.indicies[2]; | |
| 69 | -} | |
| 70 | - | |
| 71 | -QDataStream &operator>>(QDataStream &stream, TriangleIndicies &ti) | |
| 72 | -{ | |
| 73 | - return stream >> ti.indicies[0] >> ti.indicies[1] >> ti.indicies[2]; | |
| 74 | -} | |
| 75 | - | |
| 76 | -/*! | |
| 77 | - * \ingroup transforms | |
| 78 | - * \brief Synthesize additional points via triangulation. | |
| 79 | - * \author Josh Klontz \cite jklontz | |
| 80 | - */ | |
| 81 | -class SynthesizePointsTransform : public MetadataTransform | |
| 82 | -{ | |
| 83 | - Q_OBJECT | |
| 84 | - Q_PROPERTY(float minRelativeDistance READ get_minRelativeDistance WRITE set_minRelativeDistance RESET reset_minRelativeDistance STORED false) | |
| 85 | - BR_PROPERTY(float, minRelativeDistance, 0) // [0, 1] range controlling whether or not to nearby synthetic points. | |
| 86 | - // 0 = keep all points, 1 = keep only the most distance point. | |
| 87 | - | |
| 88 | - QList<TriangleIndicies> triangles; | |
| 89 | - | |
| 90 | - static QRectF getBounds(const QList<QPointF> &points, int dstPadding) | |
| 91 | - { | |
| 92 | - float srcMinX = FLT_MAX; | |
| 93 | - float srcMinY = FLT_MAX; | |
| 94 | - float srcMaxX = -FLT_MAX; | |
| 95 | - float srcMaxY = -FLT_MAX; | |
| 96 | - foreach (const QPointF &point, points) { | |
| 97 | - if (point.x() < srcMinX) srcMinX = point.x(); | |
| 98 | - if (point.y() < srcMinY) srcMinY = point.y(); | |
| 99 | - if (point.x() > srcMaxX) srcMaxX = point.x(); | |
| 100 | - if (point.y() > srcMaxY) srcMaxY = point.y(); | |
| 101 | - } | |
| 102 | - | |
| 103 | - const float padding = (srcMaxX - srcMinX) / 80 * dstPadding; | |
| 104 | - return QRectF(qRound(srcMinX - padding), qRound(srcMinY - padding), qRound(srcMaxX - srcMinX + 2 * padding), qRound(srcMaxY - srcMinY + 2 * padding)); | |
| 105 | - } | |
| 106 | - | |
| 107 | - static int getVertexIndex(const QPointF &trianglePts, const QList<QPointF> &pts) | |
| 108 | - { | |
| 109 | - for (int i = 0; i < pts.size(); i++) | |
| 110 | - // Check points using single precision accuracy to avoid potential rounding error | |
| 111 | - if ((float(trianglePts.x()) == float(pts[i].x())) && (float(trianglePts.y()) == float(pts[i].y()))) | |
| 112 | - return i; | |
| 113 | - qFatal("Couldn't identify index of requested point!"); | |
| 114 | - return -1; | |
| 115 | - } | |
| 116 | - | |
| 117 | - static QList<QList<int> > getTriangulation(const QList<QPointF> &points, const QRectF &bound) | |
| 118 | - { | |
| 119 | - Subdiv2D subdiv(OpenCVUtils::toRect(bound)); | |
| 120 | - foreach (const QPointF &point, points) { | |
| 121 | - if (!bound.contains(point)) | |
| 122 | - return QList<QList<int> >(); | |
| 123 | - subdiv.insert(OpenCVUtils::toPoint(point)); | |
| 124 | - } | |
| 125 | - | |
| 126 | - | |
| 127 | - vector<Vec6f> triangleList; | |
| 128 | - subdiv.getTriangleList(triangleList); | |
| 129 | - | |
| 130 | - QList<QList<int> > triangleIndices; | |
| 131 | - foreach (const Vec6f &triangle, triangleList) { | |
| 132 | - bool valid = true; | |
| 133 | - const QPointF vertices[3] = { QPointF(triangle[0], triangle[1]), | |
| 134 | - QPointF(triangle[2], triangle[3]), | |
| 135 | - QPointF(triangle[4], triangle[5]) }; | |
| 136 | - for (int j = 0; j < 3; j++) | |
| 137 | - if (vertices[j].x() > bound.right() || vertices[j].y() > bound.bottom() || vertices[j].x() < bound.left() || vertices[j].y() < bound.top()) { | |
| 138 | - valid = false; | |
| 139 | - break; | |
| 140 | - } | |
| 141 | - | |
| 142 | - if (valid) { | |
| 143 | - QList<int> tri; | |
| 144 | - for (int j = 0; j < 3; j++) | |
| 145 | - tri.append(getVertexIndex(vertices[j], points)); | |
| 146 | - triangleIndices.append(tri); | |
| 147 | - } | |
| 148 | - } | |
| 149 | - | |
| 150 | - return triangleIndices; | |
| 151 | - } | |
| 152 | - | |
| 153 | - void train(const TemplateList &data) | |
| 154 | - { | |
| 155 | - // Because not all triangulations are the same, we have to decide on a canonical set of triangles at training time. | |
| 156 | - QHash<TriangleIndicies, int> counts; | |
| 157 | - foreach (const Template &datum, data) { | |
| 158 | - const QList<QPointF> points = datum.file.points(); | |
| 159 | - if (points.size() <= 4) | |
| 160 | - continue; | |
| 161 | - | |
| 162 | - const QList< QList<int> > triangulation = getTriangulation(points, getBounds(points, 10)); | |
| 163 | - if (triangulation.empty()) | |
| 164 | - continue; | |
| 165 | - | |
| 166 | - foreach (const QList<int> &indicies, triangulation) | |
| 167 | - counts[TriangleIndicies(indicies)]++; | |
| 168 | - } | |
| 169 | - | |
| 170 | - if (counts.empty()) | |
| 171 | - return; | |
| 172 | - | |
| 173 | - triangles.clear(); | |
| 174 | - QHash<TriangleIndicies, int>::const_iterator i = counts.constBegin(); | |
| 175 | - while (i != counts.constEnd()) { | |
| 176 | - if (3 * i.value() > data.size()) | |
| 177 | - triangles.append(i.key()); // Keep triangles that occur in at least a third of the training instances | |
| 178 | - ++i; | |
| 179 | - } | |
| 180 | - | |
| 181 | - if (minRelativeDistance > 0) { // Discard relatively small triangles | |
| 182 | - QVector<float> averageMinDistances(triangles.size()); | |
| 183 | - foreach (const Template &datum, data) { | |
| 184 | - File dst; | |
| 185 | - projectMetadata(datum.file, dst); | |
| 186 | - const QList<QPointF> points = dst.points(); | |
| 187 | - | |
| 188 | - QVector<float> minDistances(triangles.size()); | |
| 189 | - for (int i=0; i<triangles.size(); i++) { | |
| 190 | - // Work backwards so that we can also consider distances between synthetic points | |
| 191 | - const QPointF &point = points[points.size()-1-i]; | |
| 192 | - float minDistance = std::numeric_limits<float>::max(); | |
| 193 | - for (int j=0; j<points.size()-1-i; j++) | |
| 194 | - minDistance = min(minDistance, sqrtf(powf(point.x() - points[j].x(), 2.f) + powf(point.y() - points[j].y(), 2.f))); | |
| 195 | - minDistances[triangles.size()-1-i] = minDistance; | |
| 196 | - } | |
| 197 | - | |
| 198 | - const float maxMinDistance = Common::Max(minDistances); | |
| 199 | - for (int i=0; i<minDistances.size(); i++) | |
| 200 | - averageMinDistances[i] += (minDistances[i] / maxMinDistance); | |
| 201 | - } | |
| 202 | - | |
| 203 | - const float maxAverageMinDistance = Common::Max(averageMinDistances); | |
| 204 | - for (int i=averageMinDistances.size()-1; i>=0; i--) | |
| 205 | - if (averageMinDistances[i] / maxAverageMinDistance < minRelativeDistance) | |
| 206 | - triangles.removeAt(i); | |
| 207 | - } | |
| 208 | - | |
| 209 | - if (Globals->verbose) | |
| 210 | - qDebug() << "Kept" << triangles.size() << "of" << counts.size() << "triangles."; | |
| 211 | - } | |
| 212 | - | |
| 213 | - void projectMetadata(const File &src, File &dst) const | |
| 214 | - { | |
| 215 | - QList<QPointF> points = src.points(); | |
| 216 | - if (points.size() == 0) { | |
| 217 | - dst.fte = true; | |
| 218 | - return; | |
| 219 | - } | |
| 220 | - | |
| 221 | - foreach (const TriangleIndicies &triangle, triangles) { | |
| 222 | - const QPointF &p0 = points[triangle.indicies[0]]; | |
| 223 | - const QPointF &p1 = points[triangle.indicies[1]]; | |
| 224 | - const QPointF &p2 = points[triangle.indicies[2]]; | |
| 225 | - points.append((p0 + p1 + p2) / 3 /* append the centroid of the triangle */); | |
| 226 | - } | |
| 227 | - dst.setPoints(points); | |
| 228 | - } | |
| 229 | - | |
| 230 | - void store(QDataStream &stream) const | |
| 231 | - { | |
| 232 | - stream << triangles; | |
| 233 | - } | |
| 234 | - | |
| 235 | - void load(QDataStream &stream) | |
| 236 | - { | |
| 237 | - stream >> triangles; | |
| 238 | - } | |
| 239 | -}; | |
| 240 | - | |
| 241 | -BR_REGISTER(Transform, SynthesizePointsTransform) | |
| 242 | - | |
| 243 | -} // namespace br | |
| 244 | - | |
| 245 | -#include "synthesizekeypoints.moc" |