Mehrfache Bildüberlagerung statt Filterung, Zeigerproblem??



  • Hallo !!
    Ich hab ein Problem in c++ und kann einfach die Ursache nicht finden..

    Ich habe einen Gaussfilter sowohl in Csharp als auch in c++ geschrieben.
    Er funktioniert in c# ohne Probleme und zwar mit dynamischen 2d-Arrays.

    Der einzige Unterschied c++ zu c#:
    C++ arbeitet mit dynamischen 1d-Arrays auf deren Elemente in der Form index=x*Höhe+y
    zugegriffen wird (Bitte nicht wundern! Ich habe aus reiner Konvention die Bildstruktur so geändert, dass ich mit x,y arbeiten kann, statt y,x. Funktioniert auch bei Abbildung der Arrays im Sinne "hin und wieder zurück" ohne Fehler).

    Nun taucht in C++ der Fehler auf, dass dieselbe Filterfunktion die 9 verschiedenen Anteile der Filterberechnung nicht im richtigen Punkt addiert. Stattdessen ergibt sich eine Überlagerung von 9 Bildern die exakt um 1/3 der Bildgrösse zueinander versetzt sind.

    Ich finde einfach nicht heraus warum das so ist. Ist irgendwo ein Zeiger den ich nicht sehe, der aus x+-1 x+- 1/3 Bildbreite macht ????

    Ich habe bereits mehrfach die Indexberechnungen im Debugmode schrittweise überprüft. Es müsste eigentlich richtig sein....

    Filter:

    static bool prefiltering_gauss(DOUBLEARRAY_OFIMAGE &gaussfilter,double gaussnorm,DOUBLEARRAY_OFIMAGE &filteredImage, DOUBLEARRAY_OFIMAGE &Image, double &maxval, double &minval, int Width, int Height)
    {
    	maxval = 128;
    	minval = 128;
    	double sum =0;
    	for (int dx = 1; dx < (Width-1); dx++)
                {
                    for (int dy = 1; dy < (Height-1); dy++)
                    {
    		for (int j = -1; j < 2; j++)
                        {
                            for (int k = -1; k < 2; k++)
                            {
    			    //int n=(dx+j)*(Height)+(dy+k);
    			    sum += Image.getv(dx + j,dy + k) * gaussfilter.getv(j+1,k + 1);					
                            }
                       }
    		sum = sum/gaussnorm;
    		filteredImage.setv(dx,dy,sum);
    		//filteredImage[dx][dy] = Image[dx][dy]*1;
    		if (sum < minval) minval = sum;
    		if (sum > maxval) maxval = sum;
    		sum =0;
                    }
                }
                if (maxval == minval)
                {
                    maxval = 255;
                    minval = 0;
    	   }
    	return true;
    }
    

    Bildstruktur (und Filterkernelstruktur nur 3*3 grösse):
    Body:

    int border = 1;
    double maxgrey =255;
    double mingrey =0;
    double gaussnorm =0;
    double sigma =0.33;
    DOUBLEARRAY_OFIMAGE ImageField(psImage->uiHeight+2*border,psImage->uiWidth+2*border);
    DOUBLEARRAY_OFIMAGE pregaussed(psImage->uiHeight+2*border,psImage->uiWidth+2*border);
    DOUBLEARRAY_OFIMAGE gaussfilter(3 ,3);
    defgaussfilter(gaussfilter, gaussnorm, sigma); // berechnung 3*3 gaussfilter und renormierungsgrösse
    prefiltering_gauss(gaussfilter,gaussnorm,pregaussed,ImageField,maxgrey,mingrey,Width,Height); // vorfilterung mit gaussfilter
    

    Header

    class DOUBLEARRAY_OFIMAGE 
    {
    // data
    public:
    	int				uiWidth;
    	int				uiHeight;
    	BOOL			      	bColor;
    	int				iSource;
    	LPCTSTR				lpszSourceName;
    private: 
            double*                               Value;
    
    public: 
            DOUBLEARRAY_OFIMAGE(int Hoehe,int Breite) 
            { 
                uiHeight = Hoehe; 
                uiWidth = Breite; 
                // 2-Dimensionales Array auf 1-Dimensionales abbilden 
                Value = new double[uiWidth * uiHeight]; 
            }
    	double getv(int x, int y)
    	{
    		return Value[x*uiHeight+y];
    	}
    	void setv(int x, int y, double v)
    	{
    		Value[x*uiHeight+y]=v;
    	}
    
            double* operator[](int Spalte) 
            { 
                // Array liegt "spaltenweise" im Speicher damit zugriff [x][y] konventionell b zu w ist 
                return & Value[Spalte * uiHeight]; 
            } 
            ~DOUBLEARRAY_OFIMAGE() 
            { 
                delete [] Value; 
            } 
    };
    


  • Reformat'ted:

    static bool prefiltering_gauss(DOUBLEARRAY_OFIMAGE &gaussfilter,double gaussnorm,DOUBLEARRAY_OFIMAGE &filteredImage, DOUBLEARRAY_OFIMAGE &Image, double &maxval, double &minval, int Width, int Height)
    {
        maxval = 128;
        minval = 128;
        double sum =0;
        for (int dx = 1; dx < (Width-1); dx++) // siehe getv/setv: x*uiHeight .. hier: Width :confused:
        {
            for (int dy = 1; dy < (Height-1); dy++) 
            {
                for (int j = -1; j < 2; j++)
                {
                    for (int k = -1; k < 2; k++)
                    {
                        sum += Image.getv(dx + j,dy + k) * gaussfilter.getv(j+1,k + 1);                   
                    }
                }
                sum = sum/gaussnorm;
                filteredImage.setv(dx,dy,sum);
    
                if (sum < minval) minval = sum;
                if (sum > maxval) maxval = sum;
                sum =0;
            }
        }
        if (maxval == minval)
        {
            maxval = 255;
            minval = 0;
        }
        return true;
    }
    

    Warum nicht DOUBLEARRAY_OFIMAGE(int Hoehe,int Breite) : uiHeight(Hoehe), uiWidth(Breite), Value(new double[Hoehe*Breite]) {} ?



  • padreigh schrieb:

    Warum nicht DOUBLEARRAY_OFIMAGE(int Hoehe,int Breite) : uiHeight(Hoehe), uiWidth(Breite), Value(new double[Hoehe*Breite]) {} ?

    Sorry, hab keine Ahnung was du da andeutest oder was das bewirkt....
    Zu deiner Frage:
    Ich hab die Klassendefinition als eine von mehreren Möglichkeiten hier im Forum gefunden, wie man mehr-d-Arrays abbilden kann.

    padreigh schrieb:

    for (int dx = 1; dx < (Width-1); dx++) // siehe getv/setv: x*uiHeight .. hier: Width

    Hier ist x die Anzahl der Spalten, und das Array enthält die Bilddaten in Spaltenlängen "strukturiert" im Speicher. x {0...width-1} y {0..height-1}

    MFG



  • // google: "initialisierungsliste c++" 
    DOUBLEARRAY_OFIMAGE(int Hoehe,int Breite) : uiHeight(Hoehe), uiWidth(Breite), Value(new double[Hoehe*Breite]) {}
    // versus
    DOUBLEARRAY_OFIMAGE(int Hoehe,int Breite) // alle member werden per Defaultkonstruktor konstruiert (falls kein POD)
    {
       uiHeight = Hoehe; // und dann per zuweisung "überschrieben"
       uiWidth = Breite;
       Value = new double[Hoehe*Breite];
    }
    

    Initialisierungsliste ist schneller hab ich mir sagen lassen ... bei PODs egal. Generell kann man sich das aber angewöhnen da bei komplexeren Typen Zeit eingespart wird.

    Das sind deine getter/setter:

    double getv(int x, int y)           { return Value[x*uiHeight+y]; }
    void   setv(int x, int y, double v) { Value[x*uiHeight+y]=v;      }
    

    Über das Bild läufst du mit (hab mal die Faltung rausgenommen da ich vermute die Pixel werden nicht korrekt gewählt ==> simpler):

    for (int dx = 0; dx < Width; dx++)
        {
            for (int dy = 0; dy < Height; dy++)
            {
                sum = Image.getv(dx,dy);
                filteredImage.setv(dx,dy,sum);
            }
        }
    

    Nu sezt da mal statt getv und setv deren Definition ein und Spiels mit einem asym. Bild von 1*3 Pixel durch. Deine Array indexe sind immer valide ... aber treffen die auch den Pixel den du willst?

    Alternativ verpass mal getv/setv ein ASSERT(x < uiWidth) ASSERT (y < uiHeigth)


Anmelden zum Antworten