C++ 双线性图像采样不可再现访问冲突
我有一个模板2D图像缓冲区类,可以与许多值类型一起使用。这些值存储为C++ 双线性图像采样不可再现访问冲突,c++,visual-studio-2010,templates,image-processing,bilinear-interpolation,C++,Visual Studio 2010,Templates,Image Processing,Bilinear Interpolation,我有一个模板2D图像缓冲区类,可以与许多值类型一起使用。这些值存储为T的一维动态数组,由行方法访问,以获取指向正确行的指针 该类的一个方法用于对图像中的值进行双线性采样 代码通常是有效的,但在生产环境中,我很少在这个方法中遇到访问冲突异常,我似乎无法重新创建该异常,因为崩溃转储不包括传递给该方法的坐标 以下是守则的相关部分: T* data; int width, height; T* Row(int y) const { return data + width * y; } T GetVa
T
的一维动态数组,由行
方法访问,以获取指向正确行的指针
该类的一个方法用于对图像中的值进行双线性采样
代码通常是有效的,但在生产环境中,我很少在这个方法中遇到访问冲突异常,我似乎无法重新创建该异常,因为崩溃转储不包括传递给该方法的坐标
以下是守则的相关部分:
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;
}
}
您是否看到任何明显的错误,这些错误会导致非NaN的x
和y
值的访问冲突
您可以假设宽度
、高度
和数据
有效且正确(即,正尺寸-在这种特殊情况下为1280x720,数据
不是悬空指针)
如果这很重要,那么在本例中,T
是一个float
事实上,这是不可复制的,并且通常99.9%的时间都在工作,这让我觉得这可能是一个准确性问题,尽管我不知道它会从何而来
或者,我可以使用什么调试技术来更有效地分析崩溃转储?我在1280x720
数据
上使用1073741824个随机值对这对(x
,y
)进行了测试,没有访问冲突。。因此,我会说它在99.9999999%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);
}
我得到了比例真实值的置信区间,区间是(0.000000e+00,4.460345e-09)
,因此成功率是(1-4.460345e-09)*100
,但是。。。别相信我,我不是统计学家!
xInt是否可以为负值?@AlessandroJacopson我不知道如果将
cx
钳制为0.0f
,宽度或高度是否可以小于1?另外,行(yInt)
的行为是什么?稍后,您可以使用xInt+1
访问返回的r0
。这里没有足够的细节。您需要使用调试器逐步查看索引值和数组大小。@AndyGwidth
和height
始终为正值。行
函数位于代码块顶部r0
是行的第一个值,r0[xInt]
是行的第X个值,r0[xInt+1]
是之后的一个值。如果我可以使用调试器进行调试,很遗憾,我收到的两个崩溃转储中没有对整个方法有意义的值,这就是为什么我问是否有人可以发现任何错误。@Rotem您可以修改代码吗?如果是,进行边界检查并让GetValueBilinear
returnT(0)
或其他方法返回,或者在出现错误时抛出异常而不是访问冲突,这是否可以接受/可行?
#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);
}
prop.test(0,1073741824)