Commit 8deca4539b6e05672fd858a3aa5a6a7d5b5c4fb4

Authored by JordanCheney
2 parents 9f6444f8 168a384b

Merge pull request #387 from biometrics/RODClustering

Online Rank-Order distance clustering
openbr/plugins/cluster/onlinerod.cpp 0 → 100644
  1 +#include <openbr/plugins/openbr_internal.h>
  2 +#include <openbr/core/cluster.h>
  3 +#include <openbr/core/opencvutils.h>
  4 +
  5 +using namespace cv;
  6 +
  7 +namespace br
  8 +{
  9 +
  10 +/*!
  11 + * \brief Constructors clusters based on the Rank-Order distance in an online, incremental manner
  12 + * \author Charles Otto \cite caotto
  13 + * \author Jordan Cheney \cite JordanCheney
  14 + * \br_property br::Distance* distance Distance to compute the similarity score between templates. Default is L2.
  15 + * \br_property int kNN Maximum number of nearest neighbors to keep for each template. Default is 20.
  16 + * \br_property float aggression Clustering aggresiveness. A higher value will result in larger clusters. Default is 10.
  17 + * \br_property bool incremental If true, compute the clusters as each template is processed otherwise compute the templates at the end. Default is false.
  18 + * \br_property QString evalOutput Path to store cluster informtation. Optional. Default is an empty string.
  19 + * \br_paper Zhu et al.
  20 + * "A Rank-Order Distance based Clustering Algorithm for Face Tagging"
  21 + * CVPR 2011
  22 + */
  23 +class OnlineRODTransform : public TimeVaryingTransform
  24 +{
  25 + Q_OBJECT
  26 + Q_PROPERTY(br::Distance *distance READ get_distance WRITE set_distance RESET reset_distance STORED true)
  27 + Q_PROPERTY(int kNN READ get_kNN WRITE set_kNN RESET reset_kNN STORED false)
  28 + Q_PROPERTY(float aggression READ get_aggression WRITE set_aggression RESET reset_aggression STORED false)
  29 + Q_PROPERTY(bool incremental READ get_incremental WRITE set_incremental RESET reset_incremental STORED false)
  30 + Q_PROPERTY(QString evalOutput READ get_evalOutput WRITE set_evalOutput RESET reset_evalOutput STORED false)
  31 +
  32 + BR_PROPERTY(br::Distance*, distance, Distance::make(".Dist(L2)",this))
  33 + BR_PROPERTY(int, kNN, 20)
  34 + BR_PROPERTY(float, aggression, 10)
  35 + BR_PROPERTY(bool, incremental, false)
  36 + BR_PROPERTY(QString, evalOutput, "")
  37 +
  38 + TemplateList templates;
  39 + Neighborhood neighborhood;
  40 +
  41 +public:
  42 + OnlineRODTransform() : TimeVaryingTransform(false, false) {}
  43 +
  44 +private:
  45 + void projectUpdate(const TemplateList &src, TemplateList &dst)
  46 + {
  47 + // update current graph
  48 + foreach(const Template &t, src) {
  49 + QList<float> scores = distance->compare(templates, t);
  50 +
  51 + // attempt to udpate each existing point's (sorted) k-NN list with these results.
  52 + Neighbors currentN;
  53 + for (int i=0; i < scores.size(); i++) {
  54 + currentN.append(Neighbor(i, scores[i]));
  55 + Neighbors target = neighborhood[i];
  56 +
  57 + // should we insert the new neighbor into the current target's list?
  58 + if (target.size() < kNN || scores[i] > target.last().second) {
  59 + // insert into the sorted nearest neighbor list
  60 + Neighbor temp(scores.size(), scores[i]);
  61 + br::Neighbors::iterator res = qLowerBound(target.begin(), target.end(), temp, compareNeighbors);
  62 + target.insert(res, temp);
  63 +
  64 + if (target.size() > kNN)
  65 + target.removeLast();
  66 +
  67 + neighborhood[i] = target;
  68 + }
  69 + }
  70 +
  71 + // add a new row, consisting of the top neighbors of the newest point
  72 + int actuallyKeep = std::min(kNN, currentN.size());
  73 + std::partial_sort(currentN.begin(), currentN.begin()+actuallyKeep, currentN.end(), compareNeighbors);
  74 +
  75 + Neighbors selected = currentN.mid(0, actuallyKeep);
  76 + neighborhood.append(selected);
  77 + templates.append(t);
  78 + }
  79 +
  80 + if (incremental)
  81 + identifyClusters(dst);
  82 + }
  83 +
  84 + void finalize(TemplateList &output)
  85 + {
  86 + if (!templates.empty()) {
  87 + identifyClusters(output);
  88 + templates.clear();
  89 + neighborhood.clear();
  90 + }
  91 + }
  92 +
  93 + void identifyClusters(TemplateList &dst)
  94 + {
  95 + Clusters clusters = ClusterGraph(neighborhood, aggression, evalOutput);
  96 + if (Globals->verbose)
  97 + qDebug("Built %d clusters from %d templates", clusters.size(), templates.size());
  98 +
  99 + for (int i = 0; i < clusters.size(); i++) {
  100 + // Calculate the centroid of each cluster
  101 + Mat center = Mat::zeros(templates[0].m().rows, templates[0].m().cols, CV_32F);
  102 + foreach (int t, clusters[i]) {
  103 + Mat converted; templates[t].m().convertTo(converted, CV_32F);
  104 + center += converted;
  105 + }
  106 + center /= clusters[i].size();
  107 +
  108 + // Calculate the Euclidean distance from the center to use as the cluster confidence
  109 + foreach (int t, clusters[i]) {
  110 + templates[t].file.set("Cluster", i);
  111 + Mat c; templates[t].m().convertTo(c, CV_32F);
  112 + Mat p; pow(c - center, 2, p);
  113 + templates[t].file.set("ClusterConfidence", sqrt(sum(p)[0]));
  114 + }
  115 + }
  116 + dst.append(templates);
  117 + }
  118 +};
  119 +
  120 +BR_REGISTER(Transform, OnlineRODTransform)
  121 +
  122 +} // namespace br
  123 +
  124 +#include "onlinerod.moc"
  125 +
... ...