Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / gil / extension / numeric / algorithm.hpp
index 56ab8df..bbe0eab 100644 (file)
@@ -1,5 +1,6 @@
 //
 // Copyright 2005-2007 Adobe Systems Incorporated
+// Copyright 2019 Pranam Lashkari <plashkari628@gmail.com>
 //
 // Distributed under the Boost Software License, Version 1.0
 // See accompanying file LICENSE_1_0.txt or copy at
 
 #include <boost/gil/metafunctions.hpp>
 #include <boost/gil/pixel_iterator.hpp>
+#include <boost/gil/image.hpp>
 
 #include <boost/assert.hpp>
 
 #include <algorithm>
 #include <iterator>
 #include <numeric>
+#include <type_traits>
 
 namespace boost { namespace gil {
 
-/// \brief Returns the reference proxy associated with a type that has a \p "reference" member type alias.
+/// \brief Reference proxy associated with a type that has a \p "reference" member type alias.
 ///
-/// The reference proxy is the reference type, but with stripped-out C++ reference. It models PixelConcept
+/// The reference proxy is the reference type, but with stripped-out C++ reference.
+/// Models PixelConcept.
 template <typename T>
-struct pixel_proxy : public remove_reference<typename T::reference> {};
+struct pixel_proxy : std::remove_reference<typename T::reference> {};
 
 /// \brief std::for_each for a pair of iterators
-template <typename Iterator1,typename Iterator2,typename BinaryFunction>
-BinaryFunction for_each(Iterator1 first1,Iterator1 last1,Iterator2 first2,BinaryFunction f) {
-    while(first1!=last1)
-        f(*first1++,*first2++);
+template <typename Iterator1, typename Iterator2, typename BinaryFunction>
+BinaryFunction for_each(Iterator1 first1, Iterator1 last1, Iterator2 first2, BinaryFunction f)
+{
+    while (first1 != last1)
+        f(*first1++, *first2++);
     return f;
 }
 
-template <typename SrcIterator,typename DstIterator>
-inline DstIterator assign_pixels(SrcIterator src,SrcIterator src_end,DstIterator dst) {
-    for_each(src,src_end,dst,pixel_assigns_t<typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
-                                             typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type>());
-    return dst+(src_end-src);
+template <typename SrcIterator, typename DstIterator>
+inline
+auto assign_pixels(SrcIterator src, SrcIterator src_end, DstIterator dst) -> DstIterator
+{
+    for_each(src, src_end, dst,
+        pixel_assigns_t
+        <
+            typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type,
+            typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type
+        >());
+    return dst + (src_end - src);
 }
 
 namespace detail {
+
 template <std::size_t Size>
-struct inner_product_k_t {
-    template <class _InputIterator1, class _InputIterator2, class _Tp,
-              class _BinaryOperation1, class _BinaryOperation2>
-    static _Tp apply(_InputIterator1 __first1,
-                     _InputIterator2 __first2, _Tp __init,
-                     _BinaryOperation1 __binary_op1,
-                     _BinaryOperation2 __binary_op2) {
-        __init = __binary_op1(__init, __binary_op2(*__first1, *__first2));
-        return inner_product_k_t<Size-1>::template apply(__first1+1,__first2+1,__init,
-                                                         __binary_op1, __binary_op2);
+struct inner_product_k_t
+{
+    template
+    <
+        class InputIterator1,
+        class InputIterator2,
+        class T,
+        class BinaryOperation1,
+        class BinaryOperation2
+    >
+    static T apply(
+        InputIterator1 first1,
+        InputIterator2 first2, T init,
+        BinaryOperation1 binary_op1,
+        BinaryOperation2 binary_op2)
+    {
+        init = binary_op1(init, binary_op2(*first1, *first2));
+        return inner_product_k_t<Size - 1>::template apply(
+            first1 + 1, first2 + 1, init, binary_op1, binary_op2);
     }
 };
 
 template <>
-struct inner_product_k_t<0> {
-    template <class _InputIterator1, class _InputIterator2, class _Tp,
-              class _BinaryOperation1, class _BinaryOperation2>
-    static _Tp apply(_InputIterator1 __first1,
-                     _InputIterator2 __first2, _Tp __init,
-                     _BinaryOperation1 __binary_op1,
-                     _BinaryOperation2 __binary_op2) {
-        return __init;
+struct inner_product_k_t<0>
+{
+    template
+    <
+        class InputIterator1,
+        class InputIterator2,
+        class T,
+        class BinaryOperation1,
+        class BinaryOperation2
+    >
+    static T apply(
+        InputIterator1 first1,
+        InputIterator2 first2,
+        T init,
+        BinaryOperation1 binary_op1,
+        BinaryOperation2 binary_op2)
+    {
+        return init;
     }
 };
+
 } // namespace detail
 
 /// static version of std::inner_product
-template <std::size_t Size,
-          class _InputIterator1, class _InputIterator2, class _Tp,
-          class _BinaryOperation1, class _BinaryOperation2>
+template
+<
+    std::size_t Size,
+    class InputIterator1,
+    class InputIterator2,
+    class T,
+    class BinaryOperation1,
+    class BinaryOperation2
+>
 BOOST_FORCEINLINE
-_Tp inner_product_k(_InputIterator1 __first1,
-                    _InputIterator2 __first2,
-                    _Tp __init,
-                    _BinaryOperation1 __binary_op1,
-                    _BinaryOperation2 __binary_op2) {
-    return detail::inner_product_k_t<Size>::template apply(__first1,__first2,__init,
-                                                           __binary_op1, __binary_op2);
+T inner_product_k(
+    InputIterator1 first1,
+    InputIterator2 first2,
+    T init,
+    BinaryOperation1 binary_op1,
+    BinaryOperation2 binary_op2)
+{
+    return detail::inner_product_k_t<Size>::template apply(
+        first1, first2, init, binary_op1, binary_op2);
 }
 
-/// \brief 1D un-guarded correlation with a variable-size kernel
-template <typename PixelAccum,typename SrcIterator,typename KernelIterator,typename Integer,typename DstIterator>
-inline DstIterator correlate_pixels_n(SrcIterator src_begin,SrcIterator src_end,
-                                      KernelIterator ker_begin,Integer ker_size,
-                                      DstIterator dst_begin) {
-    using PIXEL_SRC_REF = typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type;
-    using PIXEL_DST_REF = typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type;
-    using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
-    PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero);
-    while(src_begin!=src_end) {
-        pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(
-            std::inner_product(src_begin,src_begin+ker_size,ker_begin,acc_zero,
-                               pixel_plus_t<PixelAccum,PixelAccum,PixelAccum>(),
-                               pixel_multiplies_scalar_t<PIXEL_SRC_REF,kernel_type,PixelAccum>()),
+/// \brief 1D un-guarded cross-correlation with a variable-size kernel
+template
+<
+    typename PixelAccum,
+    typename SrcIterator,
+    typename KernelIterator,
+    typename Size,
+    typename DstIterator
+>
+inline
+auto correlate_pixels_n(
+    SrcIterator src_begin,
+    SrcIterator src_end,
+    KernelIterator kernel_begin,
+    Size kernel_size,
+    DstIterator dst_begin)
+    -> DstIterator
+{
+    using src_pixel_ref_t = typename pixel_proxy
+        <
+            typename std::iterator_traits<SrcIterator>::value_type
+        >::type;
+    using dst_pixel_ref_t = typename pixel_proxy
+        <
+            typename std::iterator_traits<DstIterator>::value_type
+        >::type;
+    using kernel_value_t = typename std::iterator_traits<KernelIterator>::value_type;
+
+    PixelAccum accum_zero;
+    pixel_zeros_t<PixelAccum>()(accum_zero);
+    while (src_begin != src_end)
+    {
+        pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
+            std::inner_product(
+                src_begin,
+                src_begin + kernel_size,
+                kernel_begin,
+                accum_zero,
+                pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
+                pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_value_t, PixelAccum>()),
             *dst_begin);
-        ++src_begin; ++dst_begin;
+
+        ++src_begin;
+        ++dst_begin;
     }
     return dst_begin;
 }
 
-/// \brief 1D un-guarded correlation with a fixed-size kernel
-template <std::size_t Size,typename PixelAccum,typename SrcIterator,typename KernelIterator,typename DstIterator>
-inline DstIterator correlate_pixels_k(SrcIterator src_begin,SrcIterator src_end,
-                                      KernelIterator ker_begin,
-                                      DstIterator dst_begin) {
-    using PIXEL_SRC_REF = typename pixel_proxy<typename std::iterator_traits<SrcIterator>::value_type>::type;
-    using PIXEL_DST_REF = typename pixel_proxy<typename std::iterator_traits<DstIterator>::value_type>::type;
+/// \brief 1D un-guarded cross-correlation with a fixed-size kernel
+template
+<
+    std::size_t Size,
+    typename PixelAccum,
+    typename SrcIterator,
+    typename KernelIterator,
+    typename DstIterator
+>
+inline
+auto correlate_pixels_k(
+    SrcIterator src_begin,
+    SrcIterator src_end,
+    KernelIterator kernel_begin,
+    DstIterator dst_begin)
+    -> DstIterator
+{
+    using src_pixel_ref_t = typename pixel_proxy
+        <
+            typename std::iterator_traits<SrcIterator>::value_type
+        >::type;
+    using dst_pixel_ref_t = typename pixel_proxy
+        <
+            typename std::iterator_traits<DstIterator>::value_type
+        >::type;
     using kernel_type = typename std::iterator_traits<KernelIterator>::value_type;
-    PixelAccum acc_zero; pixel_zeros_t<PixelAccum>()(acc_zero);
-    while(src_begin!=src_end) {
-        pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(
-            inner_product_k<Size>(src_begin,ker_begin,acc_zero,
-                                  pixel_plus_t<PixelAccum,PixelAccum,PixelAccum>(),
-                                  pixel_multiplies_scalar_t<PIXEL_SRC_REF,kernel_type,PixelAccum>()),
+
+    PixelAccum accum_zero;
+    pixel_zeros_t<PixelAccum>()(accum_zero);
+    while (src_begin != src_end)
+    {
+        pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
+            inner_product_k<Size>(
+                src_begin,
+                kernel_begin,
+                accum_zero,
+                pixel_plus_t<PixelAccum, PixelAccum, PixelAccum>(),
+                pixel_multiplies_scalar_t<src_pixel_ref_t, kernel_type, PixelAccum>()),
             *dst_begin);
-        ++src_begin; ++dst_begin;
+
+        ++src_begin;
+        ++dst_begin;
     }
     return dst_begin;
 }
 
 /// \brief destination is set to be product of the source and a scalar
-template <typename PixelAccum,typename SrcView,typename Scalar,typename DstView>
-inline void view_multiplies_scalar(const SrcView& src,const Scalar& scalar,const DstView& dst) {
-    BOOST_ASSERT(src.dimensions() == dst.dimensions());
-    using PIXEL_SRC_REF = typename pixel_proxy<typename SrcView::value_type>::type;
-    using PIXEL_DST_REF = typename pixel_proxy<typename DstView::value_type>::type;
-    int height=src.height();
-    for(int rr=0;rr<height;++rr) {
-        typename SrcView::x_iterator it_src=src.row_begin(rr);
-        typename DstView::x_iterator it_dst=dst.row_begin(rr);
-        typename SrcView::x_iterator it_src_end=src.row_end(rr);
-        while(it_src!=it_src_end) {
-            pixel_assigns_t<PixelAccum,PIXEL_DST_REF>()(
-                pixel_multiplies_scalar_t<PIXEL_SRC_REF,Scalar,PixelAccum>()(*it_src,scalar),
+/// \tparam PixelAccum - TODO
+/// \tparam SrcView Models ImageViewConcept
+/// \tparam DstView Models MutableImageViewConcept
+template <typename PixelAccum, typename SrcView, typename Scalar, typename DstView>
+inline
+void view_multiplies_scalar(SrcView const& src_view, Scalar const& scalar, DstView const& dst_view)
+{
+    static_assert(std::is_scalar<Scalar>::value, "Scalar is not scalar");
+    BOOST_ASSERT(src_view.dimensions() == dst_view.dimensions());
+    using src_pixel_ref_t = typename pixel_proxy<typename SrcView::value_type>::type;
+    using dst_pixel_ref_t = typename pixel_proxy<typename DstView::value_type>::type;
+    using y_coord_t = typename SrcView::y_coord_t;
+
+    y_coord_t const height = src_view.height();
+    for (y_coord_t y = 0; y < height; ++y)
+    {
+        typename SrcView::x_iterator it_src = src_view.row_begin(y);
+        typename DstView::x_iterator it_dst = dst_view.row_begin(y);
+        typename SrcView::x_iterator it_src_end = src_view.row_end(y);
+        while (it_src != it_src_end)
+        {
+            pixel_assigns_t<PixelAccum, dst_pixel_ref_t>()(
+                pixel_multiplies_scalar_t<src_pixel_ref_t, Scalar, PixelAccum>()(*it_src, scalar),
                 *it_dst);
-            ++it_src; ++it_dst;
+
+            ++it_src;
+            ++it_dst;
+        }
+    }
+}
+
+
+/// \ingroup ImageAlgorithms
+/// \brief Boundary options for image boundary extension
+enum class boundary_option
+{
+    output_ignore,  /// do nothing to the output
+    output_zero,    /// set the output to zero
+    extend_padded,  /// assume the source boundaries to be padded already
+    extend_zero,    /// assume the source boundaries to be zero
+    extend_constant /// assume the source boundaries to be the boundary value
+};
+
+namespace detail
+{
+
+template <typename SrcView, typename RltView>
+void extend_row_impl(
+    SrcView src_view,
+    RltView result_view,
+    std::size_t extend_count,
+    boundary_option option)
+{
+    std::ptrdiff_t extend_count_ = static_cast<std::ptrdiff_t>(extend_count);
+
+    if (option == boundary_option::extend_constant)
+    {
+        for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
+        {
+            if(i >= extend_count_ && i < extend_count_ + src_view.height())
+            {
+                assign_pixels(
+                    src_view.row_begin(i - extend_count_), 
+                    src_view.row_end(i - extend_count_), 
+                    result_view.row_begin(i)
+                );
+            }
+            else if(i < extend_count_)
+            {
+                assign_pixels(src_view.row_begin(0), src_view.row_end(0), result_view.row_begin(i));
+            }
+            else
+            {
+                assign_pixels(
+                    src_view.row_begin(src_view.height() - 1), 
+                    src_view.row_end(src_view.height() - 1), 
+                    result_view.row_begin(i)
+                );
+            }
+            
+        }
+    }
+    else if (option == boundary_option::extend_zero)
+    {
+        typename SrcView::value_type acc_zero;
+        pixel_zeros_t<typename SrcView::value_type>()(acc_zero);
+
+        for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
+        {
+            if (i >= extend_count_ && i < extend_count_ + src_view.height())
+            {
+                assign_pixels(
+                    src_view.row_begin(i - extend_count_),
+                    src_view.row_end(i - extend_count_),
+                    result_view.row_begin(i)
+                );
+            }
+            else 
+            {
+                std::fill_n(result_view.row_begin(i), result_view.width(), acc_zero);
+            }
         }
     }
+    else if (option == boundary_option::extend_padded)
+    {
+        auto original_view = subimage_view(
+            src_view,
+            0,
+            -extend_count,
+            src_view.width(),
+            src_view.height() + (2 * extend_count)
+        );
+        for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
+        {
+            assign_pixels(
+                original_view.row_begin(i),
+                original_view.row_end(i),
+                result_view.row_begin(i)
+            );
+        }
+    }
+    else
+    {
+        BOOST_ASSERT_MSG(false, "Invalid boundary option");
+    }
+}
+
+} //namespace detail
+
+
+/// \brief adds new row at top and bottom.
+/// Image padding introduces new pixels around the edges of an image.
+/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
+/// \tparam SrcView Models ImageViewConcept
+/// \tparam extend_count number of rows to be added each side
+/// \tparam option - TODO
+template <typename SrcView>
+auto extend_row(
+    SrcView src_view,
+    std::size_t extend_count,
+    boundary_option option
+) -> typename gil::image<typename SrcView::value_type>
+{
+    typename gil::image<typename SrcView::value_type>
+        result_img(src_view.width(), src_view.height() + (2 * extend_count));
+
+    auto result_view = view(result_img);
+    detail::extend_row_impl(src_view, result_view, extend_count, option);
+    return result_img;
+}
+
+
+/// \brief adds new column at left and right.
+/// Image padding introduces new pixels around the edges of an image. 
+/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
+/// \tparam SrcView Models ImageViewConcept
+/// \tparam extend_count number of columns to be added each side
+/// \tparam option - TODO
+template <typename SrcView>
+auto extend_col(
+    SrcView src_view,
+    std::size_t extend_count,
+    boundary_option option
+) -> typename gil::image<typename SrcView::value_type>
+{
+    auto src_view_rotate = rotated90cw_view(src_view);
+
+    typename gil::image<typename SrcView::value_type>
+        result_img(src_view.width() + (2 * extend_count), src_view.height());
+
+    auto result_view = rotated90cw_view(view(result_img));
+    detail::extend_row_impl(src_view_rotate, result_view, extend_count, option);
+    return result_img;
+}
+
+/// \brief adds new row and column at all sides.
+/// Image padding introduces new pixels around the edges of an image. 
+/// The border provides space for annotations or acts as a boundary when using advanced filtering techniques.
+/// \tparam SrcView Models ImageViewConcept
+/// \tparam extend_count number of rows/column to be added each side
+/// \tparam option - TODO
+template <typename SrcView>
+auto extend_boundary(
+    SrcView src_view,
+    std::size_t extend_count,
+    boundary_option option
+) -> typename gil::image<typename SrcView::value_type>
+{
+    if (option == boundary_option::extend_padded)
+    {
+        typename gil::image<typename SrcView::value_type>
+            result_img(src_view.width()+(2 * extend_count), src_view.height()+(2 * extend_count));
+        typename gil::image<typename SrcView::value_type>::view_t result_view = view(result_img);
+
+        auto original_view = subimage_view(
+            src_view,
+            -extend_count,
+            -extend_count,
+            src_view.width() + (2 * extend_count),
+            src_view.height() + (2 * extend_count)
+        );
+
+        for (std::ptrdiff_t i = 0; i < result_view.height(); i++)
+        {
+            assign_pixels(
+                original_view.row_begin(i),
+                original_view.row_end(i),
+                result_view.row_begin(i)
+            );
+        }
+
+        return result_img;
+    }
+
+    auto auxilary_img = extend_col(src_view, extend_count, option);
+    return extend_row(view(auxilary_img), extend_count, option);
 }
 
 }} // namespace boost::gil