bool HammingLoss::isBestEffort(Crag::CragEdge e, const Crag& crag, const BestEffort& bestEffort) { if (!_balance) return bestEffort.selected(e); // if balanced, non-leaf edges are not considered part of best-effort if (!crag.isLeafEdge(e)) return false; std::vector<Crag::CragNode> uPath = getPath(e.u(), crag); std::vector<Crag::CragNode> vPath = getPath(e.v(), crag); // are the paths of u and v merging somewhere? for (Crag::CragNode u : uPath) for (Crag::CragNode v : vPath) { if (u == v && bestEffort.selected(u)) return true; for (Crag::CragEdge e : crag.adjEdges(u)) if (crag.oppositeNode(u, e) == v && bestEffort.selected(e)) return true; } return false; }
std::map<Crag::Node, Crag::Node> CragStackCombiner::copyNodes(const Crag& source, Crag& target) { std::map<Crag::Node, Crag::Node> nodeMap; for (Crag::NodeIt i(source); i != lemon::INVALID; ++i) { Crag::Node n = target.addNode(); ExplicitVolume<unsigned char> volume = source.getVolume(i); if (!volume.getBoundingBox().isZero()) target.getVolume(n) = volume; nodeMap[i] = n; } for (Crag::EdgeIt e(source); e != lemon::INVALID; ++e) { Crag::Node u = nodeMap[source.u(e)]; Crag::Node v = nodeMap[source.v(e)]; target.addAdjacencyEdge(u, v); } for (Crag::SubsetArcIt a(source); a != lemon::INVALID; ++a) { Crag::Node s = nodeMap[source.toRag(source.getSubsetGraph().source(a))]; Crag::Node t = nodeMap[source.toRag(source.getSubsetGraph().target(a))]; target.addSubsetArc(s, t); } return nodeMap; }
bool AdjacencyAnnotator::isSiblingEdge(Crag& crag, Crag::CragEdge e) { if (crag.isRootNode(e.u()) || crag.isRootNode(e.v())) return false; Crag::CragNode parentU = (*crag.outArcs(e.u()).begin()).target(); Crag::CragNode parentV = (*crag.outArcs(e.v()).begin()).target(); return (parentU == parentV); }
void AdjacencyAnnotator::pruneChildEdges(Crag& crag) { std::vector<Crag::CragEdge> siblingEdges; for (Crag::CragEdge e : crag.edges()) if (isSiblingEdge(crag, e)) siblingEdges.push_back(e); for (Crag::CragEdge e : siblingEdges) crag.erase(e); LOG_USER(adjacencyannotatorlog) << "pruned " << siblingEdges.size() << " child adjacency edges" << std::endl; }
void AdjacencyAnnotator::propagateLeafAdjacencies(Crag& crag) { _numAdded = 0; for (Crag::CragNode n : crag.nodes()) if (crag.isRootNode(n)) recurseAdjacencies(crag, n); if (optionPruneChildEdges) pruneChildEdges(crag); LOG_USER(adjacencyannotatorlog) << "added " << _numAdded << " super node adjacency edges" << std::endl; }
void CragStackCombiner::combine(const std::vector<Crag>& crags, Crag& crag) { LOG_USER(cragstackcombinerlog) << "combining CRAGs, " << (_requireBbOverlap ? "" : " do not ") << "require bounding box overlap" << std::endl; std::map<Crag::Node, Crag::Node> prevNodeMap; std::map<Crag::Node, Crag::Node> nextNodeMap; for (unsigned int z = 1; z < crags.size(); z++) { LOG_USER(cragstackcombinerlog) << "linking CRAG " << (z-1) << " and " << z << std::endl; if (z == 1) prevNodeMap = copyNodes(crags[0], crag); else prevNodeMap = nextNodeMap; nextNodeMap = copyNodes(crags[z], crag); std::vector<std::pair<Crag::Node, Crag::Node>> links = findLinks(crags[z-1], crags[z]); for (const auto& pair : links) crag.addAdjacencyEdge( prevNodeMap[pair.first], nextNodeMap[pair.second]); } }
std::set<Crag::CragNode> AdjacencyAnnotator::recurseAdjacencies(Crag& crag, Crag::CragNode n) { LOG_ALL(adjacencyannotatorlog) << "recursing into node " << crag.id(n) << std::endl; // get all leaf subnodes std::set<Crag::CragNode> subnodes; for (Crag::CragArc a : crag.inArcs(n)) { std::set<Crag::CragNode> a_subnodes = recurseAdjacencies(crag, a.source()); for (Crag::CragNode s : a_subnodes) subnodes.insert(s); } // for each leaf subnode adjacent to a non-subnode, add an adjacency edge to // the non-subnode std::set<Crag::CragNode> neighbors; LOG_ALL(adjacencyannotatorlog) << "subnodes of " << crag.id(n) << " are:" << std::endl; for (Crag::CragNode s : subnodes) { LOG_ALL(adjacencyannotatorlog) << "\t" << crag.id(s) << std::endl; for (Crag::CragEdge e : crag.adjEdges(s)) { Crag::CragNode neighbor = e.opposite(s); // not a subnode if (!subnodes.count(neighbor)) neighbors.insert(neighbor); } } for (Crag::CragNode neighbor : neighbors) { LOG_ALL(adjacencyannotatorlog) << "adding propagated edge between " << crag.id(n) << " and " << crag.id(neighbor) << std::endl; crag.addAdjacencyEdge(n, neighbor); } _numAdded += neighbors.size(); subnodes.insert(n); LOG_ALL(adjacencyannotatorlog) << "leaving node " << crag.id(n) << std::endl; return subnodes; }
std::vector<Crag::CragNode> HammingLoss::getPath(Crag::CragNode n, const Crag& crag) { std::vector<Crag::CragNode> path; while (true) { path.push_back(n); if (crag.isRootNode(n)) break; n = (*crag.outArcs(n).begin()).target(); } return path; }
bool HammingLoss::isBestEffort(Crag::CragNode n, const Crag& crag, const BestEffort& bestEffort) { if (!_balance) return bestEffort.selected(n); // if balanced, non-leaf nodes are not considered part of best-effort if (!crag.isLeafNode(n)) return false; // is any of the parents best-effort? while (true) { if (bestEffort.selected(n)) return true; if (crag.isRootNode(n)) return false; n = (*crag.outArcs(n).begin()).target(); } }
std::set<Crag::Node> collectLeafNodes(const Crag& crag, Crag::Node n) { std::set<Crag::Node> leafNodes; if (crag.isLeafNode(n)) { leafNodes.insert(n); } else { for (Crag::SubsetInArcIt e(crag, crag.toSubset(n)); e != lemon::INVALID; ++e) { Crag::Node child = crag.toRag(crag.getSubsetGraph().source(e)); std::set<Crag::Node> leafs = collectLeafNodes(crag, child); for (Crag::Node l : leafs) leafNodes.insert(l); } } return leafNodes; }
std::vector<std::pair<Crag::Node, Crag::Node>> CragStackCombiner::findLinks(const Crag& a, const Crag& b) { UTIL_TIME_METHOD; HausdorffDistance hausdorff(a, b, 100); std::vector<std::pair<Crag::Node, Crag::Node>> links; for (Crag::NodeIt i(a); i != lemon::INVALID; ++i) { LOG_DEBUG(cragstackcombinerlog) << "checking for links of node " << a.id(i) << std::endl; for (Crag::NodeIt j(b); j != lemon::INVALID; ++j) { if (_requireBbOverlap) { util::box<float, 2> bb_i = a.getVolume(i).getBoundingBox().project<2>(); util::box<float, 2> bb_j = b.getVolume(j).getBoundingBox().project<2>(); if (!bb_i.intersects(bb_j)) continue; } double i_j, j_i; hausdorff.distance(i, j, i_j, j_i); double distance = std::min(i_j, j_i); if (distance <= _maxDistance) links.push_back(std::make_pair(i, j)); } } return links; }
HammingLoss::HammingLoss( const Crag& crag, const BestEffort& bestEffort, int balance) : Loss(crag), _balance((balance == 2 && optionBalanceHammingLoss) || (balance == 1)) { constant = 0; for (Crag::CragNode n : crag.nodes()) if (isBestEffort(n, crag, bestEffort)) { if (_balance) UTIL_ASSERT(crag.isLeafNode(n));; node[n] = -1; constant++; } else { if (!_balance || crag.isLeafNode(n)) node[n] = 1; } for (Crag::CragEdge e : crag.edges()) if (isBestEffort(e, crag, bestEffort)) { if (_balance) UTIL_ASSERT(crag.isLeafEdge(e));; edge[e] = -1; constant++; } else { if (!_balance || crag.isLeafEdge(e)) edge[e] = 1; } if (_balance) propagateLeafLoss(crag); }
void create_crag() { // useful for later: // //boost::filesystem::path dataDir = dir_of(__FILE__); //boost::filesystem::path graphfile = dataDir/"star.dat"; Crag crag; // add 100 nodes for (int i = 0; i < 100; i++) crag.addNode(); // create chains of 10 nodes for (int i = 0; i < 100; i += 10) { for (int j = i+1; j < i + 10; j++) { Crag::Node u = crag.nodeFromId(j-1); Crag::Node v = crag.nodeFromId(j); crag.addSubsetArc(u, v); } } // check levels of nodes for (int i = 0; i < 100; i++) { Crag::Node n = crag.nodeFromId(i); BOOST_CHECK_EQUAL(crag.getLevel(n), i%10); if (i%10 == 0) BOOST_CHECK(crag.isLeafNode(n)); else BOOST_CHECK(!crag.isLeafNode(n)); if (i%10 == 9) BOOST_CHECK(crag.isRootNode(n)); else BOOST_CHECK(!crag.isRootNode(n)); } }
void hausdorff() { Crag cragA; Crag cragB; CragVolumes volumesA(cragA); CragVolumes volumesB(cragB); // add two nodes each Crag::Node a1 = cragA.addNode(); Crag::Node a2 = cragA.addNode(); Crag::Node b1 = cragB.addNode(); Crag::Node b2 = cragB.addNode(); // add more nodes as parents of a and b Crag::Node p_a1 = cragA.addNode(); Crag::Node p_b1 = cragB.addNode(); cragA.addSubsetArc(a1, p_a1); cragB.addSubsetArc(b1, p_b1); // add more nodes merging p_a1 and a2 (same for b) Crag::Node root_a = cragA.addNode(); Crag::Node root_b = cragB.addNode(); cragA.addSubsetArc(p_a1, root_a); cragA.addSubsetArc(a2, root_a); cragB.addSubsetArc(p_b1, root_b); cragB.addSubsetArc(b2, root_b); // create volumes std::shared_ptr<CragVolume> volumeA1 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeA2 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeB1 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeB2 = std::make_shared<CragVolume>(11, 11, 1); volumeA2->setOffset(util::point<float, 3>(5, 5, 0)); volumeB2->setOffset(util::point<float, 3>(5, 5, 0)); volumeA1->data() = 0; volumeA2->data() = 0; volumeB1->data() = 0; volumeB2->data() = 0; // add a stripe for volumeA{1,2} and a dot for volumeB{1,2} // // 00000000000 00000000000 // 00000000000 00000000000 // 00000000000 00000000000 // 00000000x00 00000000*00 x=8,y=3 // 00000000000 00000000000 // *********** xxxxxxxxxxx y=5 // 00000000000 00000000000 // 00000000000 00000000000 // 00000000000 00000000000 // 00000000000 00000000000 // 00000000000 00000000000 for (int x = 0; x < 11; x++) { (*volumeA1)(x, 5, 0) = 1; (*volumeA2)(x, 5, 0) = 1; } (*volumeB1)(8, 3, 0) = 1; (*volumeB2)(8, 3, 0) = 1; volumesA.setVolume(a1, volumeA1); volumesA.setVolume(a2, volumeA2); volumesB.setVolume(b1, volumeB1); volumesB.setVolume(b2, volumeB2); volumesA.fillEmptyVolumes(); volumesB.fillEmptyVolumes(); HausdorffDistance hausdorff(100); double a_b, b_a; hausdorff(*volumesA[a1], *volumesB[b1], a_b, b_a); // Hausdorff should be sqrt(2*2 + 8*8) = 8.25 for A->B and 2 for B->A BOOST_CHECK_CLOSE(a_b, 8.246, 0.01); BOOST_CHECK_CLOSE(b_a, 2.0, 0.01); // same for parents hausdorff(*volumesA[p_a1], *volumesB[p_b1], a_b, b_a); BOOST_CHECK_CLOSE(a_b, 8.246, 0.01); BOOST_CHECK_CLOSE(b_a, 2.0, 0.01); // between a1 and b2, the distances should be sqrt(3*3 + 13*13) = 13.342 // A->B and sqrt(3*3 + 3*3) = 4.243 for B->A hausdorff(*volumesA[a1], *volumesB[b2], a_b, b_a); BOOST_CHECK_CLOSE(a_b, 13.342, 0.01); BOOST_CHECK_CLOSE(b_a, 4.243, 0.01); // between root_a and root_b Hausdorff should be sqrt(2*2 + 8*8) = 8.25 for // A->B and 2 for B->A hausdorff(*volumesA[root_a], *volumesB[root_b], a_b, b_a); BOOST_CHECK_CLOSE(a_b, 8.246, 0.01); BOOST_CHECK_CLOSE(b_a, 2.0, 0.01); }
void hausdorff_anisotropic() { Crag cragA; Crag cragB; CragVolumes volumesA(cragA); CragVolumes volumesB(cragB); // add two nodes each Crag::Node a1 = cragA.addNode(); Crag::Node a2 = cragA.addNode(); Crag::Node b1 = cragB.addNode(); Crag::Node b2 = cragB.addNode(); // add more nodes as parents of a and b Crag::Node p_a1 = cragA.addNode(); Crag::Node p_b1 = cragB.addNode(); cragA.addSubsetArc(a1, p_a1); cragB.addSubsetArc(b1, p_b1); // add more nodes merging p_a1 and a2 (same for b) Crag::Node root_a = cragA.addNode(); Crag::Node root_b = cragB.addNode(); cragA.addSubsetArc(p_a1, root_a); cragA.addSubsetArc(a2, root_a); cragB.addSubsetArc(p_b1, root_b); cragB.addSubsetArc(b2, root_b); // create volumes std::shared_ptr<CragVolume> volumeA1 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeA2 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeB1 = std::make_shared<CragVolume>(11, 11, 1); std::shared_ptr<CragVolume> volumeB2 = std::make_shared<CragVolume>(11, 11, 1); volumeA2->setOffset(util::point<float, 3>(5, 6, 0)); volumeB2->setOffset(util::point<float, 3>(5, 6, 0)); volumeA1->setResolution(util::point<float, 3>(1, 2, 1)); volumeA2->setResolution(util::point<float, 3>(1, 2, 1)); volumeB1->setResolution(util::point<float, 3>(1, 2, 1)); volumeB2->setResolution(util::point<float, 3>(1, 2, 1)); volumeA1->data() = 0; volumeA2->data() = 0; volumeB1->data() = 0; volumeB2->data() = 0; // add a stripe for volumeA{1,2} and a dot for volumeB{1,2} // // 00000000000 00000000000 // 00000000000 00000000000 // 00000000000 00000000000 // 00000000x00 00000000*00 x=8,y=3 // 00000000000 00000000000 // *********** xxxxxxxxxxx y=5 // 00000000000 00000000000 * x=13,y=6 // 00000000000 00000000000 // 00000000000 00000xxxxxxxxxxx // 00000000000 00000000000 // 00000000000 00000000000 for (int x = 0; x < 11; x++) { (*volumeA1)(x, 5, 0) = 1; (*volumeA2)(x, 5, 0) = 1; } (*volumeB1)(8, 3, 0) = 1; (*volumeB2)(8, 3, 0) = 1; volumesA.setVolume(a1, volumeA1); volumesA.setVolume(a2, volumeA2); volumesB.setVolume(b1, volumeB1); volumesB.setVolume(b2, volumeB2); volumesA.fillEmptyVolumes(); volumesB.fillEmptyVolumes(); { HausdorffDistance hausdorff(100); double a_b, b_a; hausdorff(*volumesA[a1], *volumesB[b1], a_b, b_a); BOOST_CHECK_CLOSE(a_b, sqrt(4*4 + 8*8), 0.01); BOOST_CHECK_CLOSE(b_a, sqrt(4*4), 0.01); // same for parents hausdorff(*volumesA[p_a1], *volumesB[p_b1], a_b, b_a); BOOST_CHECK_CLOSE(a_b, sqrt(4*4 + 8*8), 0.01); BOOST_CHECK_CLOSE(b_a, sqrt(4*4), 0.01); // b2 is offset by (5,6), which corresponds (5,3) pixels // // between a1 and b2, the distances should be sqrt(13*13 + 10*10) A->B and // sqrt(3*3 + 3*3) = 4.243 for B->A hausdorff(*volumesA[a1], *volumesB[b2], a_b, b_a); BOOST_CHECK_CLOSE(a_b, sqrt(13*13 + 2*2), 0.01); BOOST_CHECK_CLOSE(b_a, sqrt(3*3 + 2*2), 0.01); // between root_a and root_b Hausdorff should be sqrt(2*2 + 16*16) for A->B // and 4 for B->A hausdorff(*volumesA[root_a], *volumesB[root_b], a_b, b_a); BOOST_CHECK_CLOSE(a_b, sqrt(4*4 + 8*8), 0.01); BOOST_CHECK_CLOSE(b_a, sqrt(4*4), 0.01); } { HausdorffDistance hausdorff(10); double a_b, b_a; hausdorff(*volumesA[a1], *volumesB[b1], a_b, b_a); BOOST_CHECK_CLOSE(a_b, std::min(10.0, sqrt(4*4 + 8*8)), 0.01); BOOST_CHECK_CLOSE(b_a, std::min(10.0, sqrt(4*4)), 0.01); // same for parents hausdorff(*volumesA[p_a1], *volumesB[p_b1], a_b, b_a); BOOST_CHECK_CLOSE(a_b, std::min(10.0, sqrt(4*4 + 8*8)), 0.01); BOOST_CHECK_CLOSE(b_a, std::min(10.0, sqrt(4*4)), 0.01); // b2 is offset by (5,6), which corresponds (5,3) pixels // // between a1 and b2, the distances should be sqrt(13*13 + 10*10) A->B and // sqrt(3*3 + 3*3) = 4.243 for B->A hausdorff(*volumesA[a1], *volumesB[b2], a_b, b_a); BOOST_CHECK_CLOSE(a_b, std::min(10.0, sqrt(13*13 + 2*2)), 0.01); BOOST_CHECK_CLOSE(b_a, std::min(10.0, sqrt(3*3 + 2*2)), 0.01); // between root_a and root_b Hausdorff should be sqrt(2*2 + 16*16) for A->B // and 4 for B->A hausdorff(*volumesA[root_a], *volumesB[root_b], a_b, b_a); BOOST_CHECK_CLOSE(a_b, std::min(10.0, sqrt(4*4 + 8*8)), 0.01); BOOST_CHECK_CLOSE(b_a, std::min(10.0, sqrt(4*4)), 0.01); } }
int main(int argc, char** argv) { try { util::ProgramOptions::init(argc, argv); logger::LogManager::init(); Hdf5CragStore cragStore(optionProjectFile.as<std::string>()); Hdf5VolumeStore volumeStore(optionProjectFile.as<std::string>()); Crag crag; cragStore.retrieveCrag(crag); NodeFeatures nodeFeatures(crag); EdgeFeatures edgeFeatures(crag); LOG_USER(logger::out) << "reading features" << std::endl; cragStore.retrieveNodeFeatures(crag, nodeFeatures); cragStore.retrieveEdgeFeatures(crag, edgeFeatures); BundleOptimizer::Parameters parameters; parameters.lambda = optionRegularizerWeight; parameters.epsStrategy = BundleOptimizer::EpsFromGap; BundleOptimizer optimizer(parameters); BestEffort* bestEffort = 0; OverlapLoss* overlapLoss = 0; if (optionBestEffortFromProjectFile) { LOG_USER(logger::out) << "reading best-effort" << std::endl; bestEffort = new BestEffort(crag); vigra::HDF5File project( optionProjectFile.as<std::string>(), vigra::HDF5File::OpenMode::ReadWrite); project.cd("best_effort"); vigra::ArrayVector<int> beNodes; vigra::MultiArray<2, int> beEdges; project.readAndResize("nodes", beNodes); project.readAndResize("edges", beEdges); std::set<int> nodes; for (int n : beNodes) nodes.insert(n); std::set<std::pair<int, int>> edges; for (int i = 0; i < beEdges.shape(1); i++) edges.insert( std::make_pair( std::min(beEdges(i, 0), beEdges(i, 1)), std::max(beEdges(i, 0), beEdges(i, 1)))); for (Crag::NodeIt n(crag); n != lemon::INVALID; ++n) bestEffort->node[n] = nodes.count(crag.id(n)); for (Crag::EdgeIt e(crag); e != lemon::INVALID; ++e) bestEffort->edge[e] = edges.count( std::make_pair( std::min(crag.id(crag.u(e)), crag.id(crag.v(e))), std::max(crag.id(crag.u(e)), crag.id(crag.v(e))))); } else { LOG_USER(logger::out) << "reading ground-truth" << std::endl; ExplicitVolume<int> groundTruth; volumeStore.retrieveGroundTruth(groundTruth); LOG_USER(logger::out) << "finding best-effort solution" << std::endl; overlapLoss = new OverlapLoss(crag, groundTruth); bestEffort = new BestEffort(crag, *overlapLoss); } Loss* loss = 0; bool destructLoss = false; if (optionLoss.as<std::string>() == "hamming") { LOG_USER(logger::out) << "using Hamming loss" << std::endl; loss = new HammingLoss(crag, *bestEffort); destructLoss = true; } else if (optionLoss.as<std::string>() == "overlap") { LOG_USER(logger::out) << "using overlap loss" << std::endl; if (!overlapLoss) { LOG_USER(logger::out) << "reading ground-truth" << std::endl; ExplicitVolume<int> groundTruth; volumeStore.retrieveGroundTruth(groundTruth); LOG_USER(logger::out) << "finding best-effort solution" << std::endl; overlapLoss = new OverlapLoss(crag, groundTruth); } loss = overlapLoss; } else { LOG_ERROR(logger::out) << "unknown loss: " << optionLoss.as<std::string>() << std::endl; return 1; } if (optionNormalizeLoss) { LOG_USER(logger::out) << "normalizing loss..." << std::endl; loss->normalize(crag, MultiCut::Parameters()); } Oracle oracle( crag, nodeFeatures, edgeFeatures, *loss, *bestEffort); std::vector<double> weights(nodeFeatures.dims() + edgeFeatures.dims(), 0); optimizer.optimize(oracle, weights); storeVector(weights, optionFeatureWeights); if (destructLoss && loss != 0) delete loss; if (overlapLoss) delete overlapLoss; if (bestEffort) delete bestEffort; } catch (boost::exception& e) { handleException(e, std::cerr); } }
void PlanarAdjacencyAnnotator::annotate(Crag& crag) { if (optionCragType.as<std::string>() == "empty") return; UTIL_TIME_METHOD; util::box<float, 3> cragBB = crag.getBoundingBox(); util::point<float, 3> resolution; for (Crag::NodeIt n(crag); n != lemon::INVALID; ++n) { if (!crag.isLeafNode(n)) continue; resolution = crag.getVolume(n).getResolution(); break; } // no nodes? if (resolution.isZero()) return; // create a vigra multi-array large enough to hold all volumes vigra::MultiArray<3, int> ids( vigra::Shape3( cragBB.width() /resolution.x(), cragBB.height()/resolution.y(), cragBB.depth() /resolution.z()), std::numeric_limits<int>::max()); for (Crag::NodeIt n(crag); n != lemon::INVALID; ++n) { if (!crag.isLeafNode(n)) continue; const util::point<float, 3>& volumeOffset = crag.getVolume(n).getOffset(); const util::box<unsigned int, 3>& volumeDiscreteBB = crag.getVolume(n).getDiscreteBoundingBox(); util::point<unsigned int, 3> begin = (volumeOffset - cragBB.min())/resolution; util::point<unsigned int, 3> end = begin + util::point<unsigned int, 3>( volumeDiscreteBB.width(), volumeDiscreteBB.height(), volumeDiscreteBB.depth()); vigra::combineTwoMultiArrays( crag.getVolume(n).data(), ids.subarray( vigra::Shape3( begin.x(), begin.y(), begin.z()), vigra::Shape3( end.x(), end.y(), end.z())), ids.subarray( vigra::Shape3( begin.x(), begin.y(), begin.z()), vigra::Shape3( end.x(), end.y(), end.z())), vigra::functor::ifThenElse( vigra::functor::Arg1() == vigra::functor::Param(1), vigra::functor::Param(crag.id(n)), vigra::functor::Arg2() )); } //vigra::exportImage( //ids.bind<2>(0), //vigra::ImageExportInfo("debug/ids.tif")); typedef vigra::GridGraph<3> GridGraphType; typedef vigra::AdjacencyListGraph RagType; GridGraphType grid( ids.shape(), _neighborhood == Direct ? vigra::DirectNeighborhood : vigra::IndirectNeighborhood); RagType rag; RagType::EdgeMap<std::vector<GridGraphType::Edge>> affiliatedEdges; vigra::makeRegionAdjacencyGraph( grid, ids, rag, affiliatedEdges, std::numeric_limits<int>::max()); unsigned int numAdded = 0; crag.setGridGraph(grid); for (RagType::EdgeIt e(rag); e != lemon::INVALID; ++e) { int u = rag.id(rag.u(*e)); int v = rag.id(rag.v(*e)); Crag::Edge newEdge = crag.addAdjacencyEdge( crag.nodeFromId(u), crag.nodeFromId(v)); crag.setAffiliatedEdges( newEdge, affiliatedEdges[*e]); numAdded++; LOG_ALL(planaradjacencyannotatorlog) << "adding leaf node adjacency between " << u << " and " << v << std::endl; } LOG_USER(planaradjacencyannotatorlog) << "added " << numAdded << " leaf node adjacency edges" << std::endl; if (optionCragType.as<std::string>() == "full") propagateLeafAdjacencies(crag); }
void SolutionImageWriter::write( const Crag& crag, const CragVolumes& volumes, const CragSolution& solution, const std::string& basename, bool boundary) { LOG_DEBUG(solutionimagewriterlog) << "storing solution in " << basename << std::endl; if (_volumesBB.isZero()) _volumesBB = volumes.getBoundingBox(); LOG_DEBUG(solutionimagewriterlog) << "using bounding box of " << _volumesBB << std::endl; util::point<float, 3> resolution; for (Crag::CragNode n : crag.nodes()) { if (!crag.isLeafNode(n)) continue; resolution = volumes[n]->getResolution(); break; } LOG_DEBUG(solutionimagewriterlog) << "using resolution of " << resolution << std::endl; // create a vigra multi-array large enough to hold all volumes vigra::MultiArray<3, float> components( vigra::Shape3( _volumesBB.width() /resolution.x(), _volumesBB.height()/resolution.y(), _volumesBB.depth() /resolution.z()), std::numeric_limits<int>::max()); // background for areas without candidates if (boundary) components = 0.25; else components = 0; for (Crag::CragNode n : crag.nodes()) { LOG_ALL(solutionimagewriterlog) << "drawing node " << crag.id(n) << std::endl; // draw only selected nodes if (!solution.selected(n)) continue; const util::point<float, 3>& volumeOffset = volumes[n]->getOffset(); const util::box<unsigned int, 3>& volumeDiscreteBB = volumes[n]->getDiscreteBoundingBox(); util::point<unsigned int, 3> begin = (volumeOffset - _volumesBB.min())/resolution; util::point<unsigned int, 3> end = begin + util::point<unsigned int, 3>( volumeDiscreteBB.width(), volumeDiscreteBB.height(), volumeDiscreteBB.depth()); LOG_ALL(solutionimagewriterlog) << "\toffset : " << volumeOffset << std::endl; LOG_ALL(solutionimagewriterlog) << "\tdiscrete bb : " << volumeDiscreteBB << std::endl; LOG_ALL(solutionimagewriterlog) << "\ttarget area : " << begin << " -- " << end << std::endl; // fill id of connected component vigra::combineTwoMultiArrays( volumes[n]->data(), components.subarray(TinyVector3UInt(&begin[0]),TinyVector3UInt(&end[0])), components.subarray(TinyVector3UInt(&begin[0]),TinyVector3UInt(&end[0])), vigra::functor::ifThenElse( vigra::functor::Arg1() == vigra::functor::Param(1), vigra::functor::Param(solution.label(n)), vigra::functor::Arg2() )); } if (boundary) { // gray boundary for all leaf nodes for (Crag::CragNode n : crag.nodes()) if (crag.isLeafNode(n)) drawBoundary(volumes, n, components, 0.5); // black boundary for all selected nodes for (Crag::CragNode n : crag.nodes()) if (solution.selected(n)) drawBoundary(volumes, n, components, 0); } if (components.shape(2) > 1) { boost::filesystem::create_directory(basename); for (unsigned int z = 0; z < components.shape(2); z++) { std::stringstream ss; ss << std::setw(4) << std::setfill('0') << z; vigra::exportImage( components.bind<2>(z), vigra::ImageExportInfo((basename + "/" + ss.str() + ".tif").c_str())); } } else { vigra::exportImage( components.bind<2>(0), vigra::ImageExportInfo((basename + ".tif").c_str())); } }
void closed_set_solver() { /** * Subsets: * n7 * / \ * / \ * / \ * n5 n6 * / \ / \ * n1 n2 n3 n4 * * Adjacencies: * n7 * * * d * n5--------n6 * \ / * * e \ / f * * / \ * n1---n2----n3---n4 * a b c */ Crag crag; Crag::CragNode n1 = crag.addNode(); Crag::CragNode n2 = crag.addNode(); Crag::CragNode n3 = crag.addNode(); Crag::CragNode n4 = crag.addNode(); Crag::CragNode n5 = crag.addNode(); Crag::CragNode n6 = crag.addNode(); Crag::CragNode n7 = crag.addNode(); crag.addSubsetArc(n1, n5); crag.addSubsetArc(n2, n5); crag.addSubsetArc(n3, n6); crag.addSubsetArc(n4, n6); crag.addSubsetArc(n5, n7); crag.addSubsetArc(n6, n7); Crag::CragEdge a = crag.addAdjacencyEdge(n1, n2); Crag::CragEdge b = crag.addAdjacencyEdge(n2, n3); Crag::CragEdge c = crag.addAdjacencyEdge(n3, n4); Crag::CragEdge d = crag.addAdjacencyEdge(n5, n6); Crag::CragEdge e = crag.addAdjacencyEdge(n5, n3); Crag::CragEdge f = crag.addAdjacencyEdge(n2, n6); ClosedSetSolver solver(crag); CragSolution x(crag); ClosedSetSolver::Status status; { Costs costs(crag); costs.node[n7] = -1; solver.setCosts(costs); status = solver.solve(x); BOOST_CHECK_EQUAL(status, ClosedSetSolver::SolutionFound); // everything should be turned on for (Crag::CragNode n : crag.nodes()) BOOST_CHECK(x.selected(n)); for (Crag::CragEdge e : crag.edges()) BOOST_CHECK(x.selected(e)); } { Costs costs(crag); costs.node[n7] = 1; costs.edge[d] = -1; solver.setCosts(costs); status = solver.solve(x); BOOST_CHECK_EQUAL(status, ClosedSetSolver::SolutionFound); // everything except n7 should be turned on for (Crag::CragNode n : crag.nodes()) BOOST_CHECK(n != n7 ? x.selected(n) : !x.selected(n)); for (Crag::CragEdge e : crag.edges()) BOOST_CHECK(x.selected(e)); } }
void crag_iterators() { Crag crag; int numNodes = 10; for (int i = 0; i < numNodes; i++) crag.addNode(); int numEdges = 0; for (int i = 0; i < numNodes; i++) for (int j = 0; j < numNodes; j++) if (rand() > RAND_MAX/2) { crag.addAdjacencyEdge( crag.nodeFromId(i), crag.nodeFromId(j)); numEdges++; } int numArcs = 0; for (int i = 0; i < numNodes; i += 5) { for (int j = i; j < i + 4; j++) { crag.addSubsetArc( crag.nodeFromId(j), crag.nodeFromId(j+1)); numArcs++; } } BOOST_CHECK_EQUAL(crag.nodes().size(), numNodes); BOOST_CHECK_EQUAL(crag.edges().size(), numEdges); BOOST_CHECK_EQUAL(crag.arcs().size(), numArcs); numNodes = 0; { //UTIL_TIME_SCOPE("crag node old-school iterator"); //for (int j = 0; j < 1e8; j++) for (Crag::CragNodeIterator i = crag.nodes().begin(); i != crag.nodes().end(); i++) numNodes++; } { //UTIL_TIME_SCOPE("crag node iterator"); //for (int j = 0; j < 1e8; j++) for (Crag::CragNode n : crag.nodes()) { dontWarnMeAboutUnusedVar(n); numNodes++; } } { //UTIL_TIME_SCOPE("lemon node iterator"); //for (int j = 0; j < 1e8; j++) for (Crag::NodeIt n(crag); n != lemon::INVALID; ++n) numNodes -= 2; } BOOST_CHECK_EQUAL(numNodes, 0); numEdges = 0; for (Crag::CragEdge e : crag.edges()) { dontWarnMeAboutUnusedVar(e); numEdges++; } for (Crag::EdgeIt e(crag); e != lemon::INVALID; ++e) numEdges--; BOOST_CHECK_EQUAL(numEdges, 0); numArcs = 0; for (Crag::CragArc a : crag.arcs()) { dontWarnMeAboutUnusedVar(a); numArcs++; } for (Crag::SubsetArcIt a(crag); a != lemon::INVALID; ++a) numArcs--; BOOST_CHECK_EQUAL(numArcs, 0); for (Crag::CragNode n : crag.nodes()) { int numAdjEdges = 0; for (Crag::IncEdgeIt e(crag, n); e != lemon::INVALID; ++e) numAdjEdges++; BOOST_CHECK_EQUAL(crag.adjEdges(n).size(), numAdjEdges); for (Crag::CragEdge e : crag.adjEdges(n)) { dontWarnMeAboutUnusedVar(e); numAdjEdges--; } BOOST_CHECK_EQUAL(numAdjEdges, 0); int numInArcs = 0; for (Crag::SubsetInArcIt a(crag, crag.toSubset(n)); a != lemon::INVALID; ++a) numInArcs++; BOOST_CHECK_EQUAL(numInArcs, crag.inArcs(n).size()); for (Crag::CragArc a : crag.inArcs(n)) { dontWarnMeAboutUnusedVar(a); numInArcs--; } BOOST_CHECK_EQUAL(numInArcs, 0); int numOutArcs = 0; for (Crag::SubsetOutArcIt a(crag, crag.toSubset(n)); a != lemon::INVALID; ++a) numOutArcs++; BOOST_CHECK_EQUAL(numOutArcs, crag.outArcs(n).size()); for (Crag::CragArc a : crag.outArcs(n)) { dontWarnMeAboutUnusedVar(a); numOutArcs--; } BOOST_CHECK_EQUAL(numOutArcs, 0); Crag::CragEdgeIterator cei = crag.edges().begin(); Crag::EdgeIt ei(crag); while (ei != lemon::INVALID) { BOOST_CHECK((Crag::RagType::Node)((*cei).u()) == crag.getAdjacencyGraph().u(ei)); BOOST_CHECK((Crag::RagType::Node)((*cei).v()) == crag.getAdjacencyGraph().v(ei)); ++cei; ++ei; } Crag::CragArcIterator cai = crag.arcs().begin(); Crag::SubsetArcIt ai(crag); while (ai != lemon::INVALID) { BOOST_CHECK(crag.toSubset((*cai).source()) == crag.getSubsetGraph().source(ai)); BOOST_CHECK(crag.toSubset((*cai).target()) == crag.getSubsetGraph().target(ai)); ++cai; ++ai; } } }
int main(int argc, char** argv) { UTIL_TIME_SCOPE("main"); try { util::ProgramOptions::init(argc, argv); logger::LogManager::init(); util::point<float, 3> resolution( optionResX, optionResY, optionResZ); util::point<float, 3> offset( optionOffsetX, optionOffsetY, optionOffsetZ); Crag* crag = new Crag(); CragVolumes* volumes = new CragVolumes(*crag); Costs* mergeCosts = 0; CragImport import; bool alreadyDownsampled = false; if (optionMergeTree) { UTIL_TIME_SCOPE("read CRAG from mergetree"); // get information about the image to read std::string mergeTreePath = optionMergeTree; if (boost::filesystem::is_directory(boost::filesystem::path(mergeTreePath))) { std::vector<std::string> files = getImageFiles(mergeTreePath); // process one image after another std::vector<std::unique_ptr<Crag>> crags(files.size()); std::vector<std::unique_ptr<CragVolumes>> cragsVolumes; for (auto& c : crags) { c = std::unique_ptr<Crag>(new Crag); cragsVolumes.push_back(std::unique_ptr<CragVolumes>(new CragVolumes(*c))); } int i = 0; for (std::string file : files) { LOG_USER(logger::out) << "reading crag from " << file << std::endl; import.readCrag(file, *crags[i], *cragsVolumes[i], resolution, offset + util::point<float, 3>(0, 0, resolution.z()*i)); i++; } if (optionDownsampleCrag) { UTIL_TIME_SCOPE("downsample CRAG"); DownSampler downSampler(optionMinCandidateSize.as<int>()); std::vector<std::unique_ptr<Crag>> downSampledCrags(crags.size()); std::vector<std::unique_ptr<CragVolumes>> downSampledVolumes(crags.size()); for (int i = 0; i < crags.size(); i++) { downSampledCrags[i] = std::unique_ptr<Crag>(new Crag()); downSampledVolumes[i] = std::unique_ptr<CragVolumes>(new CragVolumes(*downSampledCrags[i])); downSampler.process(*crags[i], *cragsVolumes[i], *downSampledCrags[i], *downSampledVolumes[i]); } std::swap(cragsVolumes, downSampledVolumes); std::swap(crags, downSampledCrags); // prevent another downsampling on the candidates added by // the combiner alreadyDownsampled = true; } // combine crags CragStackCombiner combiner; combiner.combine(crags, cragsVolumes, *crag, *volumes); } else { import.readCrag(mergeTreePath, *crag, *volumes, resolution, offset); } } else if (optionSupervoxels.as<bool>() && (optionMergeHistory.as<bool>() || optionCandidateSegmentation.as<bool>())) { UTIL_TIME_SCOPE("read CRAG from merge history"); if (optionMergeHistory) { std::string mergeHistoryPath = optionMergeHistory; if (boost::filesystem::is_directory(boost::filesystem::path(mergeHistoryPath))) { // get all merge-history files std::vector<std::string> mhFiles; for (boost::filesystem::directory_iterator i(mergeHistoryPath); i != boost::filesystem::directory_iterator(); i++) if (!boost::filesystem::is_directory(*i) && ( i->path().extension() == ".txt" || i->path().extension() == ".dat" )) mhFiles.push_back(i->path().native()); std::sort(mhFiles.begin(), mhFiles.end()); // get all supervoxel files std::vector<std::string> svFiles = getImageFiles(optionSupervoxels); // process one image after another std::vector<std::unique_ptr<Crag>> crags(mhFiles.size()); std::vector<std::unique_ptr<CragVolumes>> cragsVolumes; for (auto& c : crags) { c = std::unique_ptr<Crag>(new Crag); cragsVolumes.push_back(std::unique_ptr<CragVolumes>(new CragVolumes(*c))); } for (int i = 0; i < mhFiles.size(); i++) { LOG_USER(logger::out) << "reading crag from supervoxel file " << svFiles[i] << " and merge history " << mhFiles[i] << std::endl; Costs mergeCosts(*crags[i]); import.readCragFromMergeHistory(svFiles[i], mhFiles[i], *crags[i], *cragsVolumes[i], resolution, offset + util::point<float, 3>(0, 0, resolution.z()*i), mergeCosts); } if (optionDownsampleCrag) { UTIL_TIME_SCOPE("downsample CRAG"); DownSampler downSampler(optionMinCandidateSize.as<int>()); std::vector<std::unique_ptr<Crag>> downSampledCrags(crags.size()); std::vector<std::unique_ptr<CragVolumes>> downSampledVolumes(crags.size()); for (int i = 0; i < crags.size(); i++) { downSampledCrags[i] = std::unique_ptr<Crag>(new Crag()); downSampledVolumes[i] = std::unique_ptr<CragVolumes>(new CragVolumes(*downSampledCrags[i])); downSampler.process(*crags[i], *cragsVolumes[i], *downSampledCrags[i], *downSampledVolumes[i]); } std::swap(cragsVolumes, downSampledVolumes); std::swap(crags, downSampledCrags); // prevent another downsampling on the candidates added by // the combiner alreadyDownsampled = true; } // combine crags CragStackCombiner combiner; combiner.combine(crags, cragsVolumes, *crag, *volumes); } else { mergeCosts = new Costs(*crag); import.readCragFromMergeHistory(optionSupervoxels, optionMergeHistory, *crag, *volumes, resolution, offset, *mergeCosts); } } else import.readCragFromCandidateSegmentation(optionSupervoxels, optionCandidateSegmentation, *crag, *volumes, resolution, offset); } else { LOG_ERROR(logger::out) << "at least one of mergetree or (supervoxels && mergeHistory) " << "have to be given to create a CRAG" << std::endl; return 1; } if (optionDownsampleCrag && !alreadyDownsampled) { UTIL_TIME_SCOPE("downsample CRAG"); Crag* downSampled = new Crag(); CragVolumes* downSampledVolumes = new CragVolumes(*downSampled); if (optionMinCandidateSize) { DownSampler downSampler(optionMinCandidateSize.as<int>()); downSampler.process(*crag, *volumes, *downSampled, *downSampledVolumes); } else { DownSampler downSampler; downSampler.process(*crag, *volumes, *downSampled, *downSampledVolumes); } delete crag; delete volumes; if (mergeCosts) { delete mergeCosts; mergeCosts = 0; } crag = downSampled; volumes = downSampledVolumes; } { UTIL_TIME_SCOPE("find CRAG adjacencies"); PlanarAdjacencyAnnotator annotator(PlanarAdjacencyAnnotator::Direct); annotator.annotate(*crag, *volumes); } // Statistics int numNodes = 0; int numRootNodes = 0; double sumSubsetDepth = 0; int maxSubsetDepth = 0; int minSubsetDepth = 1e6; for (Crag::NodeIt n(*crag); n != lemon::INVALID; ++n) { if (crag->isRootNode(n)) { int depth = crag->getLevel(n); sumSubsetDepth += depth; minSubsetDepth = std::min(minSubsetDepth, depth); maxSubsetDepth = std::max(maxSubsetDepth, depth); numRootNodes++; } numNodes++; } int numAdjEdges = 0; for (Crag::EdgeIt e(*crag); e != lemon::INVALID; ++e) numAdjEdges++; int numSubEdges = 0; for (Crag::SubsetArcIt e(*crag); e != lemon::INVALID; ++e) numSubEdges++; LOG_USER(logger::out) << "created CRAG" << std::endl; LOG_USER(logger::out) << "\t# nodes : " << numNodes << std::endl; LOG_USER(logger::out) << "\t# root nodes : " << numRootNodes << std::endl; LOG_USER(logger::out) << "\t# adjacencies : " << numAdjEdges << std::endl; LOG_USER(logger::out) << "\t# subset edges : " << numSubEdges << std::endl; LOG_USER(logger::out) << "\tmax subset depth : " << maxSubsetDepth << std::endl; LOG_USER(logger::out) << "\tmin subset depth : " << minSubsetDepth << std::endl; LOG_USER(logger::out) << "\tmean subset depth: " << sumSubsetDepth/numRootNodes << std::endl; // Store CRAG and volumes boost::filesystem::remove(optionProjectFile.as<std::string>()); Hdf5CragStore store(optionProjectFile.as<std::string>()); { UTIL_TIME_SCOPE("saving CRAG"); store.saveCrag(*crag); store.saveVolumes(*volumes); if (mergeCosts) store.saveCosts(*crag, *mergeCosts, "merge-scores"); } { UTIL_TIME_SCOPE("saving volumes"); Hdf5VolumeStore volumeStore(optionProjectFile.as<std::string>()); ExplicitVolume<float> intensities = readVolume<float>(getImageFiles(optionIntensities)); intensities.setResolution(resolution); intensities.setOffset(offset); intensities.normalize(); volumeStore.saveIntensities(intensities); if (optionGroundTruth) { ExplicitVolume<int> groundTruth = readVolume<int>(getImageFiles(optionGroundTruth)); if (optionExtractGroundTruthLabels) { vigra::MultiArray<3, int> tmp(groundTruth.data().shape()); vigra::labelMultiArrayWithBackground( groundTruth.data(), tmp); groundTruth.data() = tmp; } groundTruth.setResolution(resolution); groundTruth.setOffset(offset); volumeStore.saveGroundTruth(groundTruth); } if (optionBoundaries) { ExplicitVolume<float> boundaries = readVolume<float>(getImageFiles(optionBoundaries)); boundaries.setResolution(resolution); boundaries.setOffset(offset); boundaries.normalize(); volumeStore.saveBoundaries(boundaries); } bool atLeastOneAffinity = optionXAffinities || optionYAffinities || optionZAffinities; bool allAfinities = optionXAffinities && optionYAffinities && optionZAffinities; if (atLeastOneAffinity) { if (!allAfinities) { LOG_ERROR(logger::out) << "One of the affinities was not provided. " << "Affinities will be ignored." << std::endl; } else { ExplicitVolume<float> xAffinities = readVolume<float>(getImageFiles(optionXAffinities)); ExplicitVolume<float> yAffinities = readVolume<float>(getImageFiles(optionYAffinities)); ExplicitVolume<float> zAffinities = readVolume<float>(getImageFiles(optionZAffinities)); volumeStore.saveAffinities( xAffinities, yAffinities, zAffinities); } } } delete crag; delete volumes; delete mergeCosts; if (optionImportTrainingResult) { LOG_USER(logger::out) << "importing training results from " << optionImportTrainingResult.as<std::string>() << std::endl; Hdf5CragStore trainingStore(optionImportTrainingResult.as<std::string>()); FeatureWeights weights; FeatureWeights min; FeatureWeights max; trainingStore.retrieveFeatureWeights(weights); trainingStore.retrieveFeaturesMin(min); trainingStore.retrieveFeaturesMax(max); store.saveFeatureWeights(weights); store.saveFeaturesMin(min); store.saveFeaturesMax(max); } } catch (Exception& e) { handleException(e, std::cerr); } }