1

Ich habe eine Vorlage 2D-Bildpufferklasse, die mit vielen Werttypen verwendet werden kann. Die Werte werden als dynamisches 1D-Array von T gespeichert, auf das über eine -Methode zugegriffen wird, um einen Zeiger auf die richtige Zeile zu erhalten.Bilineare Bildabtastung Nicht reproduzierbare Zugriffsverletzung

Eine der Methoden der Klasse wird verwendet, um einen Wert im Bild bilinear abzutasten.

Der Code funktioniert im Allgemeinen, aber immer seltener bekomme ich eine Zugriffsverletzung Ausnahme in dieser Methode in der Produktion, die ich nicht neu erstellen kann, da der Absturz nicht die Koordinaten enthält, die an die Methode übergeben wurden.

Dies sind die relevanten Teile des Codes:

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; 
    } 
} 

Die Definitionen für clamp und lerp sind:

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 

Haben Sie offensichtliche Fehler zu sehen, die eine Zugriffsverletzung für jede verursachen würde Werte von x und y, die nicht NaN sind?

können Sie davon ausgehen, dass width, height und data sind gültig und richtig (das heißt, positive Dimensionen - in diesem speziellen Fall 1280x720 wird data baumelt Zeiger nicht). Wenn es darauf ankommt, dann ist T in diesem Fall ein float.

Die Tatsache, dass dies nicht reproduzierbar ist und im Allgemeinen 99,9% der Zeit funktioniert, lässt mich glauben, dass es ein Genauigkeitsproblem sein könnte, obwohl ich nicht sehen kann, woher es kommen würde.

Oder, welche Debugging-Techniken könnte ich verwenden, um die Crash-Dumps effektiver zu analysieren?

+0

Kann 'xInt' negativ sein? –

+0

@AlessandroJacopson Ich sehe nicht, wie wenn 'cx' an' 0.0f' geklammert wird. – Rotem

+0

Kann die Breite oder Höhe kleiner als 1 sein? Was ist das Verhalten von 'Row (yInt)'? Später greifen Sie auf das zurückgegebene 'r0' mit' xInt + 1' zu. Es gibt einfach nicht genug Details hier.Sie müssen einen Debugger durchlaufen, um die Werte Ihrer Indizes und die Größe Ihrer Arrays zu sehen. – AndyG

Antwort

1

ich Ihre GetValueBilinear mit 1073741824 Zufallswerten für das Paar getestet (x, y) auf einem 1280x720 data ohne Zugriffsverletzung .. so würde ich sagen, dass es in Ordnung 99,999999% der Zeit arbeitet :-) ich vermute, dass das Problem nicht in GetValueBilinear ist aber an anderer Stelle ...

#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); 
} 


Auch wenn keine Zugriffsverletzung gefunden wurde ich nicht, dass die alg sagen kann orithm funktioniert gut 100%, ein naives Modell und diesen R-Code:

prop.test(0,1073741824) 

ich einen Konfidenzintervall für den wahr Wert des Anteils erhalten, das Intervall (0.000000e+00, 4.460345e-09) ist und so der Erfolg Prozentsatz ist (1-4.460345e-09)*100, aber ... Vertrau mir nicht, ich bin kein Statistiker!