Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Überflüssigen Hindergrund bei Bildern entfernen (https://www.delphipraxis.net/175506-ueberfluessigen-hindergrund-bei-bildern-entfernen.html)

MuTzE.Y85 26. Jun 2013 19:55

Überflüssigen Hindergrund bei Bildern entfernen
 
Liste der Anhänge anzeigen (Anzahl: 2)
Hi,

ich arbeite zurzeit an einer Routine um überflüssigen Hintergrund eines Bildes zu entfernen.

Kurz erklärt:

Ich habe ein Foto von einem Gegenstand, auf einem weißen Hintergrund.
Der Hintergrund steht an jeder Seite etwas über. Ein normales Bild halt.
Jetzt möchte ich den weißen Hintergrund an jeder Seite soweit entfernen bis an jeder Seite die Außenkanten des Gegenstands an den Bildrand grenzen.

Verstanden? :)

Ein Beispielbild ist im Anhang. Das Bild soll quasi auf die Außenkannten eines Kreises verkleinert/beschnitten werden.



Mit Scanline klappt das oben und unten sehr gut.
Ich durchlaufe jede Zeile und prüfe, ob in der Zeile ein Pixel vorkommt, der nicht Weiß ist.
Finde ich einen, habe ich die Zeile wo der z.B. Kreis anfängt.

Jetzt ist nur die Frage: Wie mache ich das Vertikal? Also links und rechts.
Scanline macht ja da keinen Sinn oder?
Aber wenn ich das mit Pixels mache, dauerts doch zu lange oder?

Eine Möglichkeit wäre, das Bild um 90° zu drehen und das Ganze dann nochmal mit Scanline laufen zu lassen und wieder zurück zu drehen.


Fällt jemandem vielleicht eine bessere Lösung ein?

Namenloser 26. Jun 2013 20:35

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Wenn das Objekt konvex ist, ist dein Ansatz doch eine ganz gute Lösung. Wenn es konkav ist, ist FloodFill wahrscheinlich das, was du suchst (entspricht dem Farbeimer bei Paint).

Edit: Achso, zu Scanline: Du kannst alle Scanline-Pointer in einem Array zwischenspeichern, dann geht das auch vertikal. Oder noch besser, du sorgst dafür, dass die Scanlines im Speicher alle direkt hintereinanderstehen, dann ist es mit einfacher Pointer-Arithmethik getan. Das ist beim normalen TBitmap leider nicht gegeben, da müsstest du entweder in einen extra Speicherbereich umkopieren oder du nimmst TBitmap32 von Graphics32, da wird das so gemacht (vermutlich einer der Hauptgründe, warum Graphics32 so schnell ist im Vergleich zum normalen Canvas/Bitmap).

BUG 26. Jun 2013 21:49

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
So sollte es gehen:
Code:
var left, right, top, bottom: integer := 0;

für jede Zeile y := 0 .. height-1:
  für jede Spalte x := 0 .. width-1:
    wenn pixel[x,y] <> WEIß dann:
      top := min(top, y);
      bottom := max(bottom, y);
      left := min(left, x);
      right := max(right, x);
Das kannst du sicher so umsetzen, dass es Scanline benutzt :stupid:

Man könnte einige min und max einsparen, aber so sollte das Grundprinzip klar werden:
Gesucht ist die x-Koordinaten der nicht-weißen Pixel am weitesten links und rechts sowie die y-Koordinaten der nicht-weißen Pixel am weitesten oben und unten.

Wenn die Ränder verhältnismäßig klein sind, könnte es etwas bringen, top und bottom beziehungsweise left und right aus unterschiedlichen Richtungen zu suchen.

DeddyH 27. Jun 2013 07:56

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Das hatten wir schon einmal hier: http://www.delphipraxis.net/166570-groesse-timage.html

Sir Rufo 27. Jun 2013 08:07

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
@bug

