// // Copyright 2005-2007 Adobe Systems Incorporated // Copyright 2021 Pranam Lashkari // // Distributed under the Boost Software License, Version 1.0 // See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt // #ifndef BOOST_GIL_CHANNEL_NUMERIC_OPERATIONS_HPP #define BOOST_GIL_CHANNEL_NUMERIC_OPERATIONS_HPP #include namespace boost { namespace gil { // Function objects and utilities for channel-wise numeric operations. // // List of currently defined functors: // channel_plus_t (+) // channel_minus_t (-) // channel_multiplies_t (*) // channel_divides_t (/), // channel_plus_scalar_t (+s) // channel_minus_scalar_t (-s), // channel_multiplies_scalar_t (*s) // channel_divides_scalar_t (/s), // channel_halves_t (/=2) // channel_zeros_t (=0) // channel_assigns_t (=) /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of addition of two channel values. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_plus_t { using ChannelRef1 = typename channel_traits::const_reference; using ChannelRef2 = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef1 not convertible to ChannelResult"); static_assert(std::is_convertible::value, "ChannelRef2 not convertible to ChannelResult"); /// \param ch1 - first of the two addends (augend). /// \param ch2 - second of the two addends. auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult { return ChannelResult(ch1) + ChannelResult(ch2); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of subtraction of two channel values. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_minus_t { using ChannelRef1 = typename channel_traits::const_reference; using ChannelRef2 = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef1 not convertible to ChannelResult"); static_assert(std::is_convertible::value, "ChannelRef2 not convertible to ChannelResult"); /// \param ch1 - minuend operand of the subtraction. /// \param ch2 - subtrahend operand of the subtraction. auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult { return ChannelResult(ch1) - ChannelResult(ch2); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of multiplication of two channel values. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_multiplies_t { using ChannelRef1 = typename channel_traits::const_reference; using ChannelRef2 = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef1 not convertible to ChannelResult"); static_assert(std::is_convertible::value, "ChannelRef2 not convertible to ChannelResult"); /// \param ch1 - first of the two factors (multiplicand). /// \param ch2 - second of the two factors (multiplier). auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult { return ChannelResult(ch1) * ChannelResult(ch2); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of division of two channel values. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_divides_t { using ChannelRef1 = typename channel_traits::const_reference; using ChannelRef2 = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef1 not convertible to ChannelResult"); static_assert(std::is_convertible::value, "ChannelRef2 not convertible to ChannelResult"); /// \param ch1 - dividend operand of the two division operation. /// \param ch2 - divisor operand of the two division operation. auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelResult { return ChannelResult(ch1) / ChannelResult(ch2); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of adding scalar to channel value. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_plus_scalar_t { using ChannelRef = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef not convertible to ChannelResult"); static_assert(std::is_scalar::value, "Scalar not a scalar"); static_assert(std::is_convertible::value, "Scalar not convertible to ChannelResult"); auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult { return ChannelResult(channel) + ChannelResult(scalar); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of subtracting scalar from channel value. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_minus_scalar_t { using ChannelRef = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef not convertible to ChannelResult"); static_assert(std::is_scalar::value, "Scalar not a scalar"); static_assert(std::is_convertible::value, "Scalar not convertible to ChannelResult"); /// \param channel - minuend operand of the subtraction. /// \param scalar - subtrahend operand of the subtraction. auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult { // TODO: Convertion after subtraction vs conversion of operands in channel_minus_t? return ChannelResult(channel - scalar); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of channel value by a scalar. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_multiplies_scalar_t { using ChannelRef = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef not convertible to ChannelResult"); static_assert(std::is_scalar::value, "Scalar not a scalar"); static_assert(std::is_convertible::value, "Scalar not convertible to ChannelResult"); /// \param channel - first of the two factors (multiplicand). /// \param scalar - second of the two factors (multiplier). auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult { return ChannelResult(channel) * ChannelResult(scalar); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of dividing channel value by scalar. /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_divides_scalar_t { using ChannelRef = typename channel_traits::const_reference; static_assert(std::is_convertible::value, "ChannelRef not convertible to ChannelResult"); static_assert(std::is_scalar::value, "Scalar not a scalar"); static_assert(std::is_convertible::value, "Scalar not convertible to ChannelResult"); /// \param channel - dividend operand of the two division operation. /// \param scalar - divisor operand of the two division operation. auto operator()(ChannelRef channel, Scalar const& scalar) const -> ChannelResult { return ChannelResult(channel) / ChannelResult(scalar); } }; /// \ingroup ChannelNumericOperations /// \brief Arithmetic operation of dividing channel value by 2 /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_halves_t { using ChannelRef = typename channel_traits::reference; auto operator()(ChannelRef channel) const -> ChannelRef { // TODO: Split into steps: extract with explicit conversion to double, divide and assign? //double const v = ch; //ch = static_cast(v / 2.0); channel /= 2.0; return channel; } }; /// \ingroup ChannelNumericOperations /// \brief Operation of setting channel value to zero /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_zeros_t { using ChannelRef = typename channel_traits::reference; auto operator()(ChannelRef channel) const -> ChannelRef { channel = Channel(0); return channel; } }; /// \ingroup ChannelNumericOperations /// structure for assigning one channel to another /// \note This is a generic implementation; user should specialize it for better performance. template struct channel_assigns_t { using ChannelRef1 = typename channel_traits::const_reference; using ChannelRef2 = typename channel_traits::reference; static_assert(std::is_convertible::value, "ChannelRef1 not convertible to Channel2"); /// \param ch1 - assignor side (input) of the assignment operation /// \param ch2 - assignee side (output) of the assignment operation auto operator()(ChannelRef1 ch1, ChannelRef2 ch2) const -> ChannelRef2 { ch2 = Channel2(ch1); return ch2; } }; }} // namespace boost::gil #endif