Commit 412967e0 authored by Vivien Delmon's avatar Vivien Delmon
Browse files

Two algorithms implemented during my internship in GE.

	* delmon/growcut/Makefile: New.
	* delmon/growcut/README: New.
	* delmon/growcut/check.sh: New.
	* delmon/growcut/keep_color.cc: New.
	* delmon/growcut/main.cc: New.
	* delmon/growcut/main_bw.cc: New.
	* delmon/growcut/remove_if_blue.cc: New.
	* delmon/growcut: New.
	* delmon/minsurf/Makefile: New.
	* delmon/minsurf/README: New.
	* delmon/minsurf/check.sh: New.
	* delmon/minsurf/keep_object.cc: New.
	* delmon/minsurf/main.cc: New.
	* delmon/minsurf: New.
	* delmon: New.

git-svn-id: https://svn.lrde.epita.fr/svn/oln/trunk@3476 4aad255d-cdde-0310-9447-f3009e2ae8c0
parent 9b05847c
2009-03-04 Vivien Delmon <vivien.delmon@lrde.epita.fr>
Two algorithms implemented during my internship in GE.
* delmon/growcut/Makefile: New.
* delmon/growcut/README: New.
* delmon/growcut/check.sh: New.
* delmon/growcut/keep_color.cc: New.
* delmon/growcut/main.cc: New.
* delmon/growcut/main_bw.cc: New.
* delmon/growcut/remove_if_blue.cc: New.
* delmon/growcut: New.
* delmon/minsurf/Makefile: New.
* delmon/minsurf/README: New.
* delmon/minsurf/check.sh: New.
* delmon/minsurf/keep_object.cc: New.
* delmon/minsurf/main.cc: New.
* delmon/minsurf: New.
* delmon: New.
2009-03-04 Guillaume Lazzara <z@lrde.epita.fr>
Cleanup IGR's code.
......
all: growcut remove_if_blue growcut_bw keep_color
growcut: main.cc
g++ -O2 -DNDEBUG -I ../../.. main.cc -o growcut
growcut_bw: main_bw.cc
g++ -O2 -DNDEBUG -I ../../.. main_bw.cc -o growcut_bw
remove_if_blue:
g++ -O2 -DNDEBUG -I ../../.. remove_if_blue.cc -o remove_if_blue
keep_color: keep_color.cc
g++ -O2 -DNDEBUG -DCOLOR=255 -I ../../.. keep_color.cc -o keep_white
g++ -O2 -DNDEBUG -DCOLOR=70 -I ../../.. keep_color.cc -o keep_grey
g++ -O2 -DNDEBUG -DCOLOR=1 -I ../../.. keep_color.cc -o keep_black
debug:
g++ -g3 -ggdb3 -I ../../.. main.cc -o growcut
check: growcut_bw keep_color
./check.sh
clean:
rm -rf obj
rm -rf remove_if_blue
rm -rf growcut
rm -rf growcut_bw
rm -rf keep_white
rm -rf keep_grey
rm -rf keep_black
Grow-Cut algorithm :
http://graphics.cs.msu.ru/en/research/Segment/index.html
Usage: ./growcut image.ppm image_seed.ppm labeled.ppm
Usage: ./growcut_bw image.pgm image_seed.pgm labeled.pgm
Input :
image.ppm : image you want to label.
image_seed.ppm : image you want to label + seed for the algorithm.
Output :
labeled.ppm : labeled image that keeps colors used in the image_seed.
#! /bin/sh
for i in sel/*; do
BASENAME=`echo $i | cut -d '_' -f 1 | cut -d '/' -f 2`
NUMBER=`echo $i | cut -d '_' -f 2`
OCOLOR=`echo $i | cut -d '_' -f 3`
echo ${BASENAME}_${NUMBER}
./growcut_bw img/${BASENAME}.pgm $i res/${BASENAME}_${NUMBER}_r.pgm
if [ "x$OCOLOR" = "xw" ] ; then
./keep_white img/${BASENAME}.pgm res/${BASENAME}_${NUMBER}_r.pgm ext/${BASENAME}_${NUMBER}_e.pgm
elif [ "x$OCOLOR" = "xg" ] ; then
./keep_grey img/${BASENAME}.pgm res/${BASENAME}_${NUMBER}_r.pgm ext/${BASENAME}_${NUMBER}_e.pgm
elif [ "x$OCOLOR" = "xb" ] ; then
./keep_black img/${BASENAME}.pgm res/${BASENAME}_${NUMBER}_r.pgm ext/${BASENAME}_${NUMBER}_e.pgm
fi
done
#include <mln/core/image/image2d.hh>
#include <mln/io/pgm/all.hh>
#include <mln/value/all.hh>
int main (int argc, char ** argv)
{
using namespace mln;
if (argc != 4)
return 1;
std::string file_in = argv[1];
std::string file_sel = argv[2];
std::string file_out = argv[3];
image2d<value::int_u8> in;
io::pgm::load (in, file_in);
image2d<value::int_u8> sel;
io::pgm::load (sel, file_sel);
image2d<value::int_u8> out;
initialize(out, in);
mln_piter_(image2d<value::int_u8>) p(in.domain());
for_all (p)
if (sel(p) == COLOR)
out(p) = in(p);
else
out(p) = 255 - COLOR;
mln::io::pgm::save (out, file_out);
return 0;
}
//
// main.cc for proto_growcut
// Made by Vivien Delmon
//
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Includes
#include <mln/core/image/image2d.hh>
#include <mln/core/alias/neighb2d.hh>
#include <mln/io/pgm/all.hh>
#include <mln/io/ppm/all.hh>
#include <mln/value/all.hh>
#include <mln/data/paste.hh>
#include <map>
#include <stack>
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Implementation
namespace mln
{
namespace value
{
namespace internal
{
// Since I have no hash_map available on my computer I define an
// arbitrary operator< on rgb8 to use a map
bool
operator<(const mln::value::rgb8& a, const mln::value::rgb8& b)
{
if (a.red() != b.red())
return (a.red() < b.red());
if (a.green() != b.green())
return (a.green() < b.green());
if (a.blue() != b.blue())
return (a.blue() < b.blue());
return (false);
}
}
}
}
inline
float
g (mln::value::rgb8& p, mln::value::rgb8& n)
{
return (1 - std::sqrt((p.red() - n.red()) * (p.red() - n.red()) +
(p.green() - n.green()) * (p.green() - n.green()) +
(p.blue() - n.blue()) * (p.blue() - n.blue())) /
442.0f);
}
int
main (int argc, char** argv)
{
using namespace mln;
typedef std::map<value::rgb8, value::int_u8> color_to_label_t;
typedef std::map<value::int_u8, value::rgb8> label_to_color_t;
if (argc != 4)
{
std::cerr << "Usage: " << argv[0] << " image.ppm image_seed.ppm labeled.ppm" << std::endl;
return 1;
}
// file_in is the colored image we want to segment.
std::string file_in = argv[1];
// file_seed is the same image as file_in with seeds for areas of interest colored.
// For instance blue for background and red for the object we want to segment.
// If we want to segment more than one object we can use up to 255 colors.
std::string file_seed = argv[2];
// file_out is a colored image that represent the different objects with the color
// of their seeds.
std::string file_out = argv[3];
// Initialisations
image2d<value::rgb8> in;
io::ppm::load (in, file_in);
image2d<value::rgb8> seed;
io::ppm::load (seed, file_seed);
image2d<value::int_u8> label;
initialize(label, in);
image2d<float> teta;
initialize(teta, in);
value::int_u8 nb_label = 1;
color_to_label_t color_to_label;
label_to_color_t label_to_color;
mln_piter_(image2d<value::rgb8>) p(in.domain());
for_all (p)
if (in(p) == seed(p))
{
label(p) = 0;
teta(p) = 0;
}
else
{
color_to_label_t::iterator it = color_to_label.find(seed(p));
if (it == color_to_label.end())
{
it = color_to_label.insert(color_to_label_t::value_type(seed(p), nb_label)).first;
label_to_color[nb_label] = seed(p);
nb_label++;
}
label(p) = it->second;
teta(p) = 1;
}
// Main Loop
mln_niter_(neighb2d) n(c4(), p);
// The to_do stack stores actions needed to go from rank n to n + 1.
std::stack<std::pair<point2d, std::pair<value::int_u8, float> > > to_do;
do
{
while (!to_do.empty())
{
label(to_do.top().first) = to_do.top().second.first;
teta(to_do.top().first) = to_do.top().second.second;
to_do.pop();
}
for_all (p)
for_all (n)
if (label(p) != label(n))
{
float s = g(in(p), in(n));
if (s * teta(n) > teta(p))
to_do.push(std::make_pair(p, std::make_pair(label(n), s * teta(n))));
}
}
while (!to_do.empty());
// Save labels
image2d<value::rgb8> out;
initialize(out, in);
for_all (p)
if (label(p) != 0)
out(p) = label_to_color[label(p)];
else
out(p) = value::rgb8(0,0,0);
mln::io::ppm::save (out, file_out);
return 0;
}
//
// main.cc for proto_growcut
// Made by Vivien Delmon
//
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Includes
#include <mln/core/image/image2d.hh>
#include <mln/core/alias/neighb2d.hh>
#include <mln/io/pgm/all.hh>
#include <mln/value/all.hh>
#include <map>
#include <stack>
//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Implementation
inline
float
g (mln::value::int_u8& p, mln::value::int_u8& n)
{
return (1.f - std::abs(p - n) / 255.f);
}
int
main (int argc, char** argv)
{
using namespace mln;
if (argc != 4)
{
std::cerr << "Usage: " << argv[0] << " image.pgm image_seed.pgm labeled.pgm" << std::endl;
return 1;
}
// file_in is the colored image we want to segment.
std::string file_in = argv[1];
// file_seed is the same image as file_in with seeds for areas of interest colored.
// For instance blue for background and red for the object we want to segment.
// If we want to segment more than one object we can use up to 255 colors.
std::string file_seed = argv[2];
// file_out is a colored image that represent the different objects with the color
// of their seeds.
std::string file_out = argv[3];
// Initialisations
image2d<value::int_u8> in;
io::pgm::load (in, file_in);
image2d<value::int_u8> seed;
io::pgm::load (seed, file_seed);
image2d<value::int_u8> label;
initialize(label, in);
image2d<float> teta;
initialize(teta, in);
value::int_u8 nb_label = 1;
mln_piter_(image2d<value::rgb8>) p(in.domain());
for_all (p)
if (in(p) == seed(p))
{
label(p) = 0;
teta(p) = 0;
}
else
{
label(p) = seed(p);
teta(p) = 1;
}
// Main Loop
mln_niter_(neighb2d) n(c4(), p);
// The to_do stack stores actions needed to go from rank n to n + 1.
std::stack<std::pair<point2d, std::pair<value::int_u8, float> > > to_do;
do
{
while (!to_do.empty())
{
label(to_do.top().first) = to_do.top().second.first;
teta(to_do.top().first) = to_do.top().second.second;
to_do.pop();
}
for_all (p)
for_all (n)
if (label(p) != label(n))
{
float s = g(in(p), in(n));
if (s * teta(n) > teta(p))
to_do.push(std::make_pair(p, std::make_pair(label(n), s * teta(n))));
}
}
while (!to_do.empty());
// Save labels
image2d<value::int_u8> out;
initialize(out, in);
for_all (p)
if (label(p) != 0)
out(p) = label(p);
else
out(p) = 0;
mln::io::pgm::save (out, file_out);
return 0;
}
#include <mln/core/image/image2d.hh>
#include <mln/io/ppm/all.hh>
#include <mln/value/all.hh>
int main (int argc, char ** argv)
{
using namespace mln;
if (argc != 4)
return 1;
std::string file_in = argv[1];
std::string file_sel = argv[2];
std::string file_out = argv[3];
image2d<value::rgb8> in;
io::ppm::load (in, file_in);
image2d<value::rgb8> sel;
io::ppm::load (sel, file_sel);
image2d<value::rgb8> out;
initialize(out, in);
mln_piter_(image2d<value::rgb8>) p(in.domain());
for_all (p)
if (sel(p) == value::rgb8(0, 0, 255))
out(p) = value::rgb8(0, 0, 0);
else
out(p) = in(p);
mln::io::ppm::save (out, file_out);
return 0;
}
all: minsurf keep_object
minsurf: main.cc
g++ -O2 -DNDEBUG -I ../../.. main.cc -o minsurf
keep_object: keep_object.cc
g++ -O2 -DNDEBUG -I ../../.. keep_object.cc -o keep_object
debug:
g++ -g3 -ggdb3 -I ../../.. main.cc -o minsurf
check: minsurf keep_object
./check.sh
clean:
rm -rf keep_object
rm -rf minsurf
Minimal Surface by Continuous Maximal Flow algorithm:
www.cmis.csiro.au/Hugues.Talbot/dicta2003/cdrom/pdf/0987.pdf
Usage: ./minsurf image.pgm image_seed.pgm binarised.pbm
Input :
image.pgm : image you want to binarise.
image_seed.pgm : image you want to binarise + seed for the algorithm.
Output :
binarised.pbm : binarised image.
#! /bin/sh
for i in *; do
BASENAME=`echo $i | cut -d '_' -f 1 | cut -d '/' -f 2`
NUMBER=`echo $i | cut -d '_' -f 2`
echo ${BASENAME}_${NUMBER}
./minsurf img/${BASENAME}.pgm $i res/${BASENAME}_${NUMBER}_r.pgm
./keep_object img/${BASENAME}.pgm res/${BASENAME}_${NUMBER}_r.pgm ext/${BASENAME}_${NUMBER}_e.pgm
done
#include <mln/core/image/image2d.hh>
#include <mln/io/pgm/all.hh>
#include <mln/io/pbm/all.hh>
#include <mln/value/all.hh>
int main(int argc, char** argv)
{
using namespace mln;
image2d<value::int_u8> input;
io::pgm::load(input, argv[1]);
image2d<bool> objects;
initialize(objects, input);
io::pbm::load(objects, argv[2]);
image2d<value::int_u8> output;
initialize(output, input);
mln_piter_(image2d<value::int_u8>) p(input.domain());
for_all (p)
if (objects(p))
output(p) = input(p);
else
output(p) = 0;
io::pgm::save(output, argv[3]);
return 0;
}
/*!
** \file main.cc
** \author Vivien Delmon
**
** \brief Implementation of Globally Minimal Surfaces
** by Continuous Maximal Flows
*/
#include <mln/core/var.hh>
#include <mln/core/image/image2d.hh>
#include <mln/core/image/image_if.hh>
#include <mln/core/alias/neighb2d.hh>
#include <mln/core/routine/extend.hh>
#include <mln/io/pgm/all.hh>
#include <mln/io/pbm/all.hh>
#include <mln/value/all.hh>
#include <mln/morpho/gradient.hh>
#include <algorithm>
#define DELTA 0.7f // DELTA must be inferior to 1/sqrt(dimension)
#define GAMMA 0.03f
#define MU 0.96f
/*!
** \author Vivien Delmon
** \brief Return true if p represent a vertical edge and false otherwise
**
** \param p [mln::point2d]
**
** \retval bool
*/
inline
bool
is_vedge(const mln::point2d& p)
{
return (!(p.row() % 2) && p.col() % 2);
}
/*!
** \author Vivien Delmon
** \brief Return true if p represent an horizontal edge and false otherwise
**
** \param p [mln::point2d]
**
** \retval bool
*/
inline
bool
is_hedge(const mln::point2d& p)
{
return (p.row() % 2 && !(p.col() % 2));
}
/*!
** \author Vivien Delmon
** \brief Return true if p represent a potential
**
** \param p [mln::point2d]
**
** \retval bool
*/
inline
bool
is_potential(const mln::point2d& p)
{
return (p.row() % 2 && p.col() % 2);
}
/*!
** \author Vivien Delmon
** \brief Return true if f is inf GAMMA or sup 1 - GAMMA
**
** \param f
**
** \retval bool
*/
inline
bool
is_stable(float f)
{
return (f <= GAMMA || f >= 1.f - GAMMA);
}
/*!
** \author Vivien Delmon
** \brief Return the euclidean distance between two point2d
**
** \param a
** \param b
**
** \retval float
*/
float distance(const mln::point2d& a,
const mln::point2d& b)
{
int row = a.row() - b.row();
int col = a.col() - b.col();
return (std::sqrt(row * row - col * col));
}
/*!
** \author Vivien Delmon
** \struct g_functor : mln::Function_v2v< g_functor >
** \brief Functor that inverts an int_u8 and return a float
*/
struct g_functor : mln::Function_v2v< g_functor >
{
typedef float result;
g_functor(result epsilon)
: epsilon_(epsilon)
{
}
result operator()(mln::value::int_u8 i) const
{
return 1.0f / (1 + i) + epsilon_;
}
private:
result epsilon_;