From c43643c84c96964f3f94d879ef53fdf51cdb8fc7 Mon Sep 17 00:00:00 2001 From: Benoit Sigoure Date: Mon, 10 Dec 2007 15:47:37 +0100 Subject: [PATCH] Enhance the interface of carve_seam. * configure.ac: Use BOOST_CONVERSION. * src/all.hh: Add some declarations. * src/seam.cc (accumulate_nrg): Fix a bug by properly using duplicate borders. (carve_vertical_seam): Rename as `find_vertical_seam'. (carve_vertical_seam, uncarve_vertical_seam): New. * src/seam_main.cc (main): Change the interface. Take 5 arguments and render the carved image and the image with the selected seams. Signed-off-by: Benoit Sigoure --- configure.ac | 1 + src/all.hh | 22 ++++++++++++++++++++ src/seam.cc | 63 ++++++++++++++++++++++++++++++++++++++++++++++++-------- src/seam_main.cc | 48 ++++++++++++++++++++++++++++++------------ 4 files changed, 112 insertions(+), 22 deletions(-) diff --git a/configure.ac b/configure.ac index 048de09..0260802 100644 --- a/configure.ac +++ b/configure.ac @@ -26,6 +26,7 @@ case $GXX in #( esac BOOST_REQUIRE([1.34]) +BOOST_CONVERSION BOOST_FOREACH AC_LANG_POP([C++])dnl diff --git a/src/all.hh b/src/all.hh index 8d08055..4bd5a1f 100644 --- a/src/all.hh +++ b/src/all.hh @@ -18,4 +18,26 @@ image2d get_nrg (const image2d& img); /// Compute the entropy in \a img using a 9x9 window. image2d get_entropy (const image2d& img); +/** Find a vertical seam in the image. The process only relies on the + * energy in the image. + * \param nrg The energy in the image. + * \return A vector with the points in the seam. Let \c c be the \c r th + * value in the vector. This means that the seam passes by the point + * (r, c) in the image. + */ +std::vector +find_vertical_seam (const image2d nrg); + +/** Carve a seam out of an image. + * \param img Image to modify. + * \param path Path of the seam to carve. + * \return \a img with the seam \a path carved out. + */ +template +image2d +carve_vertical_seam (const image2d img, const std::vector& path); + +image2d +uncarve_vertical_seam (const image2d img, const std::vector& path); + #endif /* !ALL_HH_ */ diff --git a/src/seam.cc b/src/seam.cc index 813504a..1a81cb6 100644 --- a/src/seam.cc +++ b/src/seam.cc @@ -2,8 +2,10 @@ #include #include +#include #include #include +#include #include "all.hh" @@ -29,6 +31,7 @@ image2d accumulate_nrg (const image2d nrg) { image2d accu (nrg.domain ()); + border::duplicate (nrg); unsigned cols = geom::ncols (nrg); unsigned rows = geom::nrows (nrg); @@ -110,18 +113,60 @@ find_path (const image2d accu_nrg) return seam_path; } -/** Find a vertical seam in the image. The process only relies on the - * energy in the image. - * \param nrg The energy in the image. - * \return A vector with the points in the seam. Let \c c be the \c r th - * value in the vector. This means that the seam passes by the point - * (r, c) in the image. - */ std::vector -carve_vertical_seam (const image2d nrg) +find_vertical_seam (const image2d nrg) { image2d accu_nrg = accumulate_nrg (nrg); - save (accu_nrg, "accu.pgm"); std::vector seam_path = find_path (accu_nrg); return seam_path; } + +template +image2d +carve_vertical_seam (const image2d img, const std::vector& path) +{ + unsigned cols = geom::ncols (img); + unsigned rows = geom::nrows (img); + image2d carved (rows, cols - 1); + typename image2d::fwd_piter p (img.domain ()); + + for (unsigned r = 0; r < rows; ++r) + { + unsigned seam_at_col = path.at (r); + for (unsigned c = 0; c < seam_at_col; ++c) + carved.at (r, c) = img.at (r, c); + for (unsigned c = seam_at_col; c < cols; ++c) + carved.at (r, c) = img.at (r, c + 1); + } + + return carved; +} + +// Instantiate for the types we use. +template image2d +carve_vertical_seam(const image2d img, + const std::vector& path); +template image2d +carve_vertical_seam(const image2d img, + const std::vector& path); + +image2d +uncarve_vertical_seam (const image2d img, const std::vector& path) +{ + unsigned cols = geom::ncols (img); + unsigned rows = geom::nrows (img); + image2d uncarved (rows, cols + 1); + image2d::fwd_piter p (img.domain ()); + + for (unsigned r = 0; r < rows; ++r) + { + unsigned seam_at_col = path.at (r); + for (unsigned c = 0; c < seam_at_col; ++c) + uncarved.at (r, c) = img.at (r, c); + uncarved.at (r, seam_at_col) = mln::literal::red; + for (unsigned c = seam_at_col; c < cols; ++c) + uncarved.at (r, c + 1) = img.at (r, c); + } + + return uncarved; +} diff --git a/src/seam_main.cc b/src/seam_main.cc index 010d63f..52bb941 100644 --- a/src/seam_main.cc +++ b/src/seam_main.cc @@ -1,37 +1,59 @@ #include +#include #include +#include #include #include -#include #include "all.hh" using namespace mln; using namespace mln::value; -std::vector -carve_vertical_seam (const image2d img); - /// \file Find a vertical seam in an image. int main (int argc, char** argv) { - if (argc != 3) + if (argc != 5) { - std::cerr << "usage: " << *argv << " in.ppm out.ppm\n"; + std::cerr << "usage: " << *argv << " N in.ppm carved.ppm seams.ppm\n" + "where N is an integer > 0: the number of seams to carve.\n"; return 1; } - image2d img = load (argv[1]); + unsigned nseam = 1; + + try { + nseam = boost::lexical_cast (argv[1]); + } + catch (const boost::bad_lexical_cast&) + { + std::cerr << "invalid 1st argument" << std::endl; + return 2; + } + + std::cerr << "initializing ... "; + image2d img = load (argv[2]); image2d nrg = get_nrg (img); - std::vector seam_path = carve_vertical_seam (nrg); - unsigned row = 0; - BOOST_FOREACH (unsigned col, seam_path) + std::stack > seams; + + for (unsigned i = 0; i < nseam; ++i) + { + std::cerr << (i + 1) << ".."; + seams.push (find_vertical_seam (nrg)); + img = carve_vertical_seam (img, seams.top ()); + nrg = carve_vertical_seam (nrg, seams.top ()); + } + std::cerr << '.'; + io::ppm::save (img, argv[3]); + for (unsigned i = 0; i < nseam; ++i) { - img.at (row, col) = literal::red; - ++row; + img = uncarve_vertical_seam (img, seams.top ()); + seams.pop (); } - io::ppm::save (img, argv[2]); + std::cerr << '.'; + io::ppm::save (img, argv[4]); + std::cerr << std::endl; } -- 2.11.4.GIT