Ähnlichkeit zweier Bilder errechnen



  • stell konkrete fragen dann bekommst du konkrete antworten.

    einfach nur hier reinschreiben "ach, ich denk mir, ich möchte gern X machen, schreibt mal vorschläge und anregungen" führt erfahrungsgemäss zu wenig resonanz. was ich auch vollkommen verstehe und gut so finde.



  • Okay, entschuldigung das war echt etwas ungenau.
    Ich habe mich dafür entschieden, mit glReadPixels die zwei Bilder auf dem Bildschirm zu vergleichen.
    Ich möchte die Datensätze, die glReadPixels ausließt, vergleichen, indem ich die Differenz der jeweiligen Pixel(also RGB-Werte) bilde.

    Wie kann ich die Daten speichern und nutzen, die glReadPixels mir geben soll? Ich möchte mit einer bzw. zwei ineinander verschachtelten Schleifen die Werte auslesen. Allerdings weiß ich nicht, wie ich an diese herankomme.
    Etwas wie:
    GLvoid* f=glReadPixels(..., f)
    klappt nicht.
    mfg
    Boindil



  • Da steht alles was du wissen musst: http://www.opengl.org/sdk/docs/man/xhtml/glReadPixels.xml



  • Ja, danke fürs googeln ;). Auf der Seite war ich bereits, sonst würde ich euch hier nicht belästigen. Mein Problem ist einfach, dass ich die Dante, die diese Routinge zurückliefert, nicht verarbeiten kann.

    Ist GL_RGB am sinvollsten? Wenn ja, wie kann ich dann auf die einzelnen Pixel zugreifen?



  • So sieht die verschachtelte Schleife aus. Wie mache ich aus dem Voidzeiger einen double Parameter? So wie es da steht kann es der Compiler ja nicht schlucken.

    GLvoid *temp;
    
    	double summe;
    
    	for(unsigned int i=0;i<img.height;i++)
    	{
    		for(unsigned int a=0;a<img.width;a++)
    		{
    			glReadPixels(a,i,1,1,GL_RGB, GL_FLOAT,temp);
    			double diff1=dif(img.data[i],temp);
    			glReadPixels(a+1,i,1,1,GL_RGB, GL_FLOAT,temp);
    			double diff2=dif(img.data[i+1],temp);
    			glReadPixels(a+2,i,1,1,GL_RGB, GL_FLOAT,temp);
    			double diff3=dif(img.data[i],temp);
    
    			summe+=diff1+diff2+diff3;
    		}
    	}
    	summe/=img.height*img.width*3;
    


  • Verstehe dein Problem mit glReadPixels nicht?

    std::vector<GLfloat> pixeldata (3 * img.width * img.height);
    glReadPixels( 0, 0, img.width, img.height, GL_RGB, GL_FLOAT, &pixeldata[0]);
    

    Und das wars.



  • Ah vielen Dank. Die Syntax war mir einfach nicht geläufig. Jetzt klappt alles soweit aber die Daten, die ich zurück erhalte sind sehr seltsam.

    Auf dem Bildschirm ist ein rotes Rechteck mit linker unterer Ecke bei -5|1 .
    Obwohl ich glReadPixels auch dort ansetze erhalte ich keine Werte für Rot zurück.
    Woran kann das liegen? Ich habe auch darauf geachtet, dass alles nötige innerhalb des Bildschirms zu sehen ist, um undefinierte Daten zu vermeiden.

    glReadPixels( -5, 1, img.width, img.height, GL_RGB, GL_FLOAT, &Original_data[0]);
    


  • Wie es aussieht, ist mein Ansatz nicht funktionstüchtig.
    Kann mir jemand sagen wo ein Fehler liegen könnte oder was eine machbare Alternative wäre?

    Folgendes macht mein Algorithmus:
    1. Zwei Bilder enstehen auf dem Bildschirm, das Originalbild stammt aus einer Datei und wird als Bitmap geladen, das andere entsteht künstlich.
    2. Die RGB - Werte der beiden Bilder werden durch glReadPixels geladen und verglichen. Um zu erkennen, ob das künstliche Bild nach einer Änderung dem Ausgangsbild ähnlicher ist, wird die Ähnlichkeit einmal errechnet und dann noch einmal, nach dem das Bild mit der Änderung abermals gezeichnet wurde.

    Die Ähnlichkeit wird durch wie folgt bestimmt:
    In einer Schleife werden für alle RGB-Paare die Differenzen bestimmt und als Summe gespeichert. Je größer die Summe, desto unähnlicher.

    Was könnte der Haken sein?



  • Boindil schrieb:

    Auf dem Bildschirm ist ein rotes Rechteck mit linker unterer Ecke bei -5|1 .
    Obwohl ich glReadPixels auch dort ansetze erhalte ich keine Werte für Rot zurück.
    Woran kann das liegen?

    Ist das schon geklärt? Falls nicht: du bekommst bei mehr als einem Byte pro Pixel (und davon gehe ich mal ganz stark aus, wenn du von einem roten Bild sprichst) halt... ja, mehrere Bytes pro Pixel zurück! Dein Rotwert versteckt sich also in einem Wert wie z.B. 0x00ffa0b5 (RGBA, also 4 Werte, 32 Bit breit). Die einzelnen Werte müsstest du nun per Bitoperationen aus diesem int 'rausziehen. Zum Beispiel so:

    //bitwise and und bitshift zum 'Extrahieren' der benötigten Farbwerte
    char alpha=(rgba & 0xff000000)>>24;
    char red  =(rgba & 0x00ff0000)>>16;
    char green=(rgba & 0x0000ff00)>>8;
    char blue =(rgba & 0x000000ff);
    

    So, oder so ähnlich (wie es genau bei dir ist, müsstest du halt herauspuzzeln).



  • Per GL_RGB erhalte ich exakt drei Werte pro Pixel, das habe ich eig. beachtet.
    Unabhängig davon, ob sie Grün, Rot oder Blau angeben, packe ich alle in einen vektor. Die einzelnen Elemente von diesem Vektor vergleiche ich dann mit dem entsprechenden Vektor des anderen Bilds. Beim Debuggen zeigt sich auch jedes mal dass die beiden gleich groß sind.

    Mir fällt nichts mehr ein^^



  • Dann hab ich doch noch mal eine Frage: Welchen Grund kann es dafür geben, dass glReadPixels mir verschiedene Werte liefert, wenn ich stehts die selbe stelle auslese? Kann es "Messfehler" geben?

    Boindil



  • Nein, das ist ja keine Messung :p.
    glReadPixels liefert dir immer den Bildschirminhalt. Ob du 3 oder 4 Werte pro int bekommst, hängt von GL_RGB oder GL_RGBA als parameter ab. GL_RGBA funktioniert auch nur, wenn du einen entsprechenden OpenGL Kontext hast. Kommt halt auch drauf an was gerendert wird. Wenn du kein statisches Bild hast, dürften die Ergbnisse logischerweise abweichen. Ansonsten könnte Antialiasing hier auch ein Grund sein.



  • Erstmal gilt es hier Klarheit zu schaffen:

    Boindil schrieb:

    Auf dem Bildschirm ist ein rotes Rechteck mit linker unterer Ecke bei -5|1 .

    glReadPixels( -5, 1, img.width, img.height, GL_RGB, GL_FLOAT, &Original_data[0]);
    

    Mir ist nicht ganz klar, wie etwas an Position -5,1 sein kann (verwechsel das nicht mit object-Space-coordinates oder dergleichen).
    Untere linke Ecke ist 0,0.



  • Um der Sache mit glReadPixels auf den Grund zu gehen, hab ich mir jetzt mal ein kleines Quadrat an der Position des Cursors anzeigen lassen, dass die Farbe hat, die glReadPixels an der Position ausließt.

    Allerdings hat das Quadrat immer die Farbe, die der Hintergrund wegen glClearColor(0, 0, 0.2f, 0.5f) hat. glReadPixels gibt mir diese Farbe zurück, obwohl noch andere Objekte über dem Hintergrund gezeichnet werden.



  • Zur Veranschaulichung hier einmal der entsprechende Code. Es erscheint ein Quadrat an der richtigen Position, hat aber, wie gesagt, die Farbe des Szenenhintergrundes, nicht aber des Dreiecks, dass unter dem Mauszeiger ist.

    float speicher[3];
    
    glReadPixels(user.x,user.y,1,1,GL_RGB,GL_FLOAT,&speicher[0]);
    
    glBegin(GL_QUADS);
    glColor3f(speicher[0],speicher[1],speicher[2]);
    glVertex3f(user.x,user.y,0);
    glVertex3f(user.x,user.y+1,0);
    glVertex3f(user.x+1,user.y+1,0);
    glVertex3f(user.x+1,user.y,0);
    glEnd();
    


  • Ich weiss nicht wie du an deine Mauskoordinaten kommst - daher kann ich dir nicht sagen woran es liegt. Allerdings hab ich eine Vermutung.

    Falls dein OS Windows ist:
    Windows Koordinatensystem hat seinen Ursprung (0,0) in der oberen linken Ecke.
    OpenGL (in dem Fall glReadPixel) nimmt die untere linke Ecke.

    Wenn du jetzt ein Fenster hast, das sagen wir mal 500*500 Pixel gross ist und dein Mauszeiger befindet nach Windows-Koordinaten bei (250,0), also oberer Rand ganz in der Mitte, dann wäre das für Opengl (250,500).

    Daher wirst du vermutlich immer den falschen Pixel auslesen 🙂



  • Danke, aber auch gerade bemerkt und schon behoben.



  • Falls es jemanden interessiert: Es klappt jetzt und läuft ganz nett, allerdings uuuuuunglaublich langsam durch glReadPixels. Gibt es da evtl. eine schnellere Alternative?



  • glReadPixels ist verdammt langsam, ja.
    Du kannst aber das ganze auch auf einen FBO rendern und direkt von dort lesen.


Anmelden zum Antworten