Commit b0e7fdd4 authored by Guillaume Sadegh's avatar Guillaume Sadegh
Browse files

INIM: Region Adjacency Graph.

        * inim/2010/rag/rag.cc, inim/2010/rag/center_weight.hh,
        inim/2010/rag/dijkstra.hh, inim/2010/rag/p_vertices_with_accu.hh,
        inim/2010/rag/rag.hh, inim/2010/rag/Makefile: New, INIM1 project
        to detect lines from a picture with a Region Adjacency Graph.

git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@3792 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 1d56b557
2009-05-14 Guillaume Sadegh <sadegh@lrde.epita.fr>
INIM: Region Adjacency Graph.
* inim/2010/rag/rag.cc, inim/2010/rag/center_weight.hh,
inim/2010/rag/dijkstra.hh, inim/2010/rag/p_vertices_with_accu.hh,
inim/2010/rag/rag.hh, inim/2010/rag/Makefile: New, INIM1 project
to detect lines from a picture with a Region Adjacency Graph.
2009-05-12 Fabien Freling <fabien.freling@lrde.epita.fr>
Add a morpho transformation before edges computation.
......@@ -232,13 +240,13 @@
2009-05-04 Fabien Freling <fabien.freling@lrde.epita.fr>
Add watershed in fixed segmentation.
* fabien/igr/seg_fixed.cc: Add closing::volume() and
* fabien/igr/seg_fixed.cc: Add closing::volume() and
watershed::flooding() in fixed segmentation.
2009-04-30 Guillaume Lazzara <lazzara@lrde.epita.fr>
Change references to l2l:: to v2v::.
* icdar/2009/hsc/first_attempts/boxes.cc,
* icdar/2009/hsc/first_attempts/exec/iz_lines.cc,
* icdar/2009/hsc/first_attempts/exec/relabel_lines.cc,
......@@ -422,7 +430,7 @@
Finder for entry point in an watersheded image.
* Makefile: Compile directly from the directory.
* cuttor.hh: Add needed include for point2d.
* cuttor.hxx: Add function to retrieve an entry for
* cuttor.hxx: Add function to retrieve an entry for
main algorithm.
2009-04-21 Fabien Freling <fabien.freling@lrde.epita.fr>
......@@ -1154,7 +1162,7 @@
* scribo/src/extract_text_double_several_links.cc,
* scribo/src/extract_text_multiple_links.cc,
* scribo/src/extract_text_single_link.cc: cleanup small components.
* scribo/src/extract_text_several_left_links.cc,
* scribo/src/extract_text_several_multiple_links,
* scribo/src/rectangularity.cc,
......@@ -1303,7 +1311,7 @@
* scribo/table/align_lines_verticaly.hh,
* scribo/table/connect_horizontal_lines.hh,
* scribo/table/connect_vertical_lines.hh: add more parameters.
* scribo/table/extract.hh: new routine to extract document tables.
* scribo/table/extract_lines_with_opening.hh: new routine to extract
......@@ -1649,7 +1657,7 @@
* scribo/+out.txt: remove.
* scribo/Makefile: add new rules.
* scribo/demat.hh: cleanup and comment.
2009-03-05 Thierry Geraud <thierry.geraud@lrde.epita.fr>
......
SRC=rag.cc
HEADERS=center_weight.hh dijkstra.hh p_vertices_with_accu.hh rag.hh
OBJ=$(SRC:.cc=.o)
TEST=rag
CXX=g++-4.3
CXXFLAGS=-W -Wall -O2 -DNDEBUG
CPPFLAGS=-I../../../../
LD=$(CXX)
LDFLAGS=
all: $(TEST)
$(TEST): $(OBJ)
$(LD) $(LDFLAGS) $(OBJ) -o $(TEST)
.cc.o:
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c $<
clean:
rm -f *.o *~
distclean: clean
rm -f $(TEST)
rag.o: rag.cc $(HEADERS)
// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory
// (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
// Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License. This exception does not however invalidate any other
// reasons why the executable file might be covered by the GNU General
// Public License.
#ifndef MLN_ACCU_CENTER_WEIGHT_HH
# define MLN_ACCU_CENTER_WEIGHT_HH
/// \file mln/accu/center.hh
///
/// Define an accumulator that computes the mass center of a site set.
///
/// \todo Fix to_result() value when invalid...
# include <mln/accu/internal/base.hh>
# include <mln/accu/bbox.hh>
# include <mln/util/couple.hh>
namespace mln
{
namespace accu
{
/// Generic center accumulator class.
///
/// \tparam P the type of site.
/// \tparam V the type of vector to be used as result.
/// The default vector type is the one provided by P.
template <typename I, typename V = util::couple<mln_psite(I)::vec, int> >
struct center_weight
: public mln::accu::internal::base<V, center_weight<I,V> >
{
typedef mln_psite(I) argument;
typedef V result;
typedef I image_weight;
typedef argument P;
center_weight(const Image<image_weight>& im);
/// Manipulators.
/// \{
void init();
void take(const argument& t);
void take(const center_weight<I,V>& other);
/// \}
/// Get the value of the accumulator.
V to_result() const;
operator P() const;
/// Check whether this accu is able to return a result.
bool is_valid() const;
protected:
algebra::vec<P::dim, mln_sum(mln_coord(P))> center_;
unsigned nsites_;
const image_weight& im_;
int border_;
};
namespace meta
{
/// Meta accumulator for center.
struct center_weight : public Meta_Accumulator< center_weight >
{
template <typename I>
struct with
{
typedef accu::center_weight< I> ret;
};
};
} // end of namespace mln::accu::meta
# ifndef MLN_INCLUDE_ONLY
template <typename I, typename V>
inline
center_weight<I,V>::center_weight(const Image<image_weight>& im)
: im_(exact(im))
{
init();
}
template <typename I, typename V>
inline
void
center_weight<I,V>::init()
{
center_ = literal::zero;
nsites_ = 0;
border_ = 0;
}
template <typename I, typename V>
inline
void
center_weight<I,V>::take(const argument& t)
{
center_ += (im_(t) * t.to_vec());
nsites_ += im_(t);
if (t[1] == 0)
border_ = 1;
if (static_cast<unsigned>(t[1]) == im_.ncols() - 1)
border_ = 2;
}
template <typename I, typename V>
inline
void
center_weight<I,V>::take(const center_weight<I,V>& other)
{
center_ += other.center_;
nsites_ += other.nsites_;
if (border_ == 0)
border_ = other.border_;
}
template <typename I, typename V>
inline
V
center_weight<I,V>::to_result() const
{
// mln_precondition(is_valid());
if (! is_valid())
return V();
return V(center_ / nsites_, border_);
}
template <typename I, typename V>
inline
center_weight<I,V>::operator P() const
{
return P(to_result());
}
template <typename I, typename V>
inline
bool
center_weight<I,V>::is_valid() const
{
return nsites_ > 0;
}
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::accu
} // end of namespace mln
#endif // ! MLN_ACCU_CENTER_WEIGHT_HH
#ifndef DIJKSTRA_HH
# define DIJKSTRA_HH
# include <algorithm>
# include <vector>
# include <mln/core/concept/graph.hh>
# include <mln/util/array.hh>
namespace mln
{
struct dijkstra_t
{
template <typename G, typename F>
void operator()(const Graph<G>& g_, const util::vertex_id_t source,
const F& distance_calc)
{
const G& g = exact(g_);
mln_assertion(source < g.v_nmax());
previous.reserve(g.v_nmax());
dist.reserve(g.v_nmax());
for(unsigned i = 0; i < g.v_nmax(); ++i)
{
dist[i] = -1;
previous[i] = -1;
}
dist[source] = 0;
std::set<util::vertex_id_t> vertices;
mln_vertex_iter(G) v(g);
for_all(v)
vertices.insert(v.id());
while (!vertices.empty())
{
unsigned best_vertice = *vertices.begin();
for (std::set<util::vertex_id_t>::const_iterator i = vertices.begin();
i != vertices.end();
++i)
if (dist[best_vertice] > dist[*i])
best_vertice = *i;
if (dist[best_vertice] == static_cast<unsigned>(-1))
break;
util::vertex<G> current_v = g.vertex(best_vertice);
vertices.erase(best_vertice);
for (unsigned i = 0; i < current_v.nmax_nbh_vertices(); ++i)
{
unsigned d = dist[current_v.id()] +
distance_calc(current_v.id(), current_v.ith_nbh_vertex(i),
current_v.ith_nbh_edge(i));
if (d < dist[current_v.ith_nbh_vertex(i)])
{
dist[current_v.ith_nbh_vertex(i)] = d;
previous[current_v.ith_nbh_vertex(i)] = current_v.id();
}
}
}
}
std::vector<int> previous;
std::vector<unsigned> dist;
};
dijkstra_t dijkstra;
}
#endif // !DIJKSTRA_HH
// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of the Olena Library. This library is free
// software; you can redistribute it and/or modify it under the terms
// of the GNU General Public License version 2 as published by the
// Free Software Foundation.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this library; see the file COPYING. If not, write to
// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
// Boston, MA 02111-1307, USA.
//
// As a special exception, you may use this file as part of a free
// software library without restriction. Specifically, if other files
// instantiate templates or use macros or inline functions from this
// file, or you compile this file and link it with other files to
// produce an executable, this file does not by itself cause the
// resulting executable to be covered by the GNU General Public
// License.
// reasons why the executable file might be covered by the GNU General
// Public License.
#ifndef MLN_MAKE_P_VERTICES_WITH_ACCU_HH
# define MLN_MAKE_P_VERTICES_WITH_ACCU_HH
/// \file mln/make/p_vertices_with_mass_centers.hh
///
/// Create a p_vertices using region mass centers as vertex site.
///
/// \sa vertex_image, p_vertices
# include <mln/core/concept/image.hh>
# include <mln/core/concept/graph.hh>
# include <mln/core/site_set/p_vertices.hh>
# include <mln/labeling/compute.hh>
# include <mln/accu/center.hh>
# include <mln/util/couple.hh>
# include <mln/fun/i2v/array.hh>
namespace mln
{
namespace make
{
/// Construct a p_vertices from a watershed image and a region adjacency
/// graph (RAG). Map each graph vertex with an accumulator on its
/// corresponding region.
///
/// \param wst_ A watershed image.
/// \param nbasins The number of basins.
/// \param g_ A region adjacency graph.
/// \param accumulator An accumulator to label vertices.
///
/// \return A p_vertices.
///
/// \sa edge_image, vertex_image, p_vertices, p_edges,
/// make::region_adjacency_graph
//
template <typename W, typename G, typename A>
inline
p_vertices<G, fun::i2v::array<mln_site(W)> >
p_vertices_with_with_accu(const Image<W>& wst_,
const mln_value(W)& nbasins,
const Graph<G>& g_,
const A& accumulator);
# ifndef MLN_INCLUDE_ONLY
template <typename W, typename G, typename A>
inline
p_vertices<G, fun::i2v::array<util::couple<mln_site(W), int> > >
p_vertices_with_accu(const Image<W>& wst_,
const mln_value(W)& nbasins,
const Graph<G>& g_,
const A& accumulator)
{
trace::entering("make::p_vertices_with_accu");
const W& wst = exact(wst_);
const G& g = exact(g_);
mln_precondition(wst.is_valid());
mln_precondition(g.is_valid());
typedef mln_site(W) P;
typedef fun::i2v::array<util::couple<P, int> > vertex_sites_t;
vertex_sites_t vertex_sites;
convert::from_to(labeling::compute(accumulator, wst, nbasins),
vertex_sites);
p_vertices<G, vertex_sites_t> pv(g, vertex_sites);
trace::exiting("make::p_vertices_with_accu");
return pv;
}
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::make
} // end of namespace mln
#endif // ! MLN_MAKE_P_VERTICES_WITH_ACCU_HH
#include <iostream>
# include <cstdlib> // rand
# include <ctime> // rand
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
#include "rag.hh"
void usage(char* name)
{
std::cerr << "usage: " << name << " <source.pgm>" << std::endl;
exit(1);
}
int main(int argc, char* argv[])
{
if (argc != 2)
usage(argv[0]);
// mln::Image<E>
srand(time(0));
using namespace mln;
using value::int_u8;
image2d<int_u8> input;
io::pgm::load(input, argv[1]);
io::pgm::save(rag(input), "out.pgm");
}
# include <iostream>
# include <cstdlib> // rand
# include <numeric>
# include <mln/io/ppm/save.hh>
# include <mln/core/concept/image.hh>
# include <mln/core/image/image2d.hh>
# include <mln/core/alias/window2d.hh>
# include <mln/core/alias/neighb2d.hh>
# include <mln/value/int_u8.hh>
# include <mln/value/label_8.hh>
# include <mln/value/label_16.hh>
# include <mln/morpho/watershed/flooding.hh>
# include <mln/morpho/watershed/superpose.hh>
# include <mln/morpho/meyer_wst.hh>
# include <mln/morpho/closing/area.hh>
# include <mln/morpho/opening/area.hh>
# include <mln/morpho/elementary/gradient.hh>
# include <mln/level/transform.hh>
# include <mln/make/region_adjacency_graph.hh>
# include <mln/util/graph.hh>
# include <mln/core/site_set/p_vertices.hh>
# include <mln/core/var.hh>
# include <mln/fun/i2v/array.hh>
# include <mln/make/p_vertices_with_mass_centers.hh>
# include <mln/literal/grays.hh>
# include <mln/debug/draw_graph.hh>
# include <mln/draw/line.hh>
# include <mln/core/concept/function.hh>
# include <mln/util/array.hh>
# include <mln/util/couple.hh>
# include <mln/norm/l2.hh>
# include <mln/logical/not.hh>
# include "center_weight.hh"
# include "p_vertices_with_accu.hh"
# include <mln/core/image/extended.hh>
# include <mln/canvas/browsing/depth_first_search.hh>
# include "dijkstra.hh"
namespace mln
{
using value::int_u8;
using value::label_16;
typedef double distance_t;
typedef double angle_t;
typedef util::couple<distance_t, angle_t> edge_value_t;
template <typename T>
distance_t distance(T a, T b)
{
return (a[0] - b[0]) * (a[0] - b[0]) +
(a[1] - b[1]) * (a[1] - b[1]);
}
template <typename G, typename VV>
inline
p_edges<G, fun::i2v::array<edge_value_t> >
p_edges_for_lines(const Graph<G>& g_,
const VV& vertices_values)
{
trace::entering("make::p_edges_for_lines");
// const W& wst = exact(wst_);
const G& g = exact(g_);
mln_precondition(g.is_valid());
typedef fun::i2v::array<edge_value_t> edges_value_t;
edges_value_t edge_values(g.e_nmax());
mln_edge_iter(G) e(g);
for_all(e)
{
distance_t d = distance(vertices_values(e.v1()).first(), vertices_values(e.v2()).first());
distance_t y = std::abs(vertices_values(e.v1()).first()[0] -
vertices_values(e.v2()).first()[0]); // We lose genericity.
distance_t x = (vertices_values(e.v1()).first()[1] -
vertices_values(e.v2()).first()[1]);
// assert(x != 0);
angle_t a = std::abs(atan(y / (x + 1)));
edge_values(e.id()) = edge_value_t(d, a);
}
p_edges<G, edges_value_t> pe(g, edge_values);
trace::exiting("make::p_edges_for_lines");
return pe;
}
template <typename I, typename G, typename EV, typename VV>
void draw_edges(Image<I>& input_, const Graph<G>& g_,
const EV& edges_values, const VV& vertices_values)
{
I& input = exact(input_);
const G& g = exact(g_);
(void) edges_values;
mln_edge_iter(G) e(g);
for_all(e)
{
// int val = vertices_values(e.v1()).second() + vertices_values(e.v2()).second() + 1;
// std::cerr << edges_values.function()(e.id()).second() << std::endl;
// if (edges_values.function()(e.id()).second() < 0.7)
mln_VAR(val, edges_values.function()(e.id()));
int value = std::accumulate(val.begin(), val.end(), 0);
draw::line(input, vertices_values(e.v1()).first(),
vertices_values(e.v2()).first(), value + 1);
}
}
#define QRT(a) (a * a)
template <typename VV, typename EV>
struct dist_calc_t
{
dist_calc_t(const VV& vertices_values,
const EV& edges_values)