Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: So Jun 16, 2024 14:27

Foren-Übersicht » Programmierung » Shader
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Autor Nachricht
 Betreff des Beitrags: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 09:54 
Offline
DGL Member

Registriert: Di Jan 24, 2006 18:46
Beiträge: 97
Hallo ihr,

wir sollen in der Uni jetzt u.a. ein Convolution-Filter implementieren. Allerdings komm ich irgendwie mit den Datentypen im Shader noch nicht ganz klar, wes wegen ich mich im Netz mal ein bisschen umgeschaut habe. Dabei bin ich auf folgenden Code gestoßen:
Code:
// maximum size supported by this shader
const int MaxKernelSize = 25;

// array of offsets for accessing the base image
uniform vec2 Offset[MaxKernelSize];

// size of kernel (width * height) for this execution
uniform int KernelSize;

// value for each location in the convolution kernel
uniform vec4 KernelValue[MaxKernelSize];

// image to be convolved
uniform sampler2D BaseImage;

void main()
{
    int i;
    vec4 sum = vec4(0.0);

    for (i = 0; i < KernelSize; i++)
    {
        vec4 tmp = texture2D(BaseImage, gl_TexCoord[0].st + Offset[i]);
        sum += tmp * KernelValue[i];
    }
    gl_FragColor = sum;
}


Was mein Problem an dem Code ist:
  • Was ist der Unterschied zw. einem vec2 und einem vec4? Denn vec4(0.0) sieht für mich eher nach nur einer Komponente aus und nicht 4. Also woher weiß ich immer, welchen Datentyp ich brauche?
  • Im Bild bewegt man sich ja per Offset[i] vor. Was passiert wenn man außerhalb des Bildes ist? Also an Koordinate (0, 0), also Index 0 ist, und dann z.B. 1 abzieht? Löst man das manuell per Fehlerbehandlung, oder hat der Shader da eine passende Fehlerbehandlung? Und gibt es vlt schönere Wege sich im Bild fortzubewegen? (Also das man x+3 bzw y+3 machen kann, anstatt den Offset übergeben zu müssen) Bzw. wie lese ich die Bildgröße aus? (Ich habe im C-Code ja nur noch ein Gluint)
  • Wie lade ich den Filterkernel am besten hoch? Es muss ja über glUniformMatrix4fv gehen. Wie groß muss die Matrix die ich hochlade bei einem 3x3 Filter sein? 9x4 floats (wegen vec4)? Und in welchen davon müssen meine Filterwerte stehen? Reicht es dann in jedem 4. float einen Wert einzuspeichern, oder muss ein Wert in 4 aufeinanderfolgenden floats erscheinen?

