![]() |
Ü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? |
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). |
AW: Überflüssigen Hindergrund bei Bildern entfernen
So sollte es gehen:
Code:
Das kannst du sicher so umsetzen, dass es Scanline benutzt :stupid:
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); 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. |
AW: Überflüssigen Hindergrund bei Bildern entfernen
Das hatten wir schon einmal hier:
![]() |
AW: Überflüssigen Hindergrund bei Bildern entfernen
@bug
Delphi-Quellcode:
und
left
Delphi-Quellcode:
werden bei deinem Ansatz aber immer 0 sein ;)
top
Diese Werte müssen initial auf
Delphi-Quellcode:
und
left := width
Delphi-Quellcode:
gesetzt werden ;)
top := height
|
AW: Überflüssigen Hindergrund bei Bildern entfernen
Zitat:
|
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. |
AW: Überflüssigen Hindergrund bei Bildern entfernen
Warum machst du das nicht so wie in #3 erläutert? :gruebel:
|
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! |
AW: Überflüssigen Hindergrund bei Bildern entfernen
Für alle die das Gleiche suchen hier noch das Ganze mit Scanline:
Code:
Danke nochmal speziell an BUG und Sir Rufo!
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; |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:56 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz