MAP2GRAPH_BASE - From a map to a weighted graph.

Contents

Description

Convert a 2D logical map with pixels belonging to a (connected or not) graph set to true into an (undirected) weighted graph (parameterized by its adjacency matrix and the coordinates of the set of pixels belonging to it), where the weight is given by an additional cost map.

Syntax

     [graph, vertex] = MAP2GRAPH_BASE(map, weight, conn, reduce);

Inputs, outputs

Depending on the boolean variable reduce, the output graph describes the edges between neighbouring pixels belonging to the network (vertex is then the list of all true pixels present in the map): reduce=false, or the edges between the branching and leave pixels extracted from the network (vertex is then the list of such pixels): reduce=true (default).

Remark

In the case reduce=false, the map reconstruction with GRAPH2MAP_BASE from the graph output of MAP2GRAPH_BASE is exactly the original map.

See also

Ressembles: GRAPHMAP, GRAPH2MAP_BASE, GPLOT. Requires: IXNEIGHBOURS, DIJKADVANCED, BWMORPH, SPARSE.

Function implementation

function [graph, vertex] = map2graph_base(map, weight, conn, reduce)

check/set variables

if nargin<4
    if isempty(ver('images')),  reduce = false;
    else                        reduce = true;  end
elseif reduce && isempty(ver('images'))
    warning('map2graph_base:inputwarning', ...
        ['toolbox Image Processing required for reduced output - '...
        'reduce variale reset to false']);
    reduce = false;
end

% map should be a logical matrix
[X,Y] = size(map);

first search for the connection pixel to pixel

[ic,icd] = ixneighbours(true(X,Y), map, conn);
% true(X,Y): dummy variable used by IXNEIGHBOURS as map is logical

get rid of those neighbours which are not set to true in the map (ie, they don't belong to the graph/network)

ic(~map(icd)) = [];
icd(~map(icd)) = [];

find the edges between neighbour pixels

edges = unique(sort([ic icd],2),'rows');

the weight we assign to an edge between two neighbour pixels is the mean of the cost function evaluated on these two pixels

wedges = mean(weight(edges),2);
wedges(wedges==0) = NaN;  % set null weight to NaN values

define the list of points connected by an edge in the map

[ind, ~, j] = unique(edges);

change the edges FROM connection between pixels given by their indices in the map TO connection between pixels given by their indices in the vertex vector

edges = reshape(j,size(edges));

define the vertex vector of coordinates of the vertices in the map

j = unique(j);
nvert = j(end);
[i,j] = ind2sub([X, Y], ind(j));
vertex = [i,j];

complete with possibly missed isolated pixels

iso = bwisolated(map);
[isoi, isoj] = find(iso);
niso = length(isoi);
if niso>0
    vertex = [vertex; isoi isoj];
    wedges = [wedges; zeros(niso,1)];
    edges = [edges; repmat((nvert+1:nvert+niso)', [1 2])];
    nvert = nvert + niso;
end

we now have a simpler representation based on vertex indices

graph = sparse(edges(:,1), edges(:,2), wedges, nvert, nvert);
% note: otherwise we could have written at an earlier stage the
% representation as:
%    graph = sparse(edges(:,1), edges(:,2), wedges, X*Y, X*Y);
% but this is a (X*Y)x(X*Y) sparse matrix as all pixels are represented in
% the sparse matrix. Using vertex reduces the size of the full matrix.

now symetric-ize!

graph = graph | graph';
% note: we could also compute earlier:
%    edges = [edges; fliplr(edges)];
%    wedges = [wedges; wedges];
% to ensure that the resulting graph is symmetric

reduce

if reduce
    % leave points
    endPts = bwmorph(map,'endpoints') & map;
    [i,j] = find(endPts);
    rvertex = [i, j];
    % branching points
    branchPts = bwmorph(map,'branchpoints') & map;
    % note: in some cases, BWMORPH(.,'BRANCHPOINTS') returns points that do
    % not belong to the network; we avoid this by constraining the set of
    % branching points to a subset of the network (& map)
    [i,j] = find(branchPts);
    rvertex = [rvertex; i, j];

    % display
    % t = zeros(X,Y);
    % t(sub2ind([X, Y],rvertex(:,1),rvertex(:,2))) = 1;
    % figure, imagesc(t), colormap gray

    % find the indices of the branch- and endpoints in the list of vertices
    [~,irvertex] = ismember(rvertex,vertex,'rows');
    % ISMEMBER returns 1 where the rows of vertex are also in rvertex
    nvert = length(irvertex);

    % we call DIJKADVANCED_BASE (faster, handles null weights)
    A = graph>0 | isnan(graph);  % adjacency matrix
    graph(isnan(graph)) = 0;     % null weights are reset to 0
    d = dijkadvanced(A, graph, irvertex, irvertex);
    % equivalent to:
    %    d = dijkstra_base(graph,irvertex,irvertex,'sing1');
    % or:
    %    d = [];
    %    for i=1:nvert, d = [d;dijkstra_base(graph,irvertex(i),[],'sing1')];
    %    end
    % see also:
    %    d = dijk(graph,irvertex,irvertex);

    [i,j] = find(d<Inf);
    graph = sparse(i, j, d(sub2ind([nvert nvert],i,j)), nvert, nvert);
    graph = graph | graph';

    vertex = rvertex;
end

% display
% t = graph2map_base(graph, vertex, [X Y 1 1 1 1]);
% figure, imagesc(t), colormap gray
end % end of map2graph_base