Das Tutorial im Wiki gibt dazu leider nicht wirklich eine richtige Auskunft :(.

besten Dank im Voraus
SunBlack


Zuletzt geändert von SunBlack am So Jun 13, 2010 11:48, insgesamt 1-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 11:34 
Offline
DGL Member

Registriert: Di Okt 13, 2009 17:25
Beiträge: 365
Programmiersprache: C++
Hallo!
Von Convolution-Filter lese ich das erste Mal etwas, bin da also auch kein Pro. Zu deinen Fragen:
  • Ein vec2 ist ein Vektor mit zwei Komponenten, also x und y, s und t oder auch u und v. Für jede Komponente gibt es quasi einen float. Vec4 hat vier Komponenten (z.B. xyzw). Dass der vec4-Konstruktor mit nur einem Parameter aufgerufen wird, entspricht glaube ich nicht den GLSL-Regeln. Gemeint ist jedenfalls vec4(0.0, 0.0, 0.0, 0.0).
  • Was bei Texturkoordinaten > 1 oder < 0 passiert, hängt davon ab, ob du glTexParameteri GL_REPEAT oder GL_CLAMP übergeben hast. Bei GL_REPEAT wird dann gekachelt, sonst wird ein Wert > 1 zu 1 und ein Wert < 0 zu 0.
  • Den letzten Punkt kann ich dir leider nicht beantworten, da ich mich wie gesagt nicht mit Convolution-Filtern auskenne. glUniformMatrix4fv ist zum hochladen der Daten auf die Grafikkarte vermutlich nicht so geeignet, da ich in deinem GLSL-Code keine Matrix (also z.B. mat4) sehe.

Übrigens, hast du auch schon das Tutorial GLSL gelesen?

Gruß mrtrain

ps: Wie hast du eigentlich die Aufzählungspunkte gemacht? Mit [*] will es bei nicht funktionieren.
edit: Danke Lord, jetzt geht's.


Zuletzt geändert von mrtrain am Mi Aug 31, 2011 19:17, insgesamt 2-mal geändert.

Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 11:37 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Hi SunBlack,

Bevor ich deine Fragen beantworte, hier vielleicht ein andere interessanter Hinweis für dich: Für Convolution-Filter *ohne* Shader gibt es auch: glConvolutionFilter2D. Wie man damit umgeht und was das genau ist, wird hier erklärt: Convolution-Filter. Ohne Shader wird wahrscheinlich schneller funktionieren, da du sonst sehr schnell an das Limit der Texturzugriffe kommst. Dann wechselt OpenGL in den Softwaremodus und es wird richtig langsam.
Der ConvolutionFilter2D muss aktiviert werden, bevor du dein Bild an OpenGL hochlädst. Wenn du die fertigen Daten dann auslesen und weiterverarbeiten möchtest, könnte sich glGetTexImage2D lohnen. Eventuell wird dieses sogar auch vom ConvolutionFilter beeinflusst. Dann lohnt es sich, erst das Bild *ohne* aktivierten Filter hochzuladen, dann den Filter aktivieren und das Bild wieder von OpenGL mit genanntem Befehl zurückholen. So kannst du unterschiedliche Filter anwenden, ohne das Bild immer wieder zur Grafikkarte übertragen zu müssen. Das ist aber, wie gesagt, nur dann interessant, wenn du die Daten später weiterverarbeiten oder in eine Datei schreiben willst.

SunBlack hat geschrieben:
  • Was ist der Unterschied zw. einem vec2 und einem vec4? Denn vec4(0.0) sieht für mich eher nach nur einer Komponente aus und nicht 4. Also woher weiß ich immer, welchen Datentyp ich brauche?
Nun, ein vec2 hat zwei Komponenten und ein vec4 eben vier, wie du schon festgestellt hast. vec4(0.0) ist eine verkürzte Schreibweise von vec4(0.0, 0.0, 0.0, 0.0). Für Texturkoordinaten auf zweidimensionalen Bildern nutzt man immer vec2, für Farben und Vertexpositionen vec4.

SunBlack hat geschrieben:
  • Im Bild bewegt man sich ja per Offset[i] vor. Was passiert wenn man außerhalb des Bildes ist? Also an Koordinate (0, 0), also Index 0 ist, und dann z.B. 1 abzieht? Löst man das manuell per Fehlerbehandlung, oder hat der Shader da eine passende Fehlerbehandlung? Und gibt es vlt schönere Wege sich im Bild fortzubewegen? (Also das man x+3 bzw y+3 machen kann, anstatt den Offset übergeben zu müssen) Bzw. wie lese ich die Bildgröße aus? (Ich habe im C-Code ja nur noch ein Gluint)
Es greifen die normalen Texturbehandlungen von OpenGL soweit ich weiß. Außerhalb des gültigen Texturbereiches wird der äußerste Pixel des Bildes bis in die Unendlichkeit wiederholt (vgl. glTexParameter - Vergleich zwischen verschiedenen Texturwraptypen).
Generell greifst du in OpenGL auf Texturen (also "Bilder") immer nur mit Koordinaten zwischen 0 und 1 zu. Ein vec2 (0.5, 0.5) würde also genau die Mitte der Textur treffen, egal, wie groß diese ist. Das ist meistens vorteilhaft (man kann einfach hochauflösende Texturen gegen niedriger auflösende austauschen und umgekehrt), in deinem Fall aber nachteilhaft. Die Größe der Textur kannst du im Shader selbst nicht rausbekommen und um anhand der Pixelkoordinaten auf einzelne Bildpunkte zuzugreifen brauchst du irgendein hohes Shadermodel (4 oder so), wird also nicht von jeder Grafikkarte unterstützt. Wie du die Größe der Textur in C nach dem Hochladen zu OpenGL rausbekommst weiß ich gerade leider nicht. Wenn ich pixelgenaue Zugriffe brauchte, habe ich das immer so gelöst, dass ich die Originalgröße der Textur beim Laden in einer Datenstruktur zusammen mit der TexturID (der GLUInt, den du meinst), gespeichert habe.

SunBlack hat geschrieben:
  • Wie lade ich den Filterkernel am besten hoch? Es muss ja über glUniformMatrix4fv gehen. Wie groß muss die Matrix die ich hochlade bei einem 3x3 Filter sein? 9x4 floats (wegen vec4)? Und in welchen davon müssen meine Filterwerte stehen? Reicht es dann in jedem 4. float einen Wert einzuspeichern, oder muss ein Wert in 4 aufeinanderfolgenden floats erscheinen?
Nein, es geht nicht über glUniformMatrix4fv. Ich sehe bei dem Shader gerade garkeinen Filterkernel, nur Offsets. Die Pixel werden also ungewichtet aufaddiert, es scheint sich nicht wirklich um einen Convolution-Shader zu handeln.

greetings

ps: mrtrain war bei ein paar sachen schneller ;). @mrtrain: da muss auch noch ein [ list] drum. also [ list][ *]punkt 1[ *]punkt 2[ /list]

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 12:32 
Offline
DGL Member

