Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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);
}
Пример #4
0
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;
}
Пример #5
0
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;
}
Пример #6
0
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]);
	}
}
Пример #7
0
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;
}
Пример #8
0
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;
}
Пример #9
0
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();
	}
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
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);
}
Пример #13
0
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));
	}
}
Пример #14
0
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);
}
Пример #15
0
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);
	}
}
Пример #16
0
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);
	}
}
Пример #17
0
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);
}
Пример #18
0
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()));
	}
}
Пример #19
0
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));
	}
}
Пример #20
0
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;
		}
	}
}
Пример #21
0
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);
	}
}