2012年6月3日 星期日

Qt and GIL(generic image library) : 02--Design a function to calculate absolute different value for GIL

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?

沒有留言:

張貼留言