Registriert: Di Jan 24, 2006 18:46
Beiträge: 97
Hiho,

ersteinmal Danke für die Antworten :)

mrtrain hat geschrieben:
[*] Ein vec2 ist ein Vektor mit zwei Komponenten, also x und y, s und t oder auch u und v. Für jede Komponente gibt es quasi einen float. Vec4 hat vier Komponenten (z.B. xyzw). Dass der vec4-Konstruktor mit nur einem Parameter aufgerufen wird, entspricht glaube ich nicht den GLSL-Regeln. Gemeint ist jedenfalls vec4(0.0, 0.0, 0.0, 0.0).

Ok, gut. War mir da nicht ganz sicher ob er das so einfach abkam, vor allem da es mich gewundert hat, warum texture2D einen vec4 zurückgibt. Aber man sollte nicht nur an Koordinaten denken, sondern auch mal an Farbwerte (RGBA) die nicht in einer einzelnen Zahl stehen (wie bei Delphi weiß z.B. 16777215 ist ;) ), sondern als Vector getrennt.

mrtrain hat geschrieben:
Übrigens, hast du auch schon das Tutorial GLSL gelesen?

Japp, mein letzter Satz sollte das Andeuten.


Lord Horazont hat geschrieben:
Bevor ich deine Fragen beantworte, hier vielleicht ein andere interessanter Hinweis für dich: Für Convolution-Filter *ohne* Shader gibt es auch: glConvolutionFilter2D.

Leider bringt es mir in der Übung nichts - da sollen wir leider den Shader dazu verwenden - ist halt eine Shaderübung ;).

Lord Horazont hat geschrieben:
Es greifen die normalen Texturbehandlungen von OpenGL soweit ich weiß. Außerhalb des gültigen Texturbereiches wird der äußerste Pixel des Bildes bis in die Unendlichkeit wiederholt (vgl. glTexParameter - Vergleich zwischen verschiedenen Texturwraptypen).

Hab eben nachgeschaut GL_CLAMP_TO_EDGE ist eingestellt, also das passende.

Lord Horazont hat geschrieben:
Wenn ich pixelgenaue Zugriffe brauchte, habe ich das immer so gelöst, dass ich die Originalgröße der Textur beim Laden in einer Datenstruktur zusammen mit der TexturID (der GLUInt, den du meinst), gespeichert habe.

Ok schade. Hatte gehofft das Texturgrößenunabhängig machen zu können.

Lord Horazont hat geschrieben:
Nein, es geht nicht über glUniformMatrix4fv. Ich sehe bei dem Shader gerade garkeinen Filterkernel, nur Offsets. Die Pixel werden also ungewichtet aufaddiert, es scheint sich nicht wirklich um einen Convolution-Shader zu handeln.

Über was dann? Achja, hatte den flaschen Code vorhin vond er Quelle kopiert. Habe es mal korrigiert.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 12:49 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Na das sieht doch besser aus. Dann musst du deine Daten über glUniform4fv übergeben. Und zwar legst du dir dafür ein Array an, indem du die Vektoren mit den Faltungskernwerten speicherst. Auch hier handelt es sich wieder um vec4, sodass du jede Farbkomponente und Alpha mit einem anderen Wert belegen kannst. Dann übergibst du an glUniform4fv einen Pointer auf den ersten Wert des Arrays.
Ähnlich machst du's mit Offset. Da brauchst du dann ein Array aus vec2-Vektoren, in das du dann den Versatz reinsetzt. Für einen 3x3-Filter würdest du also z.B. die Vektoren
(-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1)
übergeben, wobei die noch mit einem Faktor multipliziert werden müssen, damit du die Pixel auch triffst.
Dieser Faktor ist der Kehrwert der Texturgröße in der jeweiligen Dimension, ist also für X und Y unterschiedlich. Für X ist er 1/Width, für Y 1/Height. Irgendwie müsstest du ja beim Laden an die Höhe und Breite der Textur rankommen, oder?

Ich hoffe, das war verständlich ;)

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 13:17 
Offline
DGL Member

Registriert: Di Jan 24, 2006 18:46
Beiträge: 97
Hey danke, jetzt ist alles klar. Mein Problem war wohl, dass ich die Farbe die ganze Zeit gedanklich als eine einzige Zahl interpretiert hatte (statt als Vector) und nach dem Fixen das nicht mehr darüber nachgedacht habe, was es bringt 4D-Vectoren zu übergeben (in der Übung davor haben wir alle Farbkompos gleich behandelt, wes wegen ich hier auch die Trennung vergaß ;) )

