void PathEvaluator::test_filtering() { /// Export results: QString sessionName = QString("session_%1").arg(QDateTime::currentDateTime().toString("dd.MM.yyyy_hh.mm.ss")); QString path = "results/" + sessionName; QDir d(""); d.mkpath( path ); d.mkpath( path + "/images" ); int timeLimit = 5000; // ms int numInBetweens = 8; int numSamplesPerPath = numInBetweens * 3; /// Get number of paths to evaluate: int numPaths = 0; { Scheduler defaultSchedule( *b->m_scheduler ); // Find time it takes for a single path QElapsedTimer timer; timer.start(); { defaultSchedule.setSchedule( b->m_scheduler->getSchedule() ); // default defaultSchedule.timeStep = 1.0 / numSamplesPerPath; defaultSchedule.executeAll(); } // FIXME // numPaths = qMax(1.0, double(timeLimit) / timer.elapsed() * omp_get_num_threads()); numPaths = qMax(1.0, double(timeLimit) / timer.elapsed() * 4); // Export source and target images QColor inputColor(255,255,255); b->renderer->quickRender(defaultSchedule.allGraphs.front(), inputColor).save(path + "/images/source.png"); b->renderer->quickRender(defaultSchedule.allGraphs.back(), inputColor).save(path + "/images/target.png"); } // Force number of paths numPaths = 30; // Do this once for input graphs QVector<Structure::Graph*> inputGraphs; inputGraphs << b->s->inputGraphs[0]->g << b->s->inputGraphs[1]->g; ScorerManager r_manager(b->m_gcorr, b->m_scheduler.data(), inputGraphs); r_manager.parseConstraintPair(); r_manager.parseConstraintGroup(); r_manager.parseGlobalReflectionSymm(); QVector<ScorerManager::PathScore> ps( numPaths ); MatrixXd allRanges( numPaths, 3 * 4 ); QVector<ScheduleType> allPaths = b->m_scheduler->manyRandomSchedules( numPaths ); QElapsedTimer evalTimer; evalTimer.start(); //#pragma omp parallel for for(int i = 0; i < allPaths.size(); i++) { // Setup schedule Scheduler s( *b->m_scheduler ); s.setSchedule( allPaths[i] ); s.timeStep = 1.0 / numSamplesPerPath; // Execute blend s.executeAll(); // Compute its score ps[i] = r_manager.pathScore( s.allGraphs ); QVector<QColor> colors; colors.push_back(QColor(255,0,0)); colors.push_back(QColor(0,255,0)); colors.push_back(QColor(0,0,255)); // Range of values MatrixXd ranges = ps[i].computeRange(); allRanges.row(i) = VectorXd::Map(ranges.data(), ranges.rows()*ranges.cols()); //#pragma omp critical { QImage img(QSize(600,130), QImage::Format_ARGB32); img.fill(qRgba(0,0,0,0)); QPainter painter(&img); painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform); // Text option QFont font("Monospace",8); font.setStyleHint(QFont::TypeWriter); painter.setFont(font); QVector<Structure::Graph*> inBetweens = s.topoVaryingInBetweens( numInBetweens ); QVector< QVector<double> > scores(numInBetweens); int imgWidth = 0; for(int k = 0; k < numInBetweens; k++) { inBetweens[k]->moveCenterTo( AlphaBlend(inBetweens[k]->property["t"].toDouble(), inBetweens[k]->property["sourceGraphCenter"].value<Vector3>(), inBetweens[k]->property["targetGraphCenter"].value<Vector3>()), true); // Draw images QImage inBetween = b->renderer->quickRender(inBetweens[k], Qt::white); imgWidth = inBetween.width(); // Rendered shape int newWidth = inBetween.width() * 0.5; int startX = k * newWidth; painter.drawImage(startX, 0, inBetween); // Store scores int idx = inBetweens[k]->property["graphIndex"].toInt(); QVector<double> vals; vals << ps[i].connectivity[idx] << ps[i].localSymmetry[idx] << ps[i].globalSymmetry[idx]; scores[k] = vals; } // Draw score lines for(int u = 0; u < scores.front().size(); u++) { // Graph QPainterPath poly; int padding = 0; QColor clr = colors[u]; painter.setPen(QPen(clr, 1)); // Render path for(int k = 0; k < numInBetweens; k++) { // Score graph //double minVal = ranges(u,0); //double range = ranges(u,2); //double val = (scores[k][u] - minVal) / range; double val = scores[k][u]; // Graph line int newWidth = imgWidth * 0.5; int startX = k * newWidth; int x = startX + newWidth; int y = padding + (img.height() - (img.height() * val)); if(k == 0) poly.moveTo(x, y); else poly.lineTo(x, y); // Dots painter.drawEllipse(QPoint(x,y), 2, 2); } painter.setBrush(Qt::NoBrush); painter.drawPath(poly); } // Draw ranges QStringList vals; for(int r = 0; r < 3; r++){ QStringList curVals; for(int c = 0; c < 4; c++) curVals << QString::number(ranges(r,c),'f',2); vals << curVals.join(" "); } if( false ) { painter.setPen(Qt::white); painter.drawText(11, img.height() - 9, vals.join(" # ")); painter.setPen(Qt::black); painter.drawText(10, img.height() - 10, vals.join(" # ")); } img.save( path + QString("/images/%1.png").arg(i) ); } } // Get global average for the measures Vector3d globalAvg (allRanges.col(9).mean(), allRanges.col(10).mean(), allRanges.col(11).mean()); // Sort based on score QMap<int,double> scoreMap; for(int i = 0; i < numPaths; i++) scoreMap[i] = ps[i].score(); QVector<int> sortedIndices; typedef QPair<double,int> ValIdx; foreach(ValIdx d, sortQMapByValue( scoreMap )){ sortedIndices.push_back( d.second ); }
Paths CorrespondenceGenerator::generate() { Paths result; auto boxA = a->bbox(), boxB = b->bbox(); QStringList nodesA, nodesB; for (auto n : a->nodes) nodesA << n->id; for (auto n : b->nodes) nodesB << n->id; for (auto g : a->groups) for (auto nid : g) nodesA.removeAll(nid); for (auto g : b->groups) for (auto nid : g) nodesB.removeAll(nid); Structure::NodeGroups tmpA, tmpB; for (auto nid : nodesA) tmpA.push_back( QVector<QString>() << nid ); for (auto nid : nodesB) tmpB.push_back( QVector<QString>() << nid ); for (auto g : a->groups) tmpA.push_back(g); for (auto g : b->groups) tmpB.push_back(g); a->groups = tmpA; b->groups = tmpB; /// Build similarity matrix of groups: Eigen::MatrixXd similiarity = Eigen::MatrixXd::Ones(a->groups.size(), b->groups.size() + 1); for (size_t i = 0; i < similiarity.rows(); i++){ double minVal = DBL_MAX; for (size_t j = 0; j < similiarity.cols(); j++){ double val = 0; if (j < b->groups.size()) { Eigen::AlignedBox3d groupBoxA, groupBoxB; for (auto sid : a->groups[i]) groupBoxA.extend(a->getNode(sid)->bbox(1.01)); for (auto sid : b->groups[j]) groupBoxB.extend(b->getNode(sid)->bbox(1.01)); Vector3 relativeCenterA = (groupBoxA.center() - boxA.min()).array() / boxA.sizes().array(); Vector3 relativeCenterB = (groupBoxB.center() - boxB.min()).array() / boxB.sizes().array(); val = (relativeCenterA - relativeCenterB).norm(); minVal = std::min(minVal, val); } similiarity(i, j) = val; } double maxVal = similiarity.row(i).maxCoeff(); if (maxVal == 0) maxVal = 1.0; for (size_t j = 0; j < b->groups.size(); j++) similiarity(i, j) = (similiarity(i, j) - minVal) / maxVal; } std::vector< std::vector<float> > data; for (int i = 0; i < similiarity.rows(); i++){ std::vector<float> dataRow; for (int j = 0; j < similiarity.cols(); j++) dataRow.push_back(similiarity(i, j)); data.push_back(dataRow); } //if (false) showTableColorMap(data, true); // DEBUG // Parameters: double similarity_threshold = 0.4; if (similiarity.rows() < 4) similarity_threshold = 1.0; // Collect good candidates Assignments candidates; for (size_t i = 0; i < similiarity.rows(); i++){ QVector<size_t> candidate; for (size_t j = 0; j < similiarity.cols(); j++){ if (similiarity(i, j) < similarity_threshold) candidate << j; } candidates << candidate; } int count_threshold = 1; Assignments assignments; if (candidates.size() > 7) { debugBox(QString("%1 candidates. Too complex (lower similairty?)").arg(candidates.size())); similarity_threshold = 0.1; Assignments candidates; for (size_t i = 0; i < similiarity.rows(); i++){ QVector<size_t> candidate; for (size_t j = 0; j < similiarity.cols(); j++){ if (similiarity(i, j) < similarity_threshold) candidate << j; } candidates << candidate; } cart_product(assignments, candidates, 10000); count_threshold = 12; } else { cart_product(assignments, candidates); } // Filter assignments Assignments filtered; for (auto & a : assignments) { QMap<size_t, size_t> counts; bool accept = true; auto NOTHING_SEGMENT = similiarity.cols() - 1; for (auto i : a) counts[i]++; for (auto k : counts.keys()) { if (k != NOTHING_SEGMENT && counts[k] > count_threshold){ accept = false; break; } } if (accept) filtered << a; } for (auto & assignment : filtered) { QVector < QStringList > landmarksA, landmarksB; for (size_t i = 0; i < assignment.size(); i++) { if (assignment[i] == b->groups.size()) continue; auto grpA = a->groups[i]; auto grpB = b->groups[assignment[i]]; // Resolve many-to-many if (grpA.size() > 1 && grpB.size() > 1) { QVector<QString> tmpA, tmpB; Eigen::AlignedBox3d groupBoxA, groupBoxB; for (auto sid : grpA) groupBoxA.extend(a->getNode(sid)->bbox(1.01)); for (auto sid : grpB) groupBoxB.extend(b->getNode(sid)->bbox(1.01)); for (auto nodeid_i : grpA){ auto nodeA = a->getNode(nodeid_i); QMap < QString, double > dists; for (auto nodeid_j : grpB){ auto nodeB = b->getNode(nodeid_j); Vector3 posA = (nodeA->position(Eigen::Vector4d(0.5, 0.5, 0, 0)) - boxA.min()).array() / boxA.sizes().array(); Vector3 posB = (nodeB->position(Eigen::Vector4d(0.5, 0.5, 0, 0)) - boxB.min()).array() / boxB.sizes().array(); dists[nodeid_j] = (posA - posB).norm(); } auto nodeid_j = sortQMapByValue(dists).first().second; landmarksA << (QStringList() << nodeid_i); landmarksB << (QStringList() << nodeid_j); } } else { landmarksA << QStringList::fromVector(grpA); landmarksB << QStringList::fromVector(grpB); } } result.push_back( qMakePair(landmarksA, landmarksB) ); } return result; }