Einzelnen Beitrag anzeigen

Benutzerbild von dizzy
dizzy

Registriert seit: 26. Nov 2003
Ort: Lünen
1.932 Beiträge
 
Delphi 7 Enterprise
 
#1

5x5-Blur bzw. "Antialiasing"

  Alt 26. Nov 2003, 23:00
Kein "echtes" Antialiasing, aber ein konfigurierbarer 5x5-Blur.
In AntAussen, AnzMitte und AntInnen lässt sich einstellen, wie stark welche Region in den Zielpixel einfliessen soll (wobei AntInnen das Zentrum darstellt). Dabei sollte man beachten, dass die Anteile summiert = 1 sind, sonst wird's unschön.

Die Prozedur dürfte recht fix sein, und sich auch für den einen oder anderen "realtime"-Einsatz eignen (vielleicht nicht ganz fullscreen, aber immerhin )

Anmerkung: Das ganze ist NICHT als Funktion implementiert, da ich den Eindruck hatte, dass es so schneller läuft.
Anmerkung2: Die Kanten des Bildes werden allerdings vernachlässigt, um nicht noch if-Abfragen rein zu bringen. Das Teil ist auf Geschwindigkeit geschrieben (und dass wo ich doch kein Wort Assembler kann 8) ).


Die Regionen sehen folgendermaßen aus:
A = Aussen (AntAussen)
M = Mitte (AntMitte)
I = Innen (AntInnen)
Delphi-Quellcode:
   A A A
A M M M A
A M I M A
A M M M A
   A A A
Der Code:
Delphi-Quellcode:
type
  PixelA3 = array[1..3] of Byte;
  PixelA15 = array[1..15] of Byte;


procedure TForm1.AntiAlias5(const i: TBitmap; var o: TBitmap);
var
  Po: ^PixelA3;
  P1, P2, P3, P4, P5: ^PixelA15;
  x, y: Cardinal;
  dekrement: Cardinal;
  AntAussen, AntMitte, AntInnen: double;
begin
  // Anteile der Regionen am Zielpixel festlegen
  AntAussen := 12*4; // 12 Pixel zu 1/4 in Ziel-Pixel
  AntMitte := 8*4; // 8 Pixel zu 1/4 in Ziel-Pixel
  AntInnen := 2; // 1 Pixel zu 1/2 in Ziel-Pixel

  dekrement := 3*(i.Width-3);

  // Scanline der ersten 5 Zeilen abholen
  P1 := i.ScanLine[0];
  P2 := i.ScanLine[1];
  P3 := i.ScanLine[2];
  P4 := i.ScanLine[3];
  P5 := i.ScanLine[4];

  for y := 2 to i.Height-4 do
  begin
    // Scanline des Zielbildes abholen
    Po := o.ScanLine[y];
    // und die x-Position um 2 erhöhen (wie gesagt, Rand spielt nicht mit)
    inc(Po, 2);
    for x := 2 to i.Width-2 do
    begin
      // Blauwert des Zielpixels aus den Blauwerten der Ausgangsregion basteln
      Po^[1] := round(((P1^[4]+P1^[7]+P1^[10] +
                        P2^[1] + P2^[13] +
                        P3^[1] + P3^[13] +
                        P4^[1] + P4^[13] +
                        P5^[4]+P5^[7]+P5^[10]) / AntAussen) +

                      ((P2^[4]+P2^[7]+P2^[10] +
                        P3^[4] +P3^[10] +
                        P4^[4]+P4^[7]+P4^[10]) / AntMitte) +

                       (P3^[7] / AntInnen));

      // Wie bei Blau, jetzt mit grün
      Po^[2] := round(((P1^[5]+P1^[8]+P1^[11] +
                        P2^[2] + P2^[14] +
                        P3^[2] + P3^[14] +
                        P4^[2] + P4^[14] +
                        P5^[5]+P5^[8]+P5^[11]) / AntAussen) +

                      ((P2^[5]+P2^[8]+P2^[11] +
                        P3^[5] +P3^[11] +
                        P4^[5]+P4^[8]+P4^[11]) / AntMitte) +

                       (P3^[8] / AntInnen));

        // und bei Rot...
        Po^[3] := round((( P1^[6]+P1^[9]+P1^[12] +
                          P2^[3] + P2^[15] +
                          P3^[3] + P3^[15] +
                          P4^[3] + P4^[15] +
                          P5^[6]+P5^[9]+P5^[12]) / AntAussen) +

                        ((P2^[6]+P2^[9]+P2^[12] +
                          P3^[6] +P3^[12] +
                          P4^[6]+P4^[9]+P4^[12]) / AntMitte) +

                         (P3^[9] / AntInnen));

        // Alle Zeiger um 3 Byte erhöen - also einen Pixel nach rechts
        // (PByte deswegen, weil P1-P5 15 Bytes groß sind, und sonst auch um
        // 15 Byte verschoben würden.)
        inc(PByte(P1), 3);
        inc(PByte(P2), 3);
        inc(PByte(P3), 3);
        inc(PByte(P4), 3);
        inc(PByte(P5), 3);

        // Zeiger des Zielpixels einen Pixel nach rechts
        inc(Po, 1);
      end;

     // Alle Zeiger auf den Pixel links ziehen
     dec(PByte(P2), dekrement);
     dec(PByte(P3), dekrement);
     dec(PByte(P4), dekrement);
     dec(PByte(P5), dekrement);

     // und dann die Zeilen verschieben
     P1 := P2;
     P2 := P3;
     P3 := P4;
     P4 := P5;
     P5 := i.ScanLine[y+3]; // und die neue Zeile holen
   end;
end;
Viel Spaß damit, und wer Fehler findet darf sie behalten --- oder schickt mir besser eine PM. Aber ich hab das Teil erfolgreich im Einsatz


gruss,
dizzy

[edit=Matze]Code formatiert. Mfg, Matze[/edit]
Fabian K.
INSERT INTO HandVonFreundin SELECT * FROM Himmel
  Mit Zitat antworten Zitat