双线性图像采样不可重现的访问冲突

时间:2016-05-25 08:56:53

标签: c++ visual-studio-2010 templates image-processing bilinear-interpolation

我有一个模板2D图像缓冲类,可以与许多值类型一起使用。这些值存储为T的一维动态数组,由Row方法访问以获取指向正确行的指针。

该类的一种方法用于以双线性方式对图像中的值进行采样。

代码通常可以工作,但是我很少在生产中使用此方法获得访问冲突异常,我似乎无法重新创建,因为崩溃转储不包括传递给方法的坐标。 / p>

这些是代码的相关部分:

T* data;
int width, height;

T* Row(int y) const { return data + width * y; }

T GetValueBilinear(float x, float y) const
{
    const float PIXEL_CENTER_OFFSET = 0.5F;

    const float cx = clamp(0.0F, width - 1.0F, x - PIXEL_CENTER_OFFSET);
    const float cy = clamp(0.0F, height - 1.0F, y - PIXEL_CENTER_OFFSET);

    const float tx = fmod(cx, 1.0F);
    const float ty = fmod(cy, 1.0F);

    const int xInt = (int)cx;
    const int yInt = (int)cy;

    const T* r0 = Row(yInt);
    const T* r1 = ty && yInt < (height - 1) ? Row(yInt + 1) : r0;

    //interpolate on Y
    const T& c00 = r0[xInt];
    const T& c01 = r1[xInt];
    T c0 = lerp(c00, c01, ty);

    if (tx && xInt < (width - 1))
    {
        //interpolate on X
        const T& c10 = r0[xInt + 1];
        const T& c11 = r1[xInt + 1];
        T c1 = lerp(c10, c11, ty);
        return lerp(c0, c1, tx);
    }
    else
    {
        return c0;
    }
}

clamplerp的定义是:

template <typename T>
inline T clamp(T min, T max, T value) { return value < min ? min : value > max ? max : value; }

template <typename T>
inline T lerp(T a, T b, float t) { return a + (b - a) * t; } //i.e. a(1-t)+bt

您是否发现任何明显的错误会导致xy的任何非NaN值的访问冲突?

您可以假设widthheightdata有效且正确(即正尺寸 - 在此特定情况下为1280x720,data不是悬空指针)

如果重要,那么T在这种情况下就是float

事实上,这是不可再现的并且通常在99.9%的时间内工作,这让我觉得它可能是一个准确性问题,但我看不出它会来自哪里。

或者,我可以使用哪些调试技术更有效地分析崩溃转储?

1 个答案:

答案 0 :(得分:1)

我在1280x720 GetValueBilinear上测试了x的1073741824个随机值(ydata),没有访问冲突..所以我会说工作正常99.999999% 1 :-)我怀疑问题不在GetValueBilinear但在其他地方......

#include <cmath>
#include <algorithm>

template <typename T>
inline T clamp(T min, T max, T value) { return value < min ? min : value > max ? max : value; }

template <typename T>
inline T lerp(T a, T b, float t) { return a + (b - a) * t; } //i.e. a(1-t)+bt

template < typename T >
class C
{
public:
    C(int w, int h) : height(h), width(w) {
        float lower_bound = T(0);
        float upper_bound = std::nextafter(T(255), std::numeric_limits<T>::max());
        std::uniform_real_distribution<float> unif(lower_bound, upper_bound);
        std::default_random_engine re;
        data = new T[width*height];// I know... a leak! But... who cares?!
        std::generate(data, data + (width*height), [&]() {return unif(re); });
    }
    T GetValueBilinear(float x, float y) const
    {
        const float PIXEL_CENTER_OFFSET = 0.5F;

        const float cx = clamp(0.0F, width - 1.0F, x - PIXEL_CENTER_OFFSET);
        const float cy = clamp(0.0F, height - 1.0F, y - PIXEL_CENTER_OFFSET);

        const float tx = fmod(cx, 1.0F);
        const float ty = fmod(cy, 1.0F);

        const int xInt = (int)cx;
        const int yInt = (int)cy;

        const T* r0 = Row(yInt);
        const T* r1 = ty && yInt < (height - 1) ? Row(yInt + 1) : r0;

        //interpolate on Y
        const T& c00 = r0[xInt];
        const T& c01 = r1[xInt];
        T c0 = lerp(c00, c01, ty);

        if (tx && xInt < (width - 1))
        {
            //interpolate on X
            const T& c10 = r0[xInt + 1];
            const T& c11 = r1[xInt + 1];
            T c1 = lerp(c10, c11, ty);
            return lerp(c0, c1, tx);
        }
        else
        {
            return c0;
        }
    }




    T* data;
    int width, height;

    T* Row(int y) const { return data + width * y; }


};

#include <random>
#include <iostream>

#include <Windows.h>


float x;
float y;

LONG WINAPI my_filter(_In_  struct _EXCEPTION_POINTERS *ExceptionInfo)
{
    std::cout << x << " " << y << "\n";
    return EXCEPTION_EXECUTE_HANDLER;
}

int main()
{
    auto a = ::SetUnhandledExceptionFilter(my_filter);

    float lower_bound = -(1 << 20);
    float upper_bound = -lower_bound;
    std::uniform_real_distribution<float> unif(lower_bound, upper_bound);
    std::default_random_engine re;

    float acc = 0;
    C<float> img(1280, 720);

    img.GetValueBilinear(1.863726958e-043, 1.5612089e-038);

    for (size_t i = 0; i < (1 << 30); i++) {
        x = unif(re);
        y = unif(re);

        acc += img.GetValueBilinear(x, y);
    }

    return static_cast<int>(acc);
}

<小时/> 1 即使没有发现访问冲突,我也不能说这个算法100%运行,使用天真的模型和这个R代码:

prop.test(0,1073741824)

我得到比例的 true 值的置信区间,间隔为(0.000000e+00, 4.460345e-09),因此成功百分比为(1-4.460345e-09)*100,但是......不信任我,我不是统计学家!