/* -*- mia-c++  -*-
 *
 * This file is part of MIA - a toolbox for medical image analysis
 * Copyright (c) Leipzig, Madrid 1999-2017 Gert Wollny
 *
 * MIA is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 MIA; if not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <iomanip>
#include <mia/internal/plugintester.hh>
#include <mia/2d/filter/seededwatershed.hh>


using namespace mia;
using namespace std;

const unsigned char  seed[72] = {
       1, 0, 0, 0, 0, 0, 0, 0, 4,
       0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0,
       1, 0, 0, 0, 2, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0,
       0, 0, 0, 0, 0, 0, 3, 0, 0,
       0, 0, 0, 0, 0, 0, 0, 0, 0,
};


BOOST_AUTO_TEST_CASE ( test_seeded_watershead )
{
       const C2DBounds size(9, 8);
       const int image[72] = {
              1,   1,   1,   3,   4,   5,   5,   5,   5,
              0,   0,   0,   0,   4,   5,   5,   5,   5,
              0,   0,   0,   0,   4,   4,   4,   4,   4,
              0,   0,   0,   0,   1,   2,   5,   2,   2,
              1,   0,   0,   0,   1,   2,   5,   2,   2,
              0,   0,   0,   0,   2,   3,   3,   3,   2,
              0,   0,   0,   0,   3,   3,   3,   3,   3,
              0,   0,   0,   0,   3,   3,   3,   3,   3,
       };
       const unsigned char  test[72] = {
              1,   1,   1, 255,   4,   4,   4,   4,   4,
              1,   1,   1,   1, 255,   4,   4,   4,   4,
              1,   1,   1,   1, 255,   4,   4,   4, 255,
              1,   1,   1,   1, 255,   4,   4, 255,   3,
              1,   1,   1, 255,   2, 255,   4, 255,   3,
              1,   1,   1,   1, 255,   3, 255,   3,   3,
              1,   1,   1,   1, 255,   3,   3,   3,   3,
              1,   1,   1,   1, 255,   3,   3,   3,   3,
       };
       P2DImage seed_image(new C2DUBImage(size, seed));
       P2DImage input_image(new C2DSIImage(size, image));
       auto f = BOOST_TEST_create_from_plugin<C2DSeededWSFilterPlugin>("sws:seed=seed.@,n=4n,mark=1");
       save_image("seed.@", seed_image);
       auto result = f->filter(*input_image);
       BOOST_CHECK_EQUAL(result->get_size(), size);
       const C2DUBImage& r = dynamic_cast<const C2DUBImage&>(*result);
       auto ir = r.begin();
       auto t = test;

       for (size_t y = 0; y < size.y; ++y)
              for (size_t x = 0; x < size.x; ++x, ++t, ++ir) {
                     BOOST_CHECK_EQUAL(*ir, *t);
              }

       cvdebug() << "result \n";
       ir = r.begin();

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++ir) {
                     cverb << setw(3) << (int)*ir << ", ";
              }

              cverb << "\n";
       }

       cvdebug() << "test \n";
       t = test;

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++t) {
                     cverb << setw(8) << (int)*t << ", ";
              }

              cverb << "\n";
       }

       P2DImage grad = run_filter(*input_image, "gradnorm");
       const C2DFImage& fgrad = dynamic_cast<const C2DFImage&>(*grad);
       cvdebug() << "grad \n";
       auto g = fgrad.begin();

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++g) {
                     cverb << setw(8) << *g << ", ";
              }

              cverb << "\n";
       }
}


BOOST_AUTO_TEST_CASE ( test_seeded_watershead_from_grad )
{
       const C2DBounds size(9, 8);
       const float image[72] = {
              0.0,        0,      0.4,      0.6,      0.4,      0.2,        0,        0,        0,
              0.2,      0.2,      0.2,        1,        1, 0.282843,      0.2,      0.2,      0.2,
              0.0,        0,        0,      0.8,        1,      0.6,        0,      0.6,      0.6,
              0.2,        0,        0,      0.2,  0.72111, 0.894427,      0.2,  0.72111,      0.4,
              0.,       0.2,        0,      0.2, 0.447214, 0.824621,      0.4, 0.632456,        0,
              0.2,        0,        0,      0.4,  0.72111, 0.282843,      0.4, 0.282843,      0.2,
              0.0,        0,        0,      0.6, 0.632456,        0,        0,        0,      0.2,
              0.0,        0,        0,      0.6,      0.6,        0,        0,        0,        0
       };
       const unsigned char  test[72] = {
              1,   1,   1, 255,   4,   4,   4,   4,   4,
              1,   1,   1,   1, 255,   4,   4,   4,   4,
              1,   1,   1,   1, 255,   4,   4,   4, 255,
              1,   1,   1,   1, 255,   4,   4, 255,   3,
              1,   1,   1, 255,   2, 255,   4, 255,   3,
              1,   1,   1,   1, 255,   3, 255,   3,   3,
              1,   1,   1,   1, 255,   3,   3,   3,   3,
              1,   1,   1,   1, 255,   3,   3,   3,   3,
       };
       P2DImage seed_image(new C2DUBImage(size, seed));
       P2DImage input_image(new C2DFImage(size, image));
       auto f = BOOST_TEST_create_from_plugin<C2DSeededWSFilterPlugin>("sws:seed=seed.@,n=4n,mark=1,grad=1");
       save_image("seed.@", seed_image);
       auto result = f->filter(*input_image);
       BOOST_CHECK_EQUAL(result->get_size(), size);
       const C2DUBImage& r = dynamic_cast<const C2DUBImage&>(*result);
       auto ir = r.begin();
       auto t = test;

       for (size_t y = 0; y < size.y; ++y)
              for (size_t x = 0; x < size.x; ++x, ++t, ++ir) {
                     BOOST_CHECK_EQUAL(*ir, *t);
              }

       cvdebug() << "result \n";
       ir = r.begin();

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++ir) {
                     cverb << setw(3) << (int)*ir << ", ";
              }

              cverb << "\n";
       }

       cvdebug() << "test \n";
       t = test;

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++t) {
                     cverb << setw(8) << (int)*t << ", ";
              }

              cverb << "\n";
       }

       P2DImage grad = run_filter(*input_image, "gradnorm");
       const C2DFImage& fgrad = dynamic_cast<const C2DFImage&>(*grad);
       cvdebug() << "grad \n";
       auto g = fgrad.begin();

       for (size_t y = 0; y < size.y; ++y) {
              cvdebug() << "line " << y << ":";

              for (size_t x = 0; x < size.x; ++x, ++g) {
                     cverb << setw(8) << *g << ", ";
              }

              cverb << "\n";
       }
}

