/* -*- 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 <mia/internal/plugintester.hh>
#include <mia/2d/filter/sepconv.hh>


NS_MIA_USE
using namespace std;
using namespace ::boost;
using namespace ::boost::unit_test;
namespace bfs =::boost::filesystem;
using namespace SeparableConvolute_2dimage_filter;

struct  SepconvTextFixture {
       SepconvTextFixture();

       void run(const C2DFilter& f) const;
       P2DImage image;
};

SepconvTextFixture::SepconvTextFixture()
{
       C2DFImage *src = new C2DFImage(C2DBounds(3, 3));
       fill(src->begin(), src->end(), 0);
       (*src)(1, 1) = 16.0f;
       image.reset(src);
}

void SepconvTextFixture::run(const C2DFilter& f) const
{
       const float gauss_ref[9] = {
              1, 2, 1, /**/ 2, 4, 2, /**/ 1, 2, 1
       };
       P2DImage result = f.filter(*image);
       BOOST_CHECK_EQUAL(result->get_size(), image->get_size());
       C2DFImage *r = dynamic_cast<C2DFImage *>(&*result);
       BOOST_REQUIRE(r);
       int j = 0;

       for (C2DFImage::const_iterator i = r->begin(); i != r->end(); ++i, ++j) {
              cvdebug() << *i << " vs  " << gauss_ref[j] << "\n";
              BOOST_CHECK_CLOSE(*i, gauss_ref[j], 0.0001);
       }
}

BOOST_FIXTURE_TEST_CASE( test_sepconv, SepconvTextFixture )
{
       auto filter = BOOST_TEST_create_from_plugin<C2DSeparableConvoluteFilterPlugin>("sepconv:kx=[gauss:w=1],ky=[gauss:w=1]");
       run(*filter);
}

BOOST_FIXTURE_TEST_CASE( test_gauss, SepconvTextFixture )
{
       auto filter = BOOST_TEST_create_from_plugin<C2DGaussFilterPlugin>("gauss:w=1");
       run(*filter);
}

BOOST_AUTO_TEST_CASE( test_sobel_x )
{
       auto sobel_x = BOOST_TEST_create_from_plugin<C2DSobelFilterPlugin>("sobel:dir=x");
       const float in_image[] = {
              1, 2, 3, 4,
              2, 3, 2, 5,
              6, 7, 8, 9,
              5, 4, 6, 3,
              6, 7, 8, 3
       };
       const float test_image[] = {
              0, 0.75,    1, 0,
              0, 0.5,    1, 0,
              0, 2.5 / 4,      0.625, 0,
              0, 0.75, -0.5, 0,
              0, 3.5 / 4, -6.5 / 4, 0
       };
       C2DFImage src(C2DBounds(4, 5), in_image);
       auto filtered = sobel_x->filter(src);
       const C2DFImage& f = dynamic_cast<const C2DFImage&>(*filtered);
       BOOST_CHECK_EQUAL(f.get_size(), src.get_size());
       const float *t = test_image;

       for (auto i = f.begin(); i != f.end(); ++i, ++t) {
              cvdebug() << *i << " " << *t << "\n";
              BOOST_CHECK_CLOSE(*i, *t, 0.1);
       }
}

BOOST_AUTO_TEST_CASE( test_sobel_y )
{
       auto sobel_y = BOOST_TEST_create_from_plugin<C2DSobelFilterPlugin>("sobel:dir=y");
       const float in_image[] = {
              1, 2, 6, 5, 6,
              2, 3, 7, 4, 7,
              3, 2, 8, 6, 8,
              4, 5, 9, 3, 3
       };
       const float test_image[] = {
              0,  0,  0,  0,  0,
              0.75, 0.5, 2.5 / 4, 0.75, 3.5 / 4,
              1, 1, 0.625, -0.5, -6.5 / 4,
              0,  0,  0,  0,  0
       };
       C2DFImage src(C2DBounds(5, 4), in_image);
       auto filtered = sobel_y->filter(src);
       const C2DFImage& f = dynamic_cast<const C2DFImage&>(*filtered);
       BOOST_CHECK_EQUAL(f.get_size(), src.get_size());
       const float *t = test_image;

       for (auto i = f.begin(); i != f.end(); ++i, ++t) {
              cvdebug() << *i << " " << *t << "\n";
              BOOST_CHECK_CLOSE(*i, *t, 0.1);
       }
}


BOOST_AUTO_TEST_CASE( test_scharr_x )
{
       auto scharr_x = BOOST_TEST_create_from_plugin<C2DScharrFilterPlugin>("scharr:dir=x");
       const float in_image[] = {
              1, 2, 3, 4,
              2, 3, 2, 5,
              6, 7, 8, 9,
              5, 4, 6, 3,
              6, 7, 8, 3
       };
       const float test_image[] = {
              0, .625, 1, 0,
              0, .375, 1, 0,
              0, .71875, .71875, 0,
              0, .6875, -0.5, 0,
              0, .8125, -1.4375, 0
       };
       C2DFImage src(C2DBounds(4, 5), in_image);
       auto filtered = scharr_x->filter(src);
       const C2DFImage& f = dynamic_cast<const C2DFImage&>(*filtered);
       BOOST_CHECK_EQUAL(f.get_size(), src.get_size());
       const float *t = test_image;

       for (auto i = f.begin(); i != f.end(); ++i, ++t) {
              cvdebug() << *i << " " << *t << "\n";
              BOOST_CHECK_CLOSE(*i, *t, 0.1);
       }
}

BOOST_AUTO_TEST_CASE( test_scharr_y )
{
       auto scharr_y = BOOST_TEST_create_from_plugin<C2DScharrFilterPlugin>("scharr:dir=y");
       const float in_image[] = {
              1, 2, 6, 5, 6,
              2, 3, 7, 4, 7,
              3, 2, 8, 6, 8,
              4, 5, 9, 3, 3
       };
       const float test_image[] = {
              0,  0,  0,  0,  0,
              .625, 0.375, 0.71875, 0.6875, 0.8125,
              1, 1, 0.71875, -0.5, -1.4375,
              0,  0,  0,  0,  0
       };
       C2DFImage src(C2DBounds(5, 4), in_image);
       auto filtered = scharr_y->filter(src);
       const C2DFImage& f = dynamic_cast<const C2DFImage&>(*filtered);
       BOOST_CHECK_EQUAL(f.get_size(), src.get_size());
       const float *t = test_image;

       for (auto i = f.begin(); i != f.end(); ++i, ++t) {
              cvdebug() << *i << " " << *t << "\n";
              BOOST_CHECK_CLOSE(*i, *t, 0.1);
       }
}





