From 25700bfd2aa3e28fd0894a427ab4ac51fb2e72b4 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Mon, 29 May 2017 23:53:52 +0200 Subject: [PATCH 1/6] c++: graph: added implicit edge map --- .../nifty/graph/edge_map_from_node_map.hxx | 78 +++++++++++++++++++ include/nifty/graph/graph_maps.hxx | 16 ---- include/nifty/graph/undirected_grid_graph.hxx | 31 ++++++++ .../lib/graph/undirected_grid_graph.cxx | 61 +++++++++++++++ 4 files changed, 170 insertions(+), 16 deletions(-) create mode 100644 include/nifty/graph/edge_map_from_node_map.hxx diff --git a/include/nifty/graph/edge_map_from_node_map.hxx b/include/nifty/graph/edge_map_from_node_map.hxx new file mode 100644 index 000000000..d7364b771 --- /dev/null +++ b/include/nifty/graph/edge_map_from_node_map.hxx @@ -0,0 +1,78 @@ +#pragma once + + +namespace nifty{ +namespace graph{ +namespace graph_maps{ + + + +/** + * @brief Implicit edge map + * @details Convert a node map into an edge map by applying + * a binary functor to the node maps values. + * + * @tparam GRAPH the graph type + * @tparam NODE_MAP The node map. This can be a + * (const) reference or a value type (in) case of proxy objects + * @tparam BINARY_FUNCTOR a binary functor.This can be a + * (const) reference or a value type. + */ +template +class EdgeMapFromNodeMap { +public: + typedef GRAPH GraphType; + typedef BINARY_FUNCTOR BinaryFunctorType; + typedef typename BinaryFunctorType::value_type value_type; + typedef NODE_MAP NodeMapType; + + /** + * @brief construct edge map from node map and functor + * + * @param graph the graph + * @param nodeMap the node map + * @param binaryFunctor the binary functor + */ + EdgeMapFromNodeMap( + const GraphType & graph, + NodeMapType nodeMap, + BinaryFunctorType binaryFunctor + ) + : graph_(graph), + nodeMap_(nodeMap), + binaryFunctor_(binaryFunctor){ + } + + /** + * @brief get the value for an edge + * @details get the value for an edge + * by calling the binary functor. The functor + * is called with the node maps values at + * the enpoints of the edge. + * + * @param edgeIndex the edge index + * @return the value of the edge map + */ + value_type operator[](const uint64_t edgeIndex)const{ + const auto uv = graph_.uv(edgeIndex); + const auto u = uv.first; + const auto v = uv.second; + return binaryFunctor_(nodeMap_[u], nodeMap_[v]); + } + +private: + const GraphType & graph_; + NODE_MAP nodeMap_; + BinaryFunctorType binaryFunctor_; +}; + + + + + + + +} // namespace nifty::graph::graph_maps +} // namespace nifty::graph +} // namespace nifty + diff --git a/include/nifty/graph/graph_maps.hxx b/include/nifty/graph/graph_maps.hxx index de5a15dad..b21965131 100644 --- a/include/nifty/graph/graph_maps.hxx +++ b/include/nifty/graph/graph_maps.hxx @@ -183,14 +183,6 @@ private: - - - - - - - - template struct EdgeMap : public std::vector{ EdgeMap( const G & g, const T & val) @@ -217,14 +209,6 @@ struct EdgeMap : public std::vector{ }; - - - - - - - - } // namespace nifty::graph::graph_maps } // namespace nifty::graph } // namespace nifty diff --git a/include/nifty/graph/undirected_grid_graph.hxx b/include/nifty/graph/undirected_grid_graph.hxx index a73bab670..ecd6f3521 100644 --- a/include/nifty/graph/undirected_grid_graph.hxx +++ b/include/nifty/graph/undirected_grid_graph.hxx @@ -274,6 +274,37 @@ public: void deserialize(ITER iter); + /** + * @brief convert an image with DIM dimension to an edge map + * @details convert an image with DIM dimension to an edge map + * by applying a binary functor to the values of a node map at + * the endpoints of an edge. + * + * @param image the input image + * @param binaryFunctor a binary functor + * @param[out] the result edge map + * + * @return [description] + */ + template + void imageToEdgeMap( + const IMAGE & image, + BINARY_FUNCTOR binaryFunctor, + EDGE_MAP & edgeMap + )const{ + for(const auto edge : this->edges()){ + const auto uv = this->uv(edge); + CoordinateType cU,cV; + nodeToCoordinate(uv.first, cU); + nodeToCoordinate(uv.second, cV); + const auto uVal = image(cU.asStdArray()); + const auto vVal = image(cU.asStdArray()); + edgeMap[edge] = binaryFunctor(uVal, vVal); + } + } + + + // COORDINATE RELATED CoordinateType nodeToCoordinate(const uint64_t node)const{ CoordinateType ret; diff --git a/src/python/lib/graph/undirected_grid_graph.cxx b/src/python/lib/graph/undirected_grid_graph.cxx index 4bc9751a8..395985f24 100644 --- a/src/python/lib/graph/undirected_grid_graph.cxx +++ b/src/python/lib/graph/undirected_grid_graph.cxx @@ -45,6 +45,67 @@ namespace graph{ ){ return g.coordianteToNode(coord); }) + + .def("imageToEdgeMap", + []( + const GraphType & g, + nifty::marray::PyView image, + const std::string & functorType + ){ + + nifty::marray::PyView out({g.edgeIdUpperBound()+1}); + + if(functorType == std::string("min")){ + struct { + double operator()(const float a, const float b){ + return std::min(a,b); + } + } op; + return g.imageToEdgeMap(image, op, out); + } + else if(functorType == std::string("max")){ + struct { + double operator()(const float a, const float b){ + return std::max(a,b); + } + } op; + return g.imageToEdgeMap(image, op, out); + } + else if(functorType == std::string("sum")){ + struct { + double operator()(const float a, const float b){ + return a + b; + } + } op; + return g.imageToEdgeMap(image, op, out); + } + else if(functorType == std::string("prod")){ + struct { + double operator()(const float a, const float b){ + return a*b; + } + } op; + return g.imageToEdgeMap(image, op, out); + } + else{ + const auto s = boost::format("'%s' is an unknown mode. Must be in " + "['min', 'max', 'sum', 'prod', 'interpixel']")%functorType; + throw std::runtime_error(s.str()); + } + }, + py::arg("image"), + py::arg("mode"), + "convert an image to an edge map\n\n" + "Arguments:\n\n" + " image (numpy.ndarray): the image\n" + " mode str: mode can be:\n" + " * 'min': Minimum of the two image values at edges endpoints of coordinates.\n" + " * 'max': Maximum of the two image values at edges endpoints of coordinates.\n" + " * 'sum': Sum of the two image values at edges endpoints of coordinates.\n" + " * 'prod': Product of the two image values at edges endpoints of coordinates.\n" + ) + + //.def("uvIds", // [](GraphType & g) { // nifty::marray::PyView out({uint64_t(g.numberOfEdges()), uint64_t(2)}); From cd5d86ec91dfd7b93f7323f8527b7552e6b9c4f5 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Tue, 30 May 2017 15:56:23 +0200 Subject: [PATCH 2/6] python: added edge weighted watersheds to grid graph --- CMakeLists.txt | 4 +- .../nifty/graph/edge_weighted_watersheds.hxx | 7 +- include/nifty/python/converter.hxx | 13 ++- .../graph/plot_agglomerative_clustering.py | 2 +- .../examples/graph/plot_example_helper.py | 20 +++++ .../plot_undirected_grid_graph_watershed.py | 90 +++++++++++++++++++ src/python/lib/graph/CMakeLists.txt | 1 + src/python/lib/graph/connected_components.cxx | 2 - .../lib/graph/edge_weighted_watersheds.cxx | 72 +++++++++++++++ src/python/lib/graph/graph.cxx | 4 +- .../lib/graph/undirected_grid_graph.cxx | 12 ++- 11 files changed, 212 insertions(+), 15 deletions(-) create mode 100644 src/python/examples/graph/plot_example_helper.py create mode 100644 src/python/examples/graph/plot_undirected_grid_graph_watershed.py create mode 100644 src/python/lib/graph/edge_weighted_watersheds.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d008404f..126692e84 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,8 +4,8 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) project(nifty) set (NIFTY_VERSION_MAJOR 0) -set (NIFTY_VERSION_MINOR 10) -set (NIFTY_VERSION_PATCH 2) +set (NIFTY_VERSION_MINOR 11) +set (NIFTY_VERSION_PATCH 0) set (NIFTY_VERSION_SHORT_STR "${NIFTY_VERSION_MAJOR}.${NIFTY_VERSION_MINOR}") diff --git a/include/nifty/graph/edge_weighted_watersheds.hxx b/include/nifty/graph/edge_weighted_watersheds.hxx index 1e97b6eea..c9fc14353 100644 --- a/include/nifty/graph/edge_weighted_watersheds.hxx +++ b/include/nifty/graph/edge_weighted_watersheds.hxx @@ -224,8 +224,11 @@ namespace detail_watersheds_segmentation{ const SEEDS & seeds, LABELS & labels ){ - detail_watersheds_segmentation::RawPriorityFunctor fPriority; - detail_watersheds_segmentation::edgeWeightedWatershedsSegmentationImpl(g,edgeWeights,seeds,fPriority,labels); + detail_watersheds_segmentation::edgeWeightedWatershedsSegmentationKruskalImpl( + g,edgeWeights,seeds,labels); + + //detail_watersheds_segmentation::RawPriorityFunctor fPriority; + //detail_watersheds_segmentation::edgeWeightedWatershedsSegmentationImpl(g,edgeWeights,seeds,fPriority,labels); } diff --git a/include/nifty/python/converter.hxx b/include/nifty/python/converter.hxx index d0cda626c..fdbd3343e 100644 --- a/include/nifty/python/converter.hxx +++ b/include/nifty/python/converter.hxx @@ -4,7 +4,7 @@ #include #include - +#include #include @@ -304,11 +304,20 @@ namespace marray }; +} - +template +std::ostream& operator<<( + std::ostream& os, + const nifty::marray::PyView & obj +) +{ + os<<"PyViewArray[..]\n"; + return os; } + namespace tools{ template diff --git a/src/python/examples/graph/plot_agglomerative_clustering.py b/src/python/examples/graph/plot_agglomerative_clustering.py index 5b0ef969f..55a6f3c9a 100644 --- a/src/python/examples/graph/plot_agglomerative_clustering.py +++ b/src/python/examples/graph/plot_agglomerative_clustering.py @@ -99,7 +99,7 @@ f.add_subplot(2, 2, 4) b_img = skimage.segmentation.mark_boundaries(img, - seg.astype('uint32'), mode='inner', color=(1,0,0)) + seg.astype('uint32'), mode='inner', color=(0,0,0)) pylab.imshow(b_img) pylab.title('Segmentation') diff --git a/src/python/examples/graph/plot_example_helper.py b/src/python/examples/graph/plot_example_helper.py new file mode 100644 index 000000000..e689f931a --- /dev/null +++ b/src/python/examples/graph/plot_example_helper.py @@ -0,0 +1,20 @@ +""" +Helpers for examples +==================================== + +Helper functions shared by examples +""" + +import pylab + +# increase default figure size + +a,b = pylab.rcParams['figure.figsize'] +pylab.rcParams['figure.figsize'] = 1.5*a, 1.5*b + + +def randColorMap(size, zeroToZeros=True): + r = numpy.random.rand ( size,3) + if zeroToZeros: + r[0,:] = 0 + return matplotlib.colors.ListedColormap ( r) \ No newline at end of file diff --git a/src/python/examples/graph/plot_undirected_grid_graph_watershed.py b/src/python/examples/graph/plot_undirected_grid_graph_watershed.py new file mode 100644 index 000000000..7c2997bcc --- /dev/null +++ b/src/python/examples/graph/plot_undirected_grid_graph_watershed.py @@ -0,0 +1,90 @@ +""" +Grid Graph Edge Weighted Watersheds +==================================== +Edge Weighted Watersheds on a Undirected Grid Graph + +Warning: + + This function is still somewhat experimental +""" + +#################################### +# load modules +# and do some minor setup +from __future__ import print_function + +import nifty.graph +import skimage.data +import skimage.segmentation +import vigra +import matplotlib +import pylab +import numpy + +# increase default figure size +a,b = pylab.rcParams['figure.figsize'] +pylab.rcParams['figure.figsize'] = 1.5*a, 1.5*b + + +#################################### +# load some image +img = skimage.data.astronaut().astype('float32') +shape = img.shape[0:2] + +#plot the image +pylab.imshow(img/255) +pylab.show() + +################################################### +# get some edge indicator to get seeds from +taggedImg = vigra.taggedView(img,'xyc') +edgeStrength = vigra.filters.structureTensorEigenvalues(taggedImg, 1.0, 4.0)[:,:,0] +edgeStrength = edgeStrength.squeeze() +pylab.imshow(edgeStrength) +pylab.show() + +################################################### +# get seeds via local minima +seeds = vigra.analysis.localMinima(edgeStrength) +seeds = vigra.analysis.labelImageWithBackground(seeds) + +# plot seeds +cmap = numpy.random.rand ( seeds.max()+1,3) +cmap[0,:] = 0 +cmap = matplotlib.colors.ListedColormap ( cmap) +pylab.imshow(seeds, cmap=cmap) +pylab.show() + +######################################### +# grid graph +gridGraph = nifty.graph.undirectedGridGraph(shape) + + + +######################################### +# edgeStrength +edgeStrength = vigra.filters.gaussianGradientMagnitude(vigra.taggedView(img,'xyc'), 1.0) +edgeStrength = edgeStrength.squeeze() +pylab.imshow(edgeStrength) +pylab.show() + + +######################################### +# convert image to grid graph edge map +gridGraphEdgeStrength = gridGraph.imageToEdgeMap(edgeStrength, mode='sum') +numpy.random.permutation(gridGraphEdgeStrength) + + +######################################### +# run the actual algorithm +overseg = nifty.graph.edgeWeightedWatershedSegmentation(graph=gridGraph, seeds=seeds.ravel(), + edgeWeights=gridGraphEdgeStrength.ravel()) +overseg = overseg.reshape(shape) + + +######################################### +# result +b_img = skimage.segmentation.mark_boundaries(img/255, + overseg.astype('uint32'), mode='inner', color=(0,0,0)) +pylab.imshow(b_img) +pylab.show() \ No newline at end of file diff --git a/src/python/lib/graph/CMakeLists.txt b/src/python/lib/graph/CMakeLists.txt index 90974d6f7..13f9a876f 100644 --- a/src/python/lib/graph/CMakeLists.txt +++ b/src/python/lib/graph/CMakeLists.txt @@ -6,6 +6,7 @@ addPythonModule( graph.cxx undirected_list_graph.cxx undirected_grid_graph.cxx + edge_weighted_watersheds.cxx edge_contraction_graph_undirected_graph.cxx export_shortest_path_dijkstra.cxx connected_components.cxx diff --git a/src/python/lib/graph/connected_components.cxx b/src/python/lib/graph/connected_components.cxx index fb89419f1..568063cb6 100644 --- a/src/python/lib/graph/connected_components.cxx +++ b/src/python/lib/graph/connected_components.cxx @@ -7,8 +7,6 @@ #include "nifty/python/graph/undirected_grid_graph.hxx" #include "nifty/graph/components.hxx" - - #include "nifty/python/converter.hxx" namespace py = pybind11; diff --git a/src/python/lib/graph/edge_weighted_watersheds.cxx b/src/python/lib/graph/edge_weighted_watersheds.cxx new file mode 100644 index 000000000..c2d9d5f81 --- /dev/null +++ b/src/python/lib/graph/edge_weighted_watersheds.cxx @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include "nifty/python/graph/undirected_list_graph.hxx" +#include "nifty/python/graph/undirected_grid_graph.hxx" + +#include "nifty/graph/edge_weighted_watersheds.hxx" + + +#include "nifty/python/converter.hxx" + +namespace py = pybind11; + + +namespace nifty{ +namespace graph{ + + template + void exportEdgeWeightedWatershedT(py::module & module) { + + // function + module.def("edgeWeightedWatershedSegmentation", + []( + const GRAPH & graph, + nifty::marray::PyView seeds, + nifty::marray::PyView edgeWeights + ){ + + nifty::marray::PyView labels({seeds.shape(0)}); + + edgeWeightedWatershedsSegmentation(graph, edgeWeights, seeds, labels); + + return labels; + + }, + py::arg("graph"), + py::arg("seeds"), + py::arg("edgeWeights"), + "Edge weighted watershed on a graph\n\n" + "Arguments:\n\n" + " graph : the input graph\n" + " seeds (numpy.ndarray): the seeds\n" + " edgeWeights (numpy.ndarray): the edge weights\n\n" + "Returns:\n\n" + " numpy.ndarray : the segmentation" + ); + + + + + } + + void exportEdgeWeightedWatershed(py::module & module) { + + { + typedef UndirectedGraph<> GraphType; + exportEdgeWeightedWatershedT(module); + } + { + typedef UndirectedGridGraph<2, true> GraphType; + exportEdgeWeightedWatershedT(module); + } + { + typedef UndirectedGridGraph<3, true> GraphType; + exportEdgeWeightedWatershedT(module); + } + } + +} +} diff --git a/src/python/lib/graph/graph.cxx b/src/python/lib/graph/graph.cxx index 89605472a..c90c0e04e 100644 --- a/src/python/lib/graph/graph.cxx +++ b/src/python/lib/graph/graph.cxx @@ -15,7 +15,7 @@ namespace graph{ void exportEdgeContractionGraphUndirectedGraph(py::module & ); void exportShortestPathDijkstra(py::module &); void exportConnectedComponents(py::module &); - + void exportEdgeWeightedWatershed(py::module &); } } @@ -32,7 +32,7 @@ PYBIND11_PLUGIN(_graph) { exportEdgeContractionGraphUndirectedGraph(module); exportShortestPathDijkstra(module); exportConnectedComponents(module); - + exportEdgeWeightedWatershed(module); return module.ptr(); } diff --git a/src/python/lib/graph/undirected_grid_graph.cxx b/src/python/lib/graph/undirected_grid_graph.cxx index 395985f24..dc6cbb614 100644 --- a/src/python/lib/graph/undirected_grid_graph.cxx +++ b/src/python/lib/graph/undirected_grid_graph.cxx @@ -61,7 +61,7 @@ namespace graph{ return std::min(a,b); } } op; - return g.imageToEdgeMap(image, op, out); + g.imageToEdgeMap(image, op, out); } else if(functorType == std::string("max")){ struct { @@ -69,7 +69,7 @@ namespace graph{ return std::max(a,b); } } op; - return g.imageToEdgeMap(image, op, out); + g.imageToEdgeMap(image, op, out); } else if(functorType == std::string("sum")){ struct { @@ -77,7 +77,7 @@ namespace graph{ return a + b; } } op; - return g.imageToEdgeMap(image, op, out); + g.imageToEdgeMap(image, op, out); } else if(functorType == std::string("prod")){ struct { @@ -85,13 +85,17 @@ namespace graph{ return a*b; } } op; - return g.imageToEdgeMap(image, op, out); + g.imageToEdgeMap(image, op, out); + } + else if(functorType == std::string("interpixel")){ + throw std::runtime_error("mode='interpixel' is not yet supported"); } else{ const auto s = boost::format("'%s' is an unknown mode. Must be in " "['min', 'max', 'sum', 'prod', 'interpixel']")%functorType; throw std::runtime_error(s.str()); } + return out; }, py::arg("image"), py::arg("mode"), From 3450f5ec39a9eddd028c7a5681cd9979ab080964 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Tue, 30 May 2017 19:15:36 +0200 Subject: [PATCH 3/6] added node weighted watersheds --- CMakeLists.txt | 2 +- .../nifty/graph/node_weighted_watersheds.hxx | 135 ++++++++++++++++++ .../examples/graph/plot_cgp_introduction.py | 5 +- .../plot_undirected_grid_graph_watershed.py | 60 +++++--- src/python/lib/graph/CMakeLists.txt | 1 + .../lib/graph/edge_weighted_watersheds.cxx | 38 ++--- src/python/lib/graph/graph.cxx | 6 +- .../lib/graph/node_weighted_watersheds.cxx | 72 ++++++++++ 8 files changed, 274 insertions(+), 45 deletions(-) create mode 100644 include/nifty/graph/node_weighted_watersheds.hxx create mode 100644 src/python/lib/graph/node_weighted_watersheds.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 126692e84..bf1640003 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules) project(nifty) set (NIFTY_VERSION_MAJOR 0) -set (NIFTY_VERSION_MINOR 11) +set (NIFTY_VERSION_MINOR 12) set (NIFTY_VERSION_PATCH 0) diff --git a/include/nifty/graph/node_weighted_watersheds.hxx b/include/nifty/graph/node_weighted_watersheds.hxx new file mode 100644 index 000000000..01a03c265 --- /dev/null +++ b/include/nifty/graph/node_weighted_watersheds.hxx @@ -0,0 +1,135 @@ +#pragma once + + +#include // sort + + +#include "vigra/priority_queue.hxx" +#include "nifty/tools/changable_priority_queue.hxx" +#include "nifty/ufd/ufd.hxx" + +namespace nifty{ +namespace graph{ + +// \cond SUPPRESS_DOXYGEN +namespace detail_watersheds_segmentation{ + + + + + template< + class GRAPH, + class NODE_WEIGHTS, + class SEEDS, + class LABELS + > + void nodeWeightedWatershedsSegmentationImpl( + const GRAPH & g, + const NODE_WEIGHTS & nodeWeights, + const SEEDS & seeds, + LABELS & labels + ){ + typedef GRAPH Graph; + typedef typename NODE_WEIGHTS::value_type WeightType; + typedef typename LABELS::value_type LabelType; + //typedef typename Graph:: template EdgeMap EdgeBoolMap; + typedef vigra::PriorityQueue PQ; + + PQ pq; + for(auto node : g.nodes()) + labels[node] = seeds[node]; + + // put edges from nodes with seed on pq + for(auto node : g.nodes()){ + if(labels[node]!=static_cast(0)){ + + for(auto adj : g.adjacency(node)){ + const auto edge = adj.edge(); + const auto neigbour = adj.node(); + //std::cout<<"n- node "<(0)){ + const auto priority = nodeWeights[neigbour]; + pq.push(edge,priority); + //inPQ[edge]=true; + } + } + } + } + + + while(!pq.empty()){ + + const auto edge = pq.top(); + pq.pop(); + + const auto u = g.u(edge); + const auto v = g.v(edge); + const LabelType lU = labels[u]; + const LabelType lV = labels[v]; + + + if(lU==0 && lV==0){ + throw std::runtime_error("both have no labels"); + } + else if(lU!=0 && lV!=0){ + // nothing to do + } + else{ + + const auto unlabeledNode = lU==0 ? u : v; + const auto label = lU==0 ? lV : lU; + + // assign label to unlabeled node + labels[unlabeledNode] = label; + + // iterate over the nodes edges + for(auto adj : g.adjacency(unlabeledNode)){ + const auto otherEdge = adj.edge(); + const auto targetNode = adj.node(); + if(labels[targetNode] == 0){ + //if(inPQ[otherEdge] == false && labels[targetNode] == 0){ + const auto priority = nodeWeights[targetNode]; + pq.push(otherEdge,priority); + // inPQ[otherEdge]=true; + } + } + } + } + } + + + + + + +} // end namespace detail_watersheds_segmentation + +// \endcond + + +/// \brief edge weighted watersheds Segmentataion +/// +/// \param g: input graph +/// \param nodeWeights : node weights / node height +/// \param seeds : seed must be non empty! +/// \param[out] labels : resulting nodeLabeling (not necessarily dense) +template +void nodeWeightedWatershedsSegmentation( + const GRAPH & g, + const NODE_WEIGHTS & nodeWeights, + const SEEDS & seeds, + LABELS & labels +){ + detail_watersheds_segmentation::nodeWeightedWatershedsSegmentationImpl( + g,nodeWeights,seeds,labels); + +} + + + + + + +} // namespace nifty::graph +} // namespace nifty + diff --git a/src/python/examples/graph/plot_cgp_introduction.py b/src/python/examples/graph/plot_cgp_introduction.py index 7f743043e..636ecdd5e 100644 --- a/src/python/examples/graph/plot_cgp_introduction.py +++ b/src/python/examples/graph/plot_cgp_introduction.py @@ -4,6 +4,7 @@ An introduction into the cgp. """ +# sphinx_gallery_thumbnail_number = 5 from __future__ import print_function, division @@ -37,7 +38,7 @@ ############################################################################ # Load image and compute over-segmentation -img = skimage.data.coins()[10:80,10:80] +img = skimage.data.coins()[10:80,10:80].astype('float32')/255 pylab.imshow(img) pylab.show() @@ -50,7 +51,7 @@ ############################################################################ # Superpixels overseg = skimage.segmentation.slic(img, n_segments=50, - compactness=0.2, sigma=1) + compactness=0.04, sigma=1) # let overseg start from 1 overseg += 1 assert overseg.min() == 1 diff --git a/src/python/examples/graph/plot_undirected_grid_graph_watershed.py b/src/python/examples/graph/plot_undirected_grid_graph_watershed.py index 7c2997bcc..68169bdc0 100644 --- a/src/python/examples/graph/plot_undirected_grid_graph_watershed.py +++ b/src/python/examples/graph/plot_undirected_grid_graph_watershed.py @@ -1,12 +1,13 @@ """ -Grid Graph Edge Weighted Watersheds +Edge/Node Weighted Watersheds ==================================== -Edge Weighted Watersheds on a Undirected Grid Graph -Warning: +Compare edge weighted watersheds +and node weighted on a grid graph. + - This function is still somewhat experimental """ +# sphinx_gallery_thumbnail_number = 4 #################################### # load modules @@ -23,7 +24,7 @@ # increase default figure size a,b = pylab.rcParams['figure.figsize'] -pylab.rcParams['figure.figsize'] = 1.5*a, 1.5*b +pylab.rcParams['figure.figsize'] = 2.0*a, 2.0*b #################################### @@ -35,11 +36,12 @@ pylab.imshow(img/255) pylab.show() -################################################### -# get some edge indicator to get seeds from +################################################ +# get some edge indicator taggedImg = vigra.taggedView(img,'xyc') -edgeStrength = vigra.filters.structureTensorEigenvalues(taggedImg, 1.0, 4.0)[:,:,0] +edgeStrength = vigra.filters.structureTensorEigenvalues(taggedImg, 1.5, 1.9)[:,:,0] edgeStrength = edgeStrength.squeeze() +edgeStrength = numpy.array(edgeStrength) pylab.imshow(edgeStrength) pylab.show() @@ -55,19 +57,14 @@ pylab.imshow(seeds, cmap=cmap) pylab.show() + + ######################################### # grid graph gridGraph = nifty.graph.undirectedGridGraph(shape) -######################################### -# edgeStrength -edgeStrength = vigra.filters.gaussianGradientMagnitude(vigra.taggedView(img,'xyc'), 1.0) -edgeStrength = edgeStrength.squeeze() -pylab.imshow(edgeStrength) -pylab.show() - ######################################### # convert image to grid graph edge map @@ -75,16 +72,37 @@ numpy.random.permutation(gridGraphEdgeStrength) + ######################################### -# run the actual algorithm -overseg = nifty.graph.edgeWeightedWatershedSegmentation(graph=gridGraph, seeds=seeds.ravel(), - edgeWeights=gridGraphEdgeStrength.ravel()) -overseg = overseg.reshape(shape) +# run edge weighted watershed algorithm +oversegEdgeWeighted = nifty.graph.edgeWeightedWatershedsSegmentation(graph=gridGraph, seeds=seeds.ravel(), + edgeWeights=gridGraphEdgeStrength) +oversegEdgeWeighted = oversegEdgeWeighted.reshape(shape) + + + +######################################### +# run node weighted watershed algorithm +oversegNodeWeighted = nifty.graph.nodeWeightedWatershedsSegmentation(graph=gridGraph, seeds=seeds.ravel(), + nodeWeights=edgeStrength.ravel()) +oversegNodeWeighted = oversegNodeWeighted.reshape(shape) + ######################################### -# result +# plot results +f = pylab.figure() +f.add_subplot(1, 2, 1) b_img = skimage.segmentation.mark_boundaries(img/255, - overseg.astype('uint32'), mode='inner', color=(0,0,0)) + oversegEdgeWeighted.astype('uint32'), mode='inner', color=(0.1,0.1,0.2)) pylab.imshow(b_img) +pylab.title('Edge Weighted Watershed') + +f.add_subplot(1, 2, 2) +b_img = skimage.segmentation.mark_boundaries(img/255, + oversegNodeWeighted.astype('uint32'), mode='inner', color=(0.1,0.1,0.2)) +pylab.imshow(b_img) +pylab.title('Node Weighted Watershed') + + pylab.show() \ No newline at end of file diff --git a/src/python/lib/graph/CMakeLists.txt b/src/python/lib/graph/CMakeLists.txt index 13f9a876f..3fb55e363 100644 --- a/src/python/lib/graph/CMakeLists.txt +++ b/src/python/lib/graph/CMakeLists.txt @@ -7,6 +7,7 @@ addPythonModule( undirected_list_graph.cxx undirected_grid_graph.cxx edge_weighted_watersheds.cxx + node_weighted_watersheds.cxx edge_contraction_graph_undirected_graph.cxx export_shortest_path_dijkstra.cxx connected_components.cxx diff --git a/src/python/lib/graph/edge_weighted_watersheds.cxx b/src/python/lib/graph/edge_weighted_watersheds.cxx index c2d9d5f81..59bea5aae 100644 --- a/src/python/lib/graph/edge_weighted_watersheds.cxx +++ b/src/python/lib/graph/edge_weighted_watersheds.cxx @@ -18,23 +18,23 @@ namespace nifty{ namespace graph{ template - void exportEdgeWeightedWatershedT(py::module & module) { + void exportEdgeWeightedWatershedsT(py::module & module) { // function - module.def("edgeWeightedWatershedSegmentation", - []( - const GRAPH & graph, - nifty::marray::PyView seeds, - nifty::marray::PyView edgeWeights - ){ - - nifty::marray::PyView labels({seeds.shape(0)}); - - edgeWeightedWatershedsSegmentation(graph, edgeWeights, seeds, labels); - - return labels; - - }, + module.def("edgeWeightedWatershedsSegmentation", + []( + const GRAPH & graph, + nifty::marray::PyView seeds, + nifty::marray::PyView edgeWeights + ){ + + nifty::marray::PyView labels({seeds.shape(0)}); + + edgeWeightedWatershedsSegmentation(graph, edgeWeights, seeds, labels); + + return labels; + + }, py::arg("graph"), py::arg("seeds"), py::arg("edgeWeights"), @@ -52,19 +52,19 @@ namespace graph{ } - void exportEdgeWeightedWatershed(py::module & module) { + void exportEdgeWeightedWatersheds(py::module & module) { { typedef UndirectedGraph<> GraphType; - exportEdgeWeightedWatershedT(module); + exportEdgeWeightedWatershedsT(module); } { typedef UndirectedGridGraph<2, true> GraphType; - exportEdgeWeightedWatershedT(module); + exportEdgeWeightedWatershedsT(module); } { typedef UndirectedGridGraph<3, true> GraphType; - exportEdgeWeightedWatershedT(module); + exportEdgeWeightedWatershedsT(module); } } diff --git a/src/python/lib/graph/graph.cxx b/src/python/lib/graph/graph.cxx index c90c0e04e..32967f62a 100644 --- a/src/python/lib/graph/graph.cxx +++ b/src/python/lib/graph/graph.cxx @@ -15,7 +15,8 @@ namespace graph{ void exportEdgeContractionGraphUndirectedGraph(py::module & ); void exportShortestPathDijkstra(py::module &); void exportConnectedComponents(py::module &); - void exportEdgeWeightedWatershed(py::module &); + void exportEdgeWeightedWatersheds(py::module &); + void exportNodeWeightedWatersheds(py::module &); } } @@ -32,7 +33,8 @@ PYBIND11_PLUGIN(_graph) { exportEdgeContractionGraphUndirectedGraph(module); exportShortestPathDijkstra(module); exportConnectedComponents(module); - exportEdgeWeightedWatershed(module); + exportEdgeWeightedWatersheds(module); + exportNodeWeightedWatersheds(module); return module.ptr(); } diff --git a/src/python/lib/graph/node_weighted_watersheds.cxx b/src/python/lib/graph/node_weighted_watersheds.cxx new file mode 100644 index 000000000..26d7c3702 --- /dev/null +++ b/src/python/lib/graph/node_weighted_watersheds.cxx @@ -0,0 +1,72 @@ +#include +#include +#include +#include + +#include "nifty/python/graph/undirected_list_graph.hxx" +#include "nifty/python/graph/undirected_grid_graph.hxx" + +#include "nifty/graph/node_weighted_watersheds.hxx" + + +#include "nifty/python/converter.hxx" + +namespace py = pybind11; + + +namespace nifty{ +namespace graph{ + + template + void exportNodeWeightedWatershedsT(py::module & module) { + + // function + module.def("nodeWeightedWatershedsSegmentation", + []( + const GRAPH & graph, + nifty::marray::PyView seeds, + nifty::marray::PyView nodeWeights + ){ + + nifty::marray::PyView labels({seeds.shape(0)}); + + nodeWeightedWatershedsSegmentation(graph, nodeWeights, seeds, labels); + + return labels; + + }, + py::arg("graph"), + py::arg("seeds"), + py::arg("nodeWeights"), + "Node weighted watershed on a graph\n\n" + "Arguments:\n\n" + " graph : the input graph\n" + " seeds (numpy.ndarray): the seeds\n" + " nodeWeights (numpy.ndarray): the node weights\n\n" + "Returns:\n\n" + " numpy.ndarray : the segmentation" + ); + + + + + } + + void exportNodeWeightedWatersheds(py::module & module) { + + { + typedef UndirectedGraph<> GraphType; + exportNodeWeightedWatershedsT(module); + } + { + typedef UndirectedGridGraph<2, true> GraphType; + exportNodeWeightedWatershedsT(module); + } + { + typedef UndirectedGridGraph<3, true> GraphType; + exportNodeWeightedWatershedsT(module); + } + } + +} +} From 4d988168116eff086d1bec7be452d8e3f9ed8e97 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Tue, 30 May 2017 19:20:39 +0200 Subject: [PATCH 4/6] added node weighted watersheds --- .../examples/graph/plot_example_helper.py | 20 ------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/python/examples/graph/plot_example_helper.py diff --git a/src/python/examples/graph/plot_example_helper.py b/src/python/examples/graph/plot_example_helper.py deleted file mode 100644 index e689f931a..000000000 --- a/src/python/examples/graph/plot_example_helper.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -Helpers for examples -==================================== - -Helper functions shared by examples -""" - -import pylab - -# increase default figure size - -a,b = pylab.rcParams['figure.figsize'] -pylab.rcParams['figure.figsize'] = 1.5*a, 1.5*b - - -def randColorMap(size, zeroToZeros=True): - r = numpy.random.rand ( size,3) - if zeroToZeros: - r[0,:] = 0 - return matplotlib.colors.ListedColormap ( r) \ No newline at end of file From a785600bfa143d339cb42c1fadca2c2b0b605614 Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Tue, 30 May 2017 19:29:14 +0200 Subject: [PATCH 5/6] fixed example --- src/python/examples/graph/plot_cgp_introduction.py | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/python/examples/graph/plot_cgp_introduction.py b/src/python/examples/graph/plot_cgp_introduction.py index 636ecdd5e..8bac4f949 100644 --- a/src/python/examples/graph/plot_cgp_introduction.py +++ b/src/python/examples/graph/plot_cgp_introduction.py @@ -202,12 +202,3 @@ pylab.title('Cell-%d Labels / \n%s Labels '%(cellType,cellNames[cellType] ) ) pylab.show() - -############################################################################ -# Compute edge strength - -smoothed = skimage.filters.gaussian(img, 2.5) -edgeStrength = skimage.filters.sobel(smoothed) - -# pylab.imshow(edgeStrength) -# pylab.show() \ No newline at end of file From 378b4cff8909aa7e376d60554319bb3f3e05278b Mon Sep 17 00:00:00 2001 From: DerThorsten Date: Tue, 30 May 2017 19:30:35 +0200 Subject: [PATCH 6/6] fixed example --- docsrc/python/index.rst | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/docsrc/python/index.rst b/docsrc/python/index.rst index a083cf3c4..b7bcfa8f7 100644 --- a/docsrc/python/index.rst +++ b/docsrc/python/index.rst @@ -10,20 +10,3 @@ Contents: zbibliography - -The documentation is split into 3 parts: - - * The documentation: - Auto generated API reference can be confusing - for beginners. - This is even more true for python libraries which - use pybind11 or boost::python to export C++ to python. - If the C++ code heavily relies on templates the auto generated - documentation is full of complicated ``template`` names. - Therefore we try to add es many examples and hand written - documentation to improve the user experience. - - * Examples: - TODO - * The API Reference documentation: - TODO