Delphi-Quellcode:
left
und
Delphi-Quellcode:
top
werden bei deinem Ansatz aber immer 0 sein ;)
Diese Werte müssen initial auf
Delphi-Quellcode:
left := width
und
Delphi-Quellcode:
top := height
gesetzt werden ;)

BUG 27. Jun 2013 08:11

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Zitat:

Zitat von Sir Rufo (Beitrag 1219853)
Diese Werte müssen initial auf
Delphi-Quellcode:
left := width
und
Delphi-Quellcode:
top := height
gesetzt werden ;)

Stimmt :oops:

MuTzE.Y85 28. Jun 2013 23:52

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Also ob das Objekt konkav oder konvex ist spielt eigentlich keine Rolle. Es soll ja einfach nur der Anfang gefunden werden.

Also für Oben und Unten habe ich schon den Code.
Die Frage ich jetzt nur wie ich Links und Rechts prüfe.

Oben
Code:
for H := 0 to aBitmap.Height - 1 do
  begin
  // Zeile einlesen
  P := aBitmap.ScanLine[H];
     
  // Wenn Anfang noch nicht gefunden, dann prüfen
  if RowFound = False then
    begin

      for W := 0 to aBitmap.Width - 1 do
        begin
          // Wenn Pixel nicht weiß, dann Zeile merken
          if not (RowFound = True) and not (P^[1] = 255) and not (P^[2] = 255) and not (P^[3] = 255) then
            begin
              Row := H;
              RowFound := True;
            end;
          Inc(P);
        end;

    end;

  end;

Unten das Gleiche nur mit downto in der Schleife.

Prüfe ich jetzt links und rechts gleich in den schleifen oder wie mache ich das am Besten?
Momentan scheint mir die einfachste Lösung das Drehen des Bildes zu sein.
Wäre aber cool wenn es auch so gehen würde.

Sir Rufo 28. Jun 2013 23:56

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Warum machst du das nicht so wie in #3 erläutert? :gruebel:

MuTzE.Y85 29. Jun 2013 00:15

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Ich hatte das System nicht gleich verstanden.

Ich werde das bei Gelegenheit mal mit Scanline probieren.
Wenn es klappt poste ich hier gleich die Lösung.

Danke schon mal!

MuTzE.Y85 10. Jul 2013 21:24

AW: Überflüssigen Hindergrund bei Bildern entfernen
 
Für alle die das Gleiche suchen hier noch das Ganze mit Scanline:

Code:
uses
  Math;

procedure RemoveBackground(aBitmap: TBitmap);
type
  PixArray = Array [1..3] of Byte;
var
  P: ^PixArray;
  X,Y, aLeft, aBottom, aTop, aRight: Integer;
begin
  aBitmap.PixelFormat := pf24Bit;

  aTop := aBitmap.Height;
  aLeft := aBitmap.Width;
  aBottom := 0;
  aRight := 0;

  for Y := 0 to aBitmap.Height - 1 do
    begin
      P := aBitmap.ScanLine[Y];

      for X := 0 to aBitmap.Width - 1 do
        begin
          if not (P^[1] = 255) and not (P^[2] = 255) and not (P^[3] = 255) then
            begin
              aTop := Min(aTop, Y);
              aBottom := Max(aBottom, Y);
              aLeft := Min(aLeft, X);
              aRight := Max(aRight, X);
            end;
          Inc(P);
        end;
    end;

  aBitmap.Canvas.CopyRect(Rect(0, 0, aBitmap.Width - aLeft - (aBitmap.Width - aRight) + 1, aBitmap.Height - aTop - (aBitmap.Height - aBottom) + 1), aBitmap.Canvas, Rect(aLeft, aTop, aRight + 1, aBottom + 1));
  aBitmap.Height := aBitmap.Height - aTop - (aBitmap.Height - aBottom) + 1;
  aBitmap.Width := aBitmap.Width - aLeft - (aBitmap.Width - aRight) + 1;
end;
Danke nochmal speziell an BUG und Sir Rufo!


Alle Zeitangaben in WEZ +1. Es ist jetzt 21:02 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz