For simplicity, I use non generic x_gradient to show the idea.When you are finding the gradient
of unsigned value, it is crucial to know
a is greater than b or
b is greater than a.So we write down
somehing like this(don't care about the problem of performance, it is not the big deal of this post).
void x_gradient_1(boost::gil::gray8c_view_t const &src, boost::gil::gray8_view_t const &dst)
{
for (int y = 0; y != src.height(); ++y)
for (int x = 1; x != src.width() - 1; ++x)
{
if(src(x - 1, y) > src(x + 1, y))
dst(x, y) = (src(x - 1, y) - src(x + 1, y)) / 2;
else
dst(x, y) = (src(x + 1, y) - src(x - 1, y)) / 2;
}
}
This work, but don't you think it is pretty verbose to write
if(src(x - 1, y) > src(x + 1, y))
dst(x, y) = (src(x - 1, y) - src(x + 1, y)) / 2;
else
dst(x, y) = (src(x + 1, y) - src(x - 1, y)) / 2;
everytime?We need a better solution to ease our pain.
#include <cmath>
#include <type_traits>
/* designed for pixel type of gil
*
* parameter
* X : first number
* Y : second number
*
* return value : absolute different between X and Y(|X - Y|)
*
* exception : depend on the template parameter
*/
template<typename T>
inline typename boost::gil::channel_type<T>::type absdiff_pixel(T const &x, T const &y)
{
return x > y ? x - y : y - x;
}
/* designed for unsigned primitive type
*
* parameter
* X : first number
* Y : second number
*
* return value : absolute different between X and Y(|X - Y|)
*
* exception : strong exception guarantee, nothrow guarantee
*/
template<typename T>
inline typename std::enable_if<std::is_unsigned<T>::value, T>::type
absdiff_pixel(T x, T y)
{
return x > y ? x - y : y - x;
}
/* designed for signed primitive type
*
* parameter
* X : first number
* Y : second number
*
* return value : absolute different between X and Y(|X - Y|)
*
* exception : strong exception guarantee, nothrow guarantee
*/
template<typename T>
inline typename std::enable_if<std::is_signed<T>::value, T>::type
absdiff_pixel(T x, T y)
{
return std::abs(x - y);
}
Now you can rewrite the codes like this
void x_gradient_2(boost::gil::gray8c_view_t const &src, boost::gil::gray8_view_t const &dst)
{
for (int y = 0; y != src.height(); ++y)
{
for (int x = 1; x != src.width() - 1; ++x)
{
dst(x, y) = absdiff_pixel(src(x - 1, y), src(x + 1, y)) / 2;
}
}
}
The main point to design the adsdiff_pixel is the return type, it should declare as
typename boost::gil::channel_type<T>::type;
I don't know what make us can't simply return T(looks like the parameters of x and y are pixels)
maybe the operator "-" change them to another type?
沒有留言:
張貼留言