Eine Randfrage aber noch: Wann verwendet man denn glUniformMatrix4fv, wenn glUniform4fv reicht? Denn wenn ich mir das hier ansehe, sehe ich da keinen bedeutenden Unterschied.


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 13:38 
Offline
DGL Member
Benutzeravatar

Registriert: Do Sep 02, 2004 19:42
Beiträge: 4158
Programmiersprache: FreePascal, C++
Der bedeutende Unterschied liegt einfach darin, dass die Uniform-Variable im Shader bei dir als vecX deklariert ist, in verlinkten Beispiel als matX. Bei vecX musst du immer glUniformX[fd][v] verwenden, bei matX entsprechend glUniformMatrixX[fd][v].

greetings

_________________
If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung.
current projects: ManiacLab; aioxmpp
zombofant networkmy photostream
„Writing code is like writing poetry“ - source unknown


„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: So Jun 13, 2010 21:37 
Offline
DGL Member

Registriert: Di Jan 24, 2006 18:46
Beiträge: 97
So,

ich habe eben versucht das ganze zu Implementieren. Aber irgendwie erkenne ich keinen Unterschied zw. dem pass through filter und dem mean filter.

Shader:
Code:
#version 110

const int KernelSize = 9;

uniform sampler2D samplerTexture;
uniform vec4 KernelValues[KernelSize];
uniform vec2 Offset[KernelSize];

vec4 convolution(void)
{
    //
    // Todo Convolution Filter
    //
   vec4 col = vec4(0.0, 0.0, 0.0, 0.0);

   for (int i = 0; i < KernelSize; i++)
    {
      col += texture2D(samplerTexture, gl_TexCoord[0].st + Offset[i]) * KernelValues[i];
   }
   return col;
}


void main(void)
{
    gl_FragColor = convolution();
    return;
}


Und im C-Code:

Code:
//assume 2500px*1250px pictures, because we can't read size of picture in shader
void
loadShaderOffset()
{
   float offsets[18];

   for (int y=-1; y<=1; y++){
      for (int x=-1; x<=1; x++){
         int idx = (y+1)*3 + (x+1);

         offsets[2*idx]   = x/2500.0;
         offsets[2*idx+1] = y/1250.0;
      }
   }

   glUseProgramObjectARB(g_filterProgram);
   int offsetFBO = glGetUniformLocationARB(g_filterProgram, "Offset");
   glUniform4fvARB(offsetFBO, sizeof(offsets), &offsets[0]);
   glUseProgramObjectARB(0);
}

void
loadFilter(float filter[9])
{
   float offsets[36];

   for (int y=-1; y<=1; y++){
      for (int x=-1; x<=1; x++){
         int idx = (y+1)*3 + (x+1);
         
         offsets[4*idx]   = offsets[4*idx+1] = offsets[4*idx+2] = offsets[4*idx+3] = filter[idx];
      }
   }

   glUseProgramObjectARB(g_filterProgram);
   int kernelFBO = glGetUniformLocationARB(g_filterProgram, "KernelValues");
   glUniform4fvARB(kernelFBO, sizeof(offsets), &offsets[0]);
   glUseProgramObjectARB(0);
}

...
float kernel[9] = {0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0};
loadFilter(&kernel[0]);

Seht ihr den Fehler?


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: Mo Jun 14, 2010 11:23 
Offline
DGL Member

Registriert: Di Jan 24, 2006 18:46
Beiträge: 97
Fehler gefunden (Copy&Paste-Fehler): Die offsets sollten ja nicht mit glUniform4fvARB sondenr mit glUniform2fvARB hochgeladen werden :oops:


Nach oben
 Profil  
Mit Zitat antworten  
 Betreff des Beitrags: Re: Convolution-Filter
BeitragVerfasst: Mi Jun 23, 2010 07:57 
Offline
DGL Member
Benutzeravatar

Registriert: Di Dez 27, 2005 12:44
Beiträge: 393
Wohnort: Berlin
Programmiersprache: Java, C++, Groovy
Hallo,

glConvolutionFilter2D ist deutlich langsamer als ein Shader, zumal dafür die Erweiterung ARB_Imaging benötigt wird, die nicht immer verfügbar ist und ab OpenGL 3.0 als deprecated gilt.

Viele Grüße
dj3hut1

_________________
Wenn Gauß heute lebte, wäre er ein Hacker.
Peter Sarnak, Professor an der Princeton University


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 10 Beiträge ] 
Foren-Übersicht » Programmierung » Shader


Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 9 Gäste


Du darfst keine neuen Themen in diesem Forum erstellen.
Du darfst keine Antworten zu Themen in diesem Forum erstellen.
Du darfst deine Beiträge in diesem Forum nicht ändern.
Du darfst deine Beiträge in diesem Forum nicht löschen.
Du darfst keine Dateianhänge in diesem Forum erstellen.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.065s | 17 Queries | GZIP : On ]