--- milena/mln/inpainting/inpaint.hh | 98 +++++++++++++++++++++++ milena/mln/inpainting/lpde.hh | 146 ++++++++++++++++++++++++++++++++++ milena/mln/inpainting/metric/psnr.hh | 51 ++++++++++++ 3 files changed, 295 insertions(+), 0 deletions(-) create mode 100644 milena/mln/inpainting/inpaint.hh create mode 100644 milena/mln/inpainting/lpde.hh create mode 100644 milena/mln/inpainting/metric/psnr.hh
diff --git a/milena/mln/inpainting/inpaint.hh b/milena/mln/inpainting/inpaint.hh new file mode 100644 index 0000000..44f20a8 --- /dev/null +++ b/milena/mln/inpainting/inpaint.hh @@ -0,0 +1,98 @@ +#include <mln/core/image/dmorph/image_if.hh> + +#include <mln/data/fill.hh> +#include <mln/data/paste.hh> + +#include <mln/literal/colors.hh> + +#include <mln/core/alias/box2d.hh> +#include <mln/accu/shape/bbox.hh> +#include <mln/value/label_8.hh> +#include <mln/labeling/compute.hh> + +#include <mln/pw/value.hh> +#include <mln/draw/box.hh> + +#include <mln/util/timer.hh> + +namespace mln +{ + namespace inpainting + { + /* + * Interface + */ + + template <template <typename> class I, typename T, typename F> + I<T> inpaint(const Image<I<T> >& src_, + const Image<I<bool> >& mask_, + F inpaint_method, + unsigned inpaint_radius); + + /* + * Implem + */ + + template <template <typename> class I, typename T, typename F> + I<T> inpaint(const Image<I<T> >& inpaint_src_, + const Image<I<bool> >& inpaint_mask_, + F inpaint_method, + unsigned inpaint_radius) + { + const I<T>& inpaint_src = exact(inpaint_src_); + const I<bool>& inpaint_mask = exact(inpaint_mask_); + + box2d roi; + { // Compute the region of interest + Ivalue::label_8 lbl(inpaint_mask.domain()); + + data::fill(lbl, 1); + data::fill((lbl | pw::value(inpaint_mask)).rw(), 0); + + value::label_8 nlabels = 2; + + util::array<box2d> roi_bboxes = + labeling::compute(accu::meta::shape::bbox(), + lbl, + nlabels); + + roi = roi_bboxes[0]; + roi.enlarge(inpaint_radius); + roi.crop_wrt(inpaint_src.domain()); + } + + I<mln_sum(T)> new_src(roi); + { // paste inpaint_src to new_src + mln_piter(I<T>) p(roi); + mln_pixter(I<mln_sum(T)>) p_new(new_src); + + for_all_2(p, p_new) + p_new.val() = inpaint_src(p); + } + + I<bool> new_mask(roi); + data::paste(inpaint_mask | roi, new_mask); + + mln::util::timer t; + t.start(); + + inpaint_method(new_src, new_mask); + + t.stop(); + std::cout << "inpaint time = " << t << std::endl; + + I<T> output(inpaint_src); + { // paste new_src to output + mln_piter(I<T>) p(roi); + mln_pixter(const I<mln_sum(T)>) p_new(new_src); + + for_all_2(p, p_new) + output(p) = p_new.val(); + } + + return output; + } + + } /* mln::inpainting */ + +} /* mln*/ diff --git a/milena/mln/inpainting/lpde.hh b/milena/mln/inpainting/lpde.hh new file mode 100644 index 0000000..1f754d8 --- /dev/null +++ b/milena/mln/inpainting/lpde.hh @@ -0,0 +1,146 @@ +#include <algorithm> +#include <vector> + +#include <mln/core/image/dmorph/image_if.hh> + +#include <mln/data/fill.hh> +#include <mln/literal/colors.hh> +#include <mln/literal/zero.hh> + +#include <mln/linear/convolve.hh> +#include <mln/linear/gaussian.hh> +#include <mln/core/alias/w_window2d_float.hh> + +#include <mln/pw/value.hh> + +#include <mln/value/int_u.hh> +#include <mln/algebra/vec.hh> + +#include <mln/data/paste.hh> + +#include <mln/core/alias/vec2d.hh> + +namespace mln +{ + namespace inpainting + { + struct lpde + { + public: + lpde(float dt = 1.0f, float dx = 1.0f, float t_f = 20.0); + + template <template <typename> class I, typename T> + void operator()(I<T>& src, + I<bool>& mask); + + void set(const std::vector<float>& w); + + private: + std::vector<float> w; + float dt; + float dx; + float t_f; + }; + + lpde::lpde(float dt, float dx, float t_f) + { + this->dt = dt; + this->dx = dx; + this->t_f = t_f; + } + + template <typename I> + void compute_diff_invariants(const I& u, + std::vector<I>& invs, + const std::vector<float>& w) + { + const float sigma = 0.8; + + invs[0] = linear::gaussian_1st_derivative(u, sigma, 1); + invs[1] = linear::gaussian_1st_derivative(u, sigma, 0); + invs[2] = linear::gaussian_2nd_derivative(u, sigma, 1); + invs[3] = linear::gaussian_2nd_derivative(u, sigma, 0); + invs[4] = linear::gaussian_2nd_derivative(u, sigma); + + { // TV regularization term div ( \nabla u / | \nabla u | ) + + I u_xnx( invs[5].domain() ); + I u_yny( invs[5].domain() ); + + { + mln_piter(I) p( invs[5].domain() ); + + for_all(p) + { + for (unsigned i = 0; i < mln_dim(mln_value(I)); ++i) + { + float norm; + { + vec2d_f v; + + v[0] = invs[0](p)[i]; + v[1] = invs[1](p)[i]; + + norm = norm::l2(v); + } + + u_xnx(p)[i] = invs[0](p)[i] / norm; + u_yny(p)[i] = invs[1](p)[i] / norm; + } + } + } + + u_xnx = linear::gaussian_1st_derivative(u_xnx, sigma, 1); + u_yny = linear::gaussian_1st_derivative(u_yny, sigma, 0); + + mln_piter(I) p( invs[5].domain() ); + for_all(p) + { + invs[5](p) = u_xnx(p) + u_yny(p); + } + } + } + + template <template <typename> class I, typename T> + void lpde::operator()(I<T>& src, + I<bool>& mask) + { + + data::fill((src | pw::value(mask)).rw(), literal::zero); + + std::vector<I<T> > invs(w.size(), src.domain()); + + I<T>& u_t = src; + + float r = this->dt / (this->dx * this->dx); + + for (float t = 0; t < this->t_f; t += dt) + { + compute_diff_invariants(u_t, invs, this->w); + + mln_piter(I<T>) p(u_t.domain()); + + for_all(p) + { + if (mask(p)) + { + T contribution = literal::zero; + + for (unsigned k = 0; k < w.size(); ++k) + { + contribution += this->w[k] * invs[k](p); + } + + u_t(p) += r * contribution; + } + } + } + } + + void lpde::set(const std::vector<float>& w) + { + this->w = w; + } + } /* mln::inpainting */ + +} /* mln*/ diff --git a/milena/mln/inpainting/metric/psnr.hh b/milena/mln/inpainting/metric/psnr.hh new file mode 100644 index 0000000..4998b4a --- /dev/null +++ b/milena/mln/inpainting/metric/psnr.hh @@ -0,0 +1,51 @@ +#ifndef MLN_INPAINTING_METRIC_PSNR_HH +# define MLN_INPAINTING_METRIC_PSNR_HH + +# include <cmath> + +# include <mln/core/concept/image.hh> +# include <mln/norm/l1.hh> +# include <mln/trait/value_.hh> +# include <mln/algebra/vec.hh> + +namespace mln +{ + namespace inpainting + { + namespace metric + { + template <typename I> + double psnr(const Image<I>& original_, + const Image<I>& altered_) + { + const I& original = exact(original_); + const I& altered = exact(altered_); + + mln_piter(I) p( altered.domain() ); + + double mse = 0; + + const unsigned dim = mln_dim(mln_value(I)); + + for_all(p) + { + const mln_sum(mln_value(I)) diff = original(p) - altered(p); + + if (dim == 1) + mse += diff * diff; + else + for (unsigned i = 0; i < dim; ++i) + mse += diff[i] * diff[i]; + } + + mse /= ( altered.ncols() * altered.nrows() * dim); + + const unsigned max = pow(2, mln_nbits(mln_value(I)) / dim) - 1; + + return 20 * log10( max ) - 10 * log10(mse); + } + } + } +} + +#endif