RGB zu YCbCr



  • Mal eine Frage:
    Die Quantisierung-Tabelle steht die im Zick-Zack da oder kann ich die einfach so weg schreiben, also einfach in ein 2-Dim. Array?
    Stehen tut sie ja ab dem Marker FF DB.



  • Wie gesagt, ich auch kein JPEG Experte, so genau kann ich dir das auch nicht sagen.
    Und ... ähäm ... "Farbunterabtastung", ja, wenn ich das hätte lesen können hätt ich's vermutlich verstanden 🙂

    Wie die einzelnen Blöcke der Farbkanäle angeordnet sind weiss ich nicht. Im Prinzip kannst du aber erstmal jeden Kanal einzeln dekodieren, und dann den kompletten Kanal mit voller Grösse aufblasen.
    (EDIT: gibt beide Varianten, entweder alle Blöcke eines Kanals hintereinander und dann erst der nächste Kanal, oder auch "interleaved".)

    Ich weiss nicht ob der JPEG Standard einen Filter zum Aufblasen definiert, bzw. definiert ob man die Blöcke einzeln aufblasen soll oder das Bild als ganzes. Wenn ja, dann halte dich am besten an diese Vorgaben.
    (EDIT: sieht so aus als ob der Standard keinen Filter definiert.)

    Wenn nein, dann würde ich empfehlen das Aufblasen erst mit dem ganzen Bild zu machen (vor bzw. gleichzeitig mit der YUV->RGB Konvertierung), weil es vermutlich zu nem besseren Ergebnis führen wird. Wenn du nämlich die einzelnen Blöcke aufskalierst, dann musst du entweder einen suboptimalen Vergrösserungsfilter verwenden (nearest pixel oder linear interpolieren), oder du bekommst Fehler an den Blockrändern -- weil du dort die von besseren Filtern (bikubisch, ...) benötigen Nachbarpixel nicht zur Verfügung hast. Diese Fehler würden sich dann wie ein Gitter durch das ganze Bild ziehen. Bei Bildern mit starken Farbübergängen (roter Text auf Schwarz, grüner Text auf Rot o.ä.) würde das ziemlich sicher auch auffallen.

    Wie die Quantisierungs-Matrix abgelegt ist weiss ich ehrlich gesagt auch nicht. Ich würde vermuten ohne zig-zag. Kannst du aber einfach an den Werten erkennen: wenn sie halbwegs von klein nach gross sortiert sind, dann ist es mit zigzag. Wenn sie dagegen eher ne Sägezahnkurve ergeben, dann ist es ohne zigzag.

    Oder du suchst dir die fehlenden Infos aus den entsprechenden Standarddokumenten raus:
    http://www.w3.org/Graphics/JPEG/itu-t81.pdf
    http://www.w3.org/Graphics/JPEG/jfif3.pdf



  • Hey hustbaer,
    vielen dank für deinen Beitrag! Sehr hilfreich!

    Ich schau mir das gleich mal und danke für die 2 Links die hatte ich noch nicht. 😞

    Ich meld mich dann Donnerstag wieder hab jetzt erstmal Feierabend! 😃

    Schönen 1. Mai euch!



  • Fuchs aus dem Wald schrieb:

    Ich schau mir das gleich mal und danke für die 2 Links die hatte ich noch nicht. 😞

    Sind beide auf der (englischen) Wikipedia-Seite zu JPEG zu finden 😉

    http://en.wikipedia.org/wiki/JPEG

    Tip: Browser umstellen dass er Englisch als erste Sprache meldet und Google umstellen dass google.com verwendet wird und "Google-Anwendungen" auch per Default Englisch laufen.
    Bringt eine deutliche Verbesserung der Suchresultate bei fast allen Themen, und sorgt bei einigen Seiten dafür dass man nicht per Default auf die (meist minderwertige) Deutsche Seite umgeleitet wird. (Bzw. bei MSDN per Default die (meist minderwertige) Deutsche Sprachversion presentiert bekommt.)

    Ausgenommen natürlich wenn man nach Deutsch-spezifischen Dingen sucht. Wobei Google schlau genug zu sein scheint mir trotzdem nicht nur lauter amerikanische Online Shops zu liefern wenn ich nach Produkten suche.



  • hustbaer schrieb:

    Tip: Browser umstellen dass er Englisch als erste Sprache meldet

    Gute Idee, habe ich auch schonmal versucht... nutze Firefox, und es wollte nicht klappen. Falls du auch Firefox nutzt, wie macht man das? Ich habe z.B. in \1:config Language auf en-us umgestellt, hat aber net so viel gebracht.



  • out schrieb:

    ... nutze Firefox, und es wollte nicht klappen.

    http://www.google.com/ncr



  • ncr schrieb:

    out schrieb:

    ... nutze Firefox, und es wollte nicht klappen.

    http://www.google.com/ncr

    😮 Wie einfach Dinge doch sein können... 3 Buchstaben.

    Danke dir 🙂



  • @out
    Geht noch viel einfacher.
    Geh auf google.de, und klick einfach 1x auf den "Google.com" Link ganz rechts unten. Dann merkt er sich dass du wirklich google.com willst wenn du google.com eingibst. => done

    Das Umstellen der Sprache die der Browser reportet ist dann für andere Seiten die anhand der primären Sprache entscheiden ob sie umleiten bzw. einen mit einer Maschinenübersetzung nerven sollen. Wie eben z.B. MSDN.



  • Den Tipp sollte man irgendwo mit rein Pinnen! Das ist richtig gut.



  • OK da bin ich mal wieder mit meinem Fortschritt.

    Mein Problem ist grade, wie ich diese Rechnung hier umsetzen kann.

    Formel
    Ich bräuchte da mal einen Tipp wie man sowas in Code schreiben könnte.


  • Mod

    Schleifen?



  • Fuchs aus dem Wald schrieb:

    Mal eine Frage:
    Die Quantisierung-Tabelle steht die im Zick-Zack da oder kann ich die einfach so weg schreiben, also einfach in ein 2-Dim. Array?
    Stehen tut sie ja ab dem Marker FF DB.

    Hey ich möchte noch einmal auf diese Frage zurück kommen. Da die Tabelle schon im Zick-Zack geschrieben werden muss.
    Ich weiß nicht so richtig wie ich das Programmieren soll. Das macht mir im Moment am meisten Probleme.
    Das hier habe ich jetzt dafür aber irgendwie gefällt mir das nicht. -.- Das geht doch sicher irgendwie einfacher.

    int x  = 0;
     int y  = 0;
     int up = -1;
     const char* arr;
     Matrix[x][y] = dqt; //da x,y = 0 ist das der erste punkt also der DC 
                         //dgt ist eine Pointer auf den anfang
     while(x <= 7 && y <=7){
       if(x == 0 || y == 0 || x == 7 || y == 7){ 
         if(x == 0 || x == 7){
           ++y;
         }
         if(y == 0 || y == 7){
           ++x;
         }
         arr = Matrix[x][y];
         objectstorage->setHuffMatrix(arr);
         up = -1;
       }
       x = up;
       y = up;
       arr = Matrix[x][y];
       objectstorage->setHuffMatrix(arr);
     }
    }
    


  • Da die Blöcke immer gleich gross sind würde ich sagen einfach

    static int const zigZagTable[64] = { ...
    for (int i = 0; i < 64; i++)
    {
        int offset = zigZagTable[i];
        int x = offset & 7;
        int y = offset / 8;
        // ...
    }
    


  • hustbaer schrieb:

    Da die Blöcke immer gleich gross sind würde ich sagen einfach

    static int const zigZagTable[64] = { ...
    for (int i = 0; i < 64; i++)
    {
        int offset = zigZagTable[i];
        int x = offset & 7;
        int y = offset / 8;
        // ...
    }
    

    Das versteh ich jetzt noch nicht ganz. Wieso rechnest du für x und y den Wert aus der Tabelle um? Der Wert soll doch in ein 2D-Array das so aufgebaut ist: ZigZagMatrix
    Also wenn zigZagTable[0] = 11 ist dann muss das an Matrix[0][0].

    martix[0][1] = zzt[1] 
    martix[1][0] = zzt[2]
    

    usw.



  • Ich hab mal Fortschritt für euch. 😃

    Und zwar hab ich hier jetzt eine Funktion die alle Quantisierungstabellen speichert und zwar im Zick Zack:

    void TABLES::buildQT(){
      const char* dqt = objectstorage->getDQT(); //pointer auf den dqt marker FFDB
      int next        = 5; //da die tabelle erst da los geht
      int up          = 0;
      while(objectstorage->nextDHT()){ //while schleife damit ich in die dritte diemenson die 2 Tabelle reinschreiben kann
        for(int i=0;i<7;++i){
          if(i%2){
            for(int j=0;j<=i;++j){
              arrQT[j][i-j][up]=dqt[next++];
            }
          }else{
            for(int j=i;j>=0;--j){
              arrQT[j][i-j][up]=dqt[next++];
            }
          }
        }
        for(int i=7;i>=0;--i){
          if((i+8+1)%2){
            for(int j=0;j<=i;++j){
              arrQT[8-1-j][8-1-(i-j)][up]=dqt[next++];
            }
          }else{
            for(int j=i;j>=0;--j){
              arrQT[8-1-j][8-1-(i-j)][up]=dqt[next++];
            }
          }
        }
        objectstorage->setDQTMatrix((char*)arrQT); // mein setter
        ++up; //dritte dimension
      }
    }
    


  • Sehr schön.
    Ich hatte es übrigens so gemeint:

    void Foo() { // Deine Variante
    	for (int i = 0; i < 7; ++i) { 
    		if (i % 2) { 
    			for (int j = 0; j <= i; ++j) { 
    				printf("%d, %d\n", j, i - j);
    			} 
    		} else { 
    			for (int j = i; j >= 0; --j) { 
    				printf("%d, %d\n", j, i - j);
    			} 
    		} 
    	} 
    	for (int i = 7; i >= 0; --i){ 
    		if ((i + 8 + 1) % 2) { 
    			for (int j = 0; j <= i; ++j) { 
    				printf("%d, %d\n", 8 - 1 - j, 8 - 1 - (i - j));
    			} 
    		} else { 
    			for (int j = i; j >= 0; --j) { 
    				printf("%d, %d\n", 8 - 1 - j, 8 - 1 - (i - j));
    			} 
    		} 
    	}
    }
    
    #define ZZIDX(x, y) (x + (y * 8))
    
    unsigned char const g_zigZagTable[64] = {
    	ZZIDX(0, 0), ZZIDX(0, 1), ZZIDX(1, 0), ZZIDX(2, 0), ZZIDX(1, 1), ZZIDX(0, 2), ZZIDX(0, 3), ZZIDX(1, 2),
    	ZZIDX(2, 1), ZZIDX(3, 0), ZZIDX(4, 0), ZZIDX(3, 1), ZZIDX(2, 2), ZZIDX(1, 3), ZZIDX(0, 4), ZZIDX(0, 5),
    	ZZIDX(1, 4), ZZIDX(2, 3), ZZIDX(3, 2), ZZIDX(4, 1), ZZIDX(5, 0), ZZIDX(6, 0), ZZIDX(5, 1), ZZIDX(4, 2),
    	ZZIDX(3, 3), ZZIDX(2, 4), ZZIDX(1, 5), ZZIDX(0, 6), ZZIDX(0, 7), ZZIDX(1, 6), ZZIDX(2, 5), ZZIDX(3, 4),
    	ZZIDX(4, 3), ZZIDX(5, 2), ZZIDX(6, 1), ZZIDX(7, 0), ZZIDX(7, 1), ZZIDX(6, 2), ZZIDX(5, 3), ZZIDX(4, 4),
    	ZZIDX(3, 5), ZZIDX(2, 6), ZZIDX(1, 7), ZZIDX(2, 7), ZZIDX(3, 6), ZZIDX(4, 5), ZZIDX(5, 4), ZZIDX(6, 3),
    	ZZIDX(7, 2), ZZIDX(7, 3), ZZIDX(6, 4), ZZIDX(5, 5), ZZIDX(4, 6), ZZIDX(3, 7), ZZIDX(4, 7), ZZIDX(5, 6),
    	ZZIDX(6, 5), ZZIDX(7, 4), ZZIDX(7, 5), ZZIDX(6, 6), ZZIDX(5, 7), ZZIDX(6, 7), ZZIDX(7, 6), ZZIDX(7, 7),
    	};
    
    void Bar() { // Meine Variante
    	for (int i = 0; i < 64; i++) {
    		int x = g_zigZagTable[i] & 7;
    		int y = g_zigZagTable[i] / 8;
    		printf("%d, %d\n", x, y);
    	} 
    }
    
    int main() {
    	Foo();
    	printf("\n\n");
    	Bar();
    }
    

    Man ersetzt also die 6 Schleifen durch eine Schleife + einen 64 Byte grossen Table.
    mMn. wesentlich übersichtlicher.

    Und nochwas...

    if ((i + 8 + 1) % 2)
        A;
    else
        B;
    
    // ist das selbe wie
    
    if ((i + 1) % 2)
        A;
    else
        B;
    
    // und das selbe wie
    
    if (i % 2)
        B;
    else
        A;
    


  • hustbaer schrieb:

    Und nochwas...

    if ((i + 8 + 1) % 2)
        A;
    else
        B;
    
    // ist das selbe wie
    
    if ((i + 1) % 2)
        A;
    else
        B;
    
    // und das selbe wie
    
    if (i % 2)
        B;
    else
        A;
    

    Erstmal zu dem. Das ist schlau. 😃 Danke dafür.

    hustbaer schrieb:

    Sehr schön.
    Ich hatte es übrigens so gemeint:

    #define ZZIDX(x, y) (x + (y * 8))
    
    unsigned char const g_zigZagTable[64] = {
    	ZZIDX(0, 0), ZZIDX(0, 1), ZZIDX(1, 0), ZZIDX(2, 0), ZZIDX(1, 1), ZZIDX(0, 2), ZZIDX(0, 3), ZZIDX(1, 2),
    	ZZIDX(2, 1), ZZIDX(3, 0), ZZIDX(4, 0), ZZIDX(3, 1), ZZIDX(2, 2), ZZIDX(1, 3), ZZIDX(0, 4), ZZIDX(0, 5),
    	ZZIDX(1, 4), ZZIDX(2, 3), ZZIDX(3, 2), ZZIDX(4, 1), ZZIDX(5, 0), ZZIDX(6, 0), ZZIDX(5, 1), ZZIDX(4, 2),
    	ZZIDX(3, 3), ZZIDX(2, 4), ZZIDX(1, 5), ZZIDX(0, 6), ZZIDX(0, 7), ZZIDX(1, 6), ZZIDX(2, 5), ZZIDX(3, 4),
    	ZZIDX(4, 3), ZZIDX(5, 2), ZZIDX(6, 1), ZZIDX(7, 0), ZZIDX(7, 1), ZZIDX(6, 2), ZZIDX(5, 3), ZZIDX(4, 4),
    	ZZIDX(3, 5), ZZIDX(2, 6), ZZIDX(1, 7), ZZIDX(2, 7), ZZIDX(3, 6), ZZIDX(4, 5), ZZIDX(5, 4), ZZIDX(6, 3),
    	ZZIDX(7, 2), ZZIDX(7, 3), ZZIDX(6, 4), ZZIDX(5, 5), ZZIDX(4, 6), ZZIDX(3, 7), ZZIDX(4, 7), ZZIDX(5, 6),
    	ZZIDX(6, 5), ZZIDX(7, 4), ZZIDX(7, 5), ZZIDX(6, 6), ZZIDX(5, 7), ZZIDX(6, 7), ZZIDX(7, 6), ZZIDX(7, 7),
    	};
    
    void Bar() { // Meine Variante
    	for (int i = 0; i < 64; i++) {
    		int x = g_zigZagTable[i] & 7;
    		int y = g_zigZagTable[i] / 8;
    		printf("%d, %d\n", x, y);
    	} 
    }
    
    int main() {
    	Foo();
    	printf("\n\n");
    	Bar();
    }
    

    Man ersetzt also die 6 Schleifen durch eine Schleife + einen 64 Byte grossen Table.
    mMn. wesentlich übersichtlicher.
    [/cpp]

    Ahhhhaa das verstehe ich nun auch. Ich danke dir dafür das ist viel besser. Dazu kommt das bei deiner Variante nur eine Tabelle und bei mir ein 3d Array. Vielen dank.
    Ich werde mal weiter machen und hier weiter meine Vorschritte posten.



  • Mal eine kleine Frage...
    Die DCT oder auch iDCT Rechnung muss ja mit jedem wert durch geführt werden. Also wenn ich alle werte die ich beim Decoden nach der ReQuantisierung habe in einen Vektor pushe, könnte ich doch dann einfach jeden Wert ohne 8x8 Matrix errechnen oder?
    Dann noch die Farbumwandlung und Überabtastung und schon bin ich fertig ??



  • Ich glaub du verwechselst da gerade was. Oder ich verstehe dich nicht richtig. Die (i)DCT kann immer nur auf ganzen 8x8 Blöcken arbeiten.

    Also beim Decoden hast du (frei aus dem Gedächtnis):

    Entropy Decoding (Huffman/Arithmetic) => De-Quantisierung => De-ZigZag => iDCT

    Dann bist du im Prinzip fertig und hast ein Bild in dem Colorspace und den Channel-Auflösungen vorliegen wie sie abgespeichert wurden.
    Wenn Subsampling und YUV verwendet wurde, und du 1:1:1 Sampling und RGB haben willst folgt darauf noch

    Resampling => Color Space Conversion

    Beim Entropy Decoding gibt's sowieso (noch) keine Blöcke, da entstehen die ja erst.

    Die De-Quantisierung arbeitet zwar im Prinzip auf jedem Wert einzeln, aber der Quantizer muss aus an der richtigen Stelle der Quantizer-Matrix nachgeschlagen werden - ist also auch nicht ganz von der Block-Struktur losgelöst.
    De-ZigZag und iDCT sind sowieso total blockgebunden.

    Resampling ist dann auf dem ganzen Bild zu machen, und Color Space Conversion auf einzelnen Pixeln, wobei du da aber die Werte aller 3 Kanäle für diesen Pixel gleichzeitig brauchst.



  • Hmm ... also ich hab grade überlegt. Bei der Quantisierung ist es doch so das man 2 Matrizen je nachdem ob De- oder Quantisierung * () / nimmt. Da ist es für mich auch logisch. Gut Huffman ist doch unabhängig von dem 8x8 Block man muss nur wissen welche Tabelle man anwenden muss. Beispiel: Man hat 3 8x8 Blöcke, Block 1 und 2 nutzen Tabelle 1 und der 3 Tabelle 2. Nun kann ich ja auch auf die ersten 128 Zeichen Tabelle 1 anwenden und auf die letzten von 129-192 Tabelle 2 oder nicht?
    Den Zick Zack muss man dann wieder mit 8x8 Blöcken machen das ist mir klar. Die Reihenfolge ist ja dadrauf ausgelegt.
    Gut nun (i)DCT da muss man ja die gleiche Rechnung für jedes Zeichen machen, also für jeden AC und wenn ich das richtig verstanden hab für jeden DC. Da hab ich gedacht das man das nicht unbedingt in einem 8x8 Block machen muss. Oder hab ich bei der (i)DCT was falsch verstanden??

    Zur Reihenfolge noch mal
    Encoder:
    RGB zu YCbCr -> dann für jede Schicht ein Scan -> DCT -> Quantisierung -> RLE -> Huffman -> 010100011...
    Decoder:
    01010011... -> Huffman -> RLE -> Dequantisierung -> iDCT -> YCbCr zu RGB


Anmelden zum Antworten