Einzelnen Beitrag anzeigen

berens

Registriert seit: 3. Sep 2004
430 Beiträge
 
Delphi 2010 Professional
 
#6

AW: BitmapCompare nicht zuverlässig / Scanline Problem?

  Alt 24. Jan 2019, 20:17
Danke für die Antworten.

Das ScanLine-Beispiel habe ich auch zur Verifizierung meines Codes verwendet; ich kann nichts erkennen, was ich falsch gemacht hätte.

Zitat:
Na ja Du vergleichst Äpfel mit Birnen......
Nunja, hier muss ich doch Einspruch erheben. Trotzdem erstmal danke, dass Du Dich mit dem Thema auseinandersetzt.
Man muss natürlich berücksichtigen, dass der Code aus dem Anhang zur Verdeutlichung angepasst und erweitert wurde, was in der fertigen Version natürlich so nicht sein soll. Doch zum eigentlichen Thema:

Delphi-Quellcode:
// Hier vergleichst Du Byte......
    if Pix1[x] <> Pix2[x] then begin
Das hier ist der Code, der in der fertigen Version verwendet werden soll. Beide Bitmaps sind im Pixelformat 32-Bit, entsprechend sollte Pix1[x] ein 4 Byte langer Wert sein (jede Farbe R G B und der Alphakanal; jeweils ein Byte). Somit kann ich imo durchaus sagen: Wenn Bild1[x] = Bild2[x], dann sind die Farben Rot, Grün, Blau und der Alpha Wert auf beiden Seiten identisch. Halten wir das erstmal so fest: Ich vergleiche vergleichbare Werte, und erhalte das Ergebnis: Die Farben auf beiden Bildern sind 1:1 identisch.

Delphi-Quellcode:
        end else begin // bedeutet Pix1[x] = Pix2[x]
          c1 := pic1.Canvas.Pixels[x,y];
          c2 := pic2.Canvas.Pixels[x,y];
// und hier Integer
          if c1 <> c2 then begin
An dieser Stelle muss man betonen, dass es nur die detaillierte Fehlersuche darstellt. Das Else bedeutet ja automatisch in diesem Zusammenhang "Pix1[x] = Pix2[x]". Das bedeutet wiederum: der Pixel in Bild1 ist 1:1 identisch mit dem Pixel in Bild2.
Nun lese ich mit (der exorbitant langsamen) Funktion "Pixels" die Farbe (TColor) genau der selben Pixel aus, die ich eben schon mit Scanline geprüft habe. ScanLine sagte ja, dass genau dieser Pixel in Bild 1 und 2 jeweils für R, G, B und A den Wert "0" hat, und somit auf beiden Bildern identisch ist (in beiden Bildern "Schwarz", obwohl eigentlich in Bild 2 "grün"). c1 besagt nun: in Bild 1 ist der Pixel Schwarz (korrekt) und: in Bild 2 ist dieser Pixel grün (korrekt).

Durch die Verschachtelung der Anweisungen habe ich im Endeffekt die Abfrage "Sind die Pixel auf beiden Bildern identisch? (Scanline-Verfahren)" und "Sind die Pixel auf beiden Bildern identisch? (Pixel-Verfahren)". Beide Abfragen müssen korrekterweise das gleiche ausgeben, tun sie aber nicht - ScanLine liefert eine falsche Antwort.

Das Vergleichsverfahren kann ich nicht komplett auf die "Pixels"-Prüfung umstellen, da diese viel zu langsam ist; ich muss mit ScanLine Arbeiten. Das Pixelsverfahren ist hier nur einprogrammiert, um den Fehler von Scanline "nachweisen" zu können.

Also: Was mache ich an ScanLine falsch?

Zwecks lesbarkeit, hier nochmal die aktuelle Version:
Delphi-Quellcode:
function BitmapCompare(pic1, pic2: Graphics.Tbitmap): Boolean;
var
  Pix1, Pix2 : PByte;
  y, k, x : Integer;
  c1, c2: TColor;
const
  PixelFormatBytes: Array[TPixelFormat] of Byte = ( 0, 0, 0, 1, 0, 2, 3, 4, 0 );
begin
  result:=false;
  try
    if PixelFormatBytes[pic1.PixelFormat] <> PixelFormatBytes[pic2.PixelFormat] then Exit;
    if PixelFormatBytes[pic1.PixelFormat] = 0 then Exit; // PixelFormat wird nicht unterstützt
    if (pic1.Width <> pic2.Width) or (pic1.Height <> pic2.Height) then Exit;

    for y := 0 to pic2.Height - 1 do
    begin
      Pix1 := pic1.Scanline[y];
      Pix2 := pic2.Scanline[y];
      for x := 0 to pic2.Width - 1 do begin

        if (x = 4) and (y = 0) then begin
          c1 := pic1.Canvas.Pixels[4,0];
          c2 := pic2.Canvas.Pixels[4,0];
          sleep(0);
        end;

        if Pix1[x] <> Pix2[x] then begin
          Exit; // ungleich, verlasse deshalb routine. Result ist in diesem Falle = False ...
        end else begin // bedeutet Pix1[x] = Pix2[x]
          c1 := pic1.Canvas.Pixels[x,y];
          c2 := pic2.Canvas.Pixels[x,y];
          if c1 <> c2 then begin
            ShowMessage('ACHTUNG: Farbe unterschiedlich, obwohl Scanline angeblich identisch???'
                        + #13#10#13#10 + IntToStr(c1) + ' // ' + IntToStr(c2));
          end;
        end;

      end;
    end;
    Result := true;
  except
    on E: SysUtils.Exception do begin
    end;
  end;
end;
Delphi 10.4 32-Bit auf Windows 10 Pro 64-Bit, ehem. Delphi 2010 32-Bit auf Windows 10 Pro 64-Bit
  Mit Zitat antworten Zitat