15 #include "drwnNNGraph.h"
18 using namespace Eigen;
81 namespace drwnNNGraphMoves {
84 template<
class DistanceMetric>
93 template<
class DistanceMetric>
94 void initialize(
drwnNNGraph& graph,
unsigned imgIndx,
const DistanceMetric& M);
98 template<
class DistanceMetric>
99 double rescore(
drwnNNGraph& graph,
const DistanceMetric& M);
107 template<
class DistanceMetric>
108 double rescore(
drwnNNGraph& graph,
unsigned imgIndx,
const DistanceMetric& M);
112 template<
class DistanceMetric>
113 void flann(
drwnNNGraph& graph,
const DistanceMetric& M);
117 template<
class DistanceMetric>
118 void update(
drwnNNGraph& graph,
const DistanceMetric& M);
126 template<
class DistanceMetric>
131 template<
class DistanceMetric>
136 template<
class DistanceMetric>
142 template<
class DistanceMetric>
143 bool randproj(
drwnNNGraph& graph,
const DistanceMetric& M);
147 template<
class DistanceMetric>
148 bool enrichment(
drwnNNGraph& graph,
const DistanceMetric& M);
152 template<
class DistanceMetric>
158 template<
class DistanceMetric>
161 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
162 if (!graph[imgIndx].bSourceMatchable) {
163 DRWN_LOG_DEBUG(
"...skipping initialization of " << graph[imgIndx].name());
171 template<
class DistanceMetric>
175 DRWN_LOG_DEBUG(
"...initializing " << graph[imgIndx].name());
178 #if !(defined(_WIN32)||defined(WIN32)||defined(__WIN32__)||defined(__VISUALC__))
179 unsigned short int xsubi[3] = {0, 0, 0};
184 vector<unsigned> indexes;
186 for (
unsigned i = 0; i < graph.
numImages(); i++) {
187 if (!graph[i].bTargetMatchable)
continue;
189 indexes.push_back(i);
192 bool bLessMatches =
false;
193 const unsigned kMatches = std::min((
unsigned)indexes.size(),
drwnNNGraph::K);
196 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
198 if (!M.isMatchable(graph[imgIndx][segId]))
continue;
201 const bool bHasExistingMatches = !graph[imgIndx][segId].edges.empty();
204 drwn::shuffle(indexes);
205 #elif defined(_WIN32)||defined(WIN32)||defined(__WIN32__)||defined(__VISUALC__)
206 drwn::shuffle(indexes);
210 unsigned int seed = (
unsigned int)erand48(xsubi);
211 const size_t n = indexes.size();
212 for (
size_t i = 0; i < n - 1; i++) {
213 size_t j = rand_r(&seed) % (n - i);
214 std::swap(indexes[i], indexes[i + j]);
218 unsigned matchesAdded = 0;
219 for (
unsigned k = 0; k < indexes.size(); k++) {
222 vector<unsigned> segIndexes;
223 segIndexes.reserve(graph[indexes[k]].numNodes());
224 for (
unsigned i = 0; i < graph[indexes[k]].
numNodes(); i++) {
225 if (M.isFinite(graph[imgIndx][segId], graph[indexes[k]][i])) {
226 segIndexes.push_back(i);
229 if (segIndexes.empty())
continue;
233 #if defined(_WIN32)||defined(WIN32)||defined(__WIN32__)||defined(__VISUALC__)
234 e.
targetNode.
segId = (uint16_t)segIndexes[drand48() * segIndexes.size()];
236 e.
targetNode.
segId = (uint16_t)segIndexes[erand48(xsubi) * segIndexes.size()];
239 graph[imgIndx][segId].edges.push_back(e);
242 if (++matchesAdded >= kMatches)
247 bLessMatches = bLessMatches || (graph[imgIndx][segId].edges.size() < kMatches);
250 if (bHasExistingMatches) {
253 drwnNNGraphEdgeList::iterator kt = graph[imgIndx][segId].edges.begin();
254 drwnNNGraphEdgeList::iterator jt = kt++;
255 while (kt != graph[imgIndx][segId].edges.end()) {
256 if (kt->targetNode.imgIndx == jt->targetNode.imgIndx) {
257 kt = graph[imgIndx][segId].edges.erase(kt);
265 graph[imgIndx][segId].edges.sort();
268 if (bHasExistingMatches) {
269 graph[imgIndx][segId].edges.resize(kMatches);
275 DRWN_LOG_WARNING(
"some nodes in " << graph[imgIndx].name()
282 template<
class DistanceMetric>
288 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
289 energy +=
rescore(graph, imgIndx, M);
296 template<
class DistanceMetric>
301 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
302 drwnNNGraphEdgeList& e = graph[imgIndx][segId].edges;
303 for (drwnNNGraphEdgeList::iterator kt = e.begin(); kt != e.end(); ++kt) {
304 if (M.isFinite(graph[imgIndx][segId], graph[kt->targetNode])) {
305 kt->weight = M.score(graph[imgIndx][segId], graph[kt->targetNode]);
306 energy += kt->weight;
318 template<
class DistanceMetric>
324 const size_t numFeatures = graph[0][0].features.size();
325 vector<drwnNNGraphNodeIndex> sampleIndexes;
326 for (
unsigned i = 0; i < graph.
numImages(); i++) {
327 if (!graph[i].bTargetMatchable)
continue;
330 for (
unsigned j = 0; j < graph[i].
numNodes(); j++) {
335 cv::Mat features(sampleIndexes.size(), numFeatures, CV_32FC1);
336 for (
unsigned i = 0; i < sampleIndexes.size(); i++) {
337 for (
unsigned d = 0; d < numFeatures; d++) {
338 features.at<
float>(i, d) = graph[sampleIndexes[i]].features[d];
343 cv::flann::KDTreeIndexParams indexParams;
344 cv::flann::Index kdtree(features, indexParams);
347 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
348 if (!graph[imgIndx].bSourceMatchable)
continue;
350 const unsigned numQueries = graph[imgIndx].
numNodes();
351 cv::Mat queries(numQueries, numFeatures, CV_32FC1);
352 for (
unsigned i = 0; i < numQueries; i++) {
353 for (
unsigned d = 0; d < numFeatures; d++) {
354 queries.at<
float>(i, d) = graph[imgIndx][i].features[d];
360 kdtree.knnSearch(queries, indexes, dists,
drwnNNGraph::K, cv::flann::SearchParams(64));
363 for (
unsigned i = 0; i < numQueries; i++) {
368 if (!M.isMatchable(graph[v]))
continue;
369 if (M.isFinite(graph[u], graph[v])) {
370 const float w = M.score(graph[u], graph[v]);
380 template<
class DistanceMetric>
388 double totalWeight = 0.0;
389 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
390 if (!graph[imgIndx].bSourceMatchable)
continue;
391 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
392 const drwnNNGraphEdgeList& e = graph[imgIndx][segId].edges;
393 if (e.empty())
continue;
395 totalWeight += (double)e.front().weight;
400 set<drwnNNGraphNodeIndex> sampledNodes;
404 double weight = totalWeight * drand48();
407 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
408 if (!graph[imgIndx].bSourceMatchable)
continue;
409 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
410 const drwnNNGraphEdgeList& e = graph[imgIndx][segId].edges;
411 if (e.empty())
continue;
417 weight -= (double)e.front().weight;
421 totalWeight -= (double)e.front().weight;
425 if (weight <= 0.0)
break;
430 for (set<drwnNNGraphNodeIndex>::const_iterator it = sampledNodes.begin(); it != sampledNodes.end(); ++it) {
445 if (!graph[u.
imgIndx].bSourceMatchable) {
446 DRWN_LOG_DEBUG(
"...skipping " << graph[u.
imgIndx].name());
473 template<
class DistanceMetric>
476 drwnNNGraphEdgeList& el = graph[u].edges;
477 if (el.empty())
return false;
479 bool bChanged =
false;
480 for (drwnNNGraphEdgeList::iterator kt = el.begin(); kt != el.end(); ++kt) {
483 if (kt->status == DRWN_NNG_DIRTY) {
484 kt->status = DRWN_NNG_PROCESSED_ONCE;
485 }
else if (kt->status == DRWN_NNG_PROCESSED_ONCE) {
486 kt->status = DRWN_NNG_PROCESSED_TWICE;
493 for (set<uint16_t>::const_iterator ut = graph[u].spatialNeighbours.begin();
494 ut != graph[u].spatialNeighbours.end(); ++ut) {
497 if (graph[u.
imgIndx][*ut].edges.empty())
continue;
500 for (set<uint16_t>::const_iterator vt = graph[v].spatialNeighbours.begin();
501 vt != graph[v].spatialNeighbours.end(); ++vt) {
508 const float w = M.score(graph[u.
imgIndx][*ut], graph[v.
imgIndx][*vt]);
510 if (graph[u.
imgIndx][*ut].insert(e)) {
520 template<
class DistanceMetric>
524 vector<unsigned> validIndexes;
525 validIndexes.reserve(graph.
numImages() - 1);
526 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
527 if (!graph[imgIndx].bTargetMatchable)
continue;
529 validIndexes.push_back(imgIndx);
533 if (validIndexes.empty())
return false;
537 e.
targetNode.
imgIndx = validIndexes[(unsigned)(drand48() * validIndexes.size())];
540 vector<unsigned> segIndexes;
544 segIndexes.push_back(i);
547 if (segIndexes.empty())
return false;
549 e.
targetNode.
segId = (uint16_t)segIndexes[drand48() * segIndexes.size()];
551 const bool bChanged = graph[u].insert(e);
556 template<
class DistanceMetric>
559 drwnNNGraphEdgeList& el = graph[u].edges;
561 bool bChanged =
false;
562 for (drwnNNGraphEdgeList::iterator kt = el.begin(); kt != el.end(); ++kt) {
563 if (kt->status != DRWN_NNG_DIRTY)
continue;
566 for (set<uint16_t>::const_iterator it = graph[v].spatialNeighbours.begin();
567 it != graph[v].spatialNeighbours.end(); ++it) {
569 if (!M.isFinite(graph[u], graph[v.
imgIndx][*it]))
572 const float w = M.score(graph[u], graph[v.
imgIndx][*it]);
573 if (w < kt->weight) {
575 kt->targetNode.segId = *it;
576 kt->status = DRWN_NNG_DIRTY;
590 template<
class DistanceMetric>
594 bool bChanged =
false;
597 VectorXf mu(graph[0][0].features.size());
598 for (
int i = 0; i < mu.rows(); i++) {
599 mu[i] = float(drand48() - 0.5);
604 vector<pair<float, drwnNNGraphNodeIndex> > projections;
605 projections.reserve(graph.
numNodes());
610 const float x = mu.dot(graph[u].features);
611 projections.push_back(make_pair(x, u));
616 sort(projections.begin(), projections.end());
619 unsigned dbCountChanged = 0;
621 for (
unsigned i = 0; i < projections.size() - 1; i++) {
625 if (!graph[u.
imgIndx].bSourceMatchable || graph[u].edges.empty()) {
626 if (inext <= i) inext += 1;
631 while (inext != projections.size()) {
632 if (graph[projections[inext].second.imgIndx].bTargetMatchable &&
638 if (inext == projections.size())
break;
640 float uworst = sqrt(graph[u].edges.back().weight);
643 if ((projections[j].first - projections[i].first) >= uworst) {
648 if (!graph[projections[j].second.imgIndx].bTargetMatchable)
continue;
655 if (M.isFinite(graph[u], graph[v])) {
656 const float w = M.score(graph[u], graph[v]);
658 uworst = sqrt(graph[u].edges.back().weight);
666 DRWN_LOG_DEBUG(
"randproj() improved " << dbCountChanged <<
" matches");
671 template<
class DistanceMetric>
675 bool bChanged =
false;
678 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
680 if (!graph[imgIndx].bTargetMatchable)
continue;
682 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
683 const drwnNNGraphEdgeList& el = graph[imgIndx][segId].edges;
684 for (drwnNNGraphEdgeList::const_iterator kt = el.begin(); kt != el.end(); ++kt) {
687 if (!graph[kt->targetNode.imgIndx].bSourceMatchable)
692 if (graph[kt->targetNode].insert(e)) {
700 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
702 if (!graph[imgIndx].bSourceMatchable)
continue;
704 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
706 const drwnNNGraphEdgeList el(graph[imgIndx][segId].edges);
709 for (drwnNNGraphEdgeList::const_iterator it = el.begin(); it != el.end(); ++it) {
710 const drwnNNGraphEdgeList& r = graph[it->targetNode].edges;
712 for (drwnNNGraphEdgeList::const_iterator kt = r.begin(); kt != r.end(); ++kt) {
715 if (!graph[kt->targetNode.imgIndx].bTargetMatchable)
continue;
716 if (graph.
inSameEqvClass(kt->targetNode.imgIndx, imgIndx))
continue;
719 if ((it->status == DRWN_NNG_PROCESSED_TWICE) &&
720 (kt->status == DRWN_NNG_PROCESSED_TWICE))
continue;
723 if (!M.isFinite(graph[imgIndx][segId], graph[kt->targetNode]))
726 const float w = M.score(graph[imgIndx][segId], graph[kt->targetNode]);
727 if (graph[imgIndx][segId].insert(
drwnNNGraphEdge(kt->targetNode, w))) {
732 if (nCompared < 0)
break;
735 if (nCompared < 0)
break;
744 template<
class DistanceMetric>
748 drwnNNGraphEdgeList& el = graph[u].edges;
750 bool bChanged =
false;
751 for (
unsigned imgIndx = 0; imgIndx < graph.
numImages(); imgIndx++) {
752 if (!graph[imgIndx].bTargetMatchable)
continue;
756 if (!el.empty()) bestEdge = el.back();
758 for (
unsigned segId = 0; segId < graph[imgIndx].
numNodes(); segId++) {
761 if (!M.isFinite(graph[u], graph[v]))
764 const float w = M.score(graph[u], graph[v]);
765 if (w < bestEdge.
weight) {
770 if (graph[u].insert(bestEdge)) {
static int DO_RANDPROJ
execute random projection move to given horizon
Definition: drwnNNGraph.h:315
bool local(drwnNNGraph &graph, const drwnNNGraphNodeIndex &u, const DistanceMetric &M)
local neighbourhood search around current match for superpixel u (returns true if a better match was ...
Definition: drwnNNGraphMoves.h:557
drwnNNGraphNodeIndex targetNode
index of the target node
Definition: drwnNNGraph.h:84
uint16_t imgIndx
image index for this node
Definition: drwnNNGraph.h:47
uint16_t segId
superpixel identifier this node
Definition: drwnNNGraph.h:48
bool exhaustive(drwnNNGraph &graph, const drwnNNGraphNodeIndex &u, const DistanceMetric &M)
exhaustive search for best match across entire graph — use sparingly (returns true if a better match ...
Definition: drwnNNGraphMoves.h:745
Definition: drwnNNGraph.h:45
Implements the scoring functions needed by the search moves. Required member functions are isMatchabl...
Definition: drwnNNGraphMoves.h:24
bool enrichment(drwnNNGraph &graph, const DistanceMetric &M)
enrichment: inverse (from target to source) and forward (from source to target's target) (returns tru...
Definition: drwnNNGraphMoves.h:672
void reserve(size_t n)
reserve a given number of images (reduced memory allocation)
Definition: drwnNNGraph.h:337
Definition: drwnNNGraphMoves.h:45
bool propagate(drwnNNGraph &graph, const drwnNNGraphNodeIndex &u, const DistanceMetric &M)
propagate good matches from supeprixel u to its neighbours (returns true if a better match was found)...
Definition: drwnNNGraphMoves.h:474
int32_t label
label for this node
Definition: drwnNNGraph.h:133
static bool DO_PROPAGATE
execute propagate move
Definition: drwnNNGraph.h:312
static bool DO_SEARCH
execute random search move
Definition: drwnNNGraph.h:314
bool search(drwnNNGraph &graph, const drwnNNGraphNodeIndex &u, const DistanceMetric &M)
random search across all images for superpixel u (returns true if a better match was found) ...
Definition: drwnNNGraphMoves.h:521
bool randproj(drwnNNGraph &graph, const DistanceMetric &M)
random projection moves that project all superpixels onto a random direction, sort and compare adjace...
Definition: drwnNNGraphMoves.h:591
static unsigned int K
default number of matches per node
Definition: drwnNNGraph.h:311
size_t numNodes() const
number of nodes (superpixels) in the graph
Definition: drwnNNGraph.cpp:814
bool inSameEqvClass(unsigned imgIndxA, unsigned imgIndxB) const
return true if two images are in the same equivalence class
Definition: drwnNNGraph.h:367
Definition: drwnNNGraphMoves.h:67
VectorXf features
features for this node
Definition: drwnNNGraph.h:132
Encapsulates a superpixel node in a drwnNNGraph.
Definition: drwnNNGraph.h:130
Definition: drwnNNGraph.h:114
Definition: drwnNNGraphMoves.h:56
Definition: drwnNNGraph.h:107
size_t numImages() const
number of images in the graph
Definition: drwnNNGraph.h:343
float weight
weight ot score for this edge
Definition: drwnNNGraph.h:85
Encapsulates an outgoing edge in a drwnNNGraph.
Definition: drwnNNGraph.h:82
void update(drwnNNGraph &graph, const DistanceMetric &M)
perform one update iteration (including enrichment and exhaustive) on all active images ...
Definition: drwnNNGraphMoves.h:381
static int DO_EXHAUSTIVE
execute n exhaustive search moves per iteration
Definition: drwnNNGraph.h:317
static bool DO_LOCAL
execute local move
Definition: drwnNNGraph.h:313
double rescore(drwnNNGraph &graph, const DistanceMetric &M)
rescore all matches based on current features (which may have changed since graph was created) ...
Definition: drwnNNGraphMoves.h:283
static bool DO_ENRICHMENT
execute enrichment moves
Definition: drwnNNGraph.h:316
Class for maintaining a nearest neighbour graph over superpixel images. Search moves are implemented ...
Definition: drwnNNGraph.h:309
void flann(drwnNNGraph &graph, const DistanceMetric &M)
update initial edges using FLANN (with possible self-matches in both source and destination matchable...
Definition: drwnNNGraphMoves.h:319
void initialize(drwnNNGraph &graph, const DistanceMetric &M)
randomly initialize edges (matched) for all active images (keeps existing matches unless an improveme...
Definition: drwnNNGraphMoves.h:159
Definition: drwnNNGraphMoves.h:34