Registriert: So Jan 07, 2007 21:26 Beiträge: 130 Wohnort: mal hier mal da mal irgendwo
Hi Leute,
ein sonderbares Problem hält mich jetzt schon seit ca. 2 Wochen auf. Ich habe via Ressource 2 Bitmaps ("edge00" und "egde11") zur Verfügung. Beide wurden mit Gimp erstellt und mit gleichem Format gespeichert (24 bit R8 G8 B8). An sich sind nur die Farben schwarz(0,0,0), rot(255,0,0), blau(0,0,255) und grün(0,255,0) vorhanden. Dazu kommt dass jeweils nur ein Pixel im gesamten Bild blau ist.
Aus Performance-Gründen arbeite ich mit ScanLine & dem Pixelformat pf24bit:
Code:
procedure LoadMasks(); var b: TBitmap; p: PScanLine; mark: TPoint; x,y: Integer; function Pixel(const px,py: Integer): PBGR; begin Result := @p[px+b.Width*(b.Height-(py+1))]; end; function CEqual(const a,b: TBGR): boolean; begin Result := (a.r=b.r)and(a.g=b.g)and(a.b=b.b); end; begin;
desweiteren greife ich auf die einzelnen Pixeldaten zu in dem ich den Zeiger auf den Beginn der Bilddaten in einer Variablen speicher und den Index berechne:
Code:
procedure LoadMasks(); var b: TBitmap; p: PScanLine; mark: TPoint; x,y: Integer; function Pixel(const px,py: Integer): PBGR; begin Result := @p[px+b.Width*(b.Height-(py+1))]; end; function CEqual(const a,b: TBGR): boolean; begin Result := (a.r=b.r)and(a.g=b.g)and(a.b=b.b); end; begin
Die Bitmaps lade ich so:
Code:
b := TBitmap.Create; try SetLength(MaskLT, 0); b.HandleType := bmDIB; b.PixelFormat := pf24bit; b.LoadFromResourceName(hInstance, 'edge00'); p := b.ScanLine[b.Height-1];
Dann suche ich nach den Koordinaten von dem blauen Pixel. Und genau da beginnt mein Problem. Bei "edge00" wird er noch gefunden, bei "egde11" aber nicht mehr =/ Hier noch mal der relevante Code zusammenhängend:
Code:
TMaskPixel = record Equal: Boolean; X,Y: Integer; end; TBGR = record b,g,r: Byte; end; PBGR = ^TBGR; TScanLine = Array[0..0] of TBGR; PScanLine = ^TScanLine;
var MaskLT, MaskRB: Array of TMaskPixel;
function RGB(r,g,b: Byte):TBGR;overload; begin Result.r := r; Result.g := g; Result.b := b; end;
procedure LoadMasks(); var b: TBitmap; p: PScanLine; mark: TPoint; x,y: Integer; function Pixel(const px,py: Integer): PBGR; begin Result := @p[px+b.Width*(b.Height-(py+1))]; end; function CEqual(const a,b: TBGR): boolean; begin Result := (a.r=b.r)and(a.g=b.g)and(a.b=b.b); end; begin //edge00 mask b := TBitmap.Create; try SetLength(MaskLT, 0); b.HandleType := bmDIB; b.PixelFormat := pf24bit; b.LoadFromResourceName(hInstance, 'edge00'); p := b.ScanLine[b.Height-1]; for x := 0 to b.Width-1 do for y := 0 to b.Height-1 do if CEqual(Pixel(x,y)^,RGB(0,0,255)) then mark := Point(x,y); for x := 0 to b.Width-1 do for y := 0 to b.Height-1 do if (CEqual(Pixel(x,y)^,RGB(255,0,0)))or(CEqual(Pixel(x,y)^,RGB(0,255,0))) then begin SetLength(MaskLT, Length(MaskLT)+1); MaskLT[High(MaskLT)].Equal := CEqual(Pixel(x,y)^,RGB(255,0,0)); MaskLT[High(MaskLT)].X := x-mark.X; MaskLT[High(MaskLT)].Y := y-mark.Y; end; finally b.Free; end;
//edge11 mask b := TBitmap.Create; try SetLength(MaskRB, 0); b.HandleType := bmDIB; b.PixelFormat := pf24bit; b.LoadFromResourceName(hInstance, 'edge11'); p := b.ScanLine[b.Height-1]; for x := 0 to b.Width-1 do for y := 0 to b.Height-1 do if CEqual(Pixel(x,y)^,RGB(0,0,255)) then //ist irgendwie niemals true =| mark := Point(x,y); for x := 0 to b.Width-1 do for y := 0 to b.Height-1 do if (CEqual(Pixel(x,y)^,RGB(255,0,0)))or(CEqual(Pixel(x,y)^,RGB(0,255,0))) then begin SetLength(MaskRB, Length(MaskRB)+1); MaskRB[High(MaskRB)].Equal := CEqual(Pixel(x,y)^,RGB(255,0,0)); MaskRB[High(MaskRB)].X := x-mark.X; MaskRB[High(MaskRB)].Y := y-mark.Y; end;
finally b.Free; end; end;
Ich weiß nun echt keine Rat mehr, da ich ja an sich exakt das gleiche bei edge11 wie bei edge00 mache ... Im Anhang sind die Bitmaps die ich als Ressource einbinde:
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
_________________ Wenn Worte nichts als Worte sind, dann müssen's Steine sein! Solange - bis sie pleite sind - schmeißt Fensterscheiben ein! - Fidl Kunterbunt -
Registriert: Do Sep 02, 2004 19:42 Beiträge: 4158
Programmiersprache: FreePascal, C++
Die Farbwerte stimmen. Aber geh mal deine Indicies durch. Irgendwo da wird der Fehler liegen, es ist auffällig, dass der blaue Punkt bei edge11 an der oberen Kante liegt. Schau mal, ob er erkannt wird, wenn er einen Pixel weiter unten liegt. Wenn ja, prüf mal deine Indicies.
greetings
_________________ If you find any deadlinks, please send me a notification – Wenn du tote Links findest, sende mir eine Benachrichtigung. current projects: ManiacLab; aioxmpp zombofant network • my photostream „Writing code is like writing poetry“ - source unknown
„Give a man a fish, and you feed him for a day. Teach a man to fish and you feed him for a lifetime. “ ~ A Chinese Proverb
Registriert: Do Dez 05, 2002 10:35 Beiträge: 4234 Wohnort: Dortmund
Hu Hu. Auch auf die Gefahr hin mich unbeliebt zu machen. Aber du hast zu mindest einen gravierenden Fehler in deinem Code. Dein TBGR beinhaltet 3 Bytes. Das normale Alignment steht aber auf 4. Also wird deine Struktur vom Compiler erweitert. Also muss das Record packed sein. Ich behaupte jetzt auch einfach mal, dass, wenn dein Rot 254 und dein Grün 253 wäre du kein Blau bekommen würdest mit einem Wert von 255.
Was potentiell problematisch ist ist ein Array[0..0]. Falls jemand die Bereichprüfung aktiv hat (sollte immer der Fall sein) knallt der Code dort. Wie ich finde zu recht. Wenn du die Prüfung deaktiv hast verdeckst du eventuell andere richtige Fehler. Zu mindest ist das aber kein guter Stil. Wie ich finde.
Das Setzen des Pixelformates ist sinnlos. Du setzt zwar das Pixelformat. Allerdings liest du anschließend erst das Bild ein. Damit wird das Pixelformat wieder mit dem Format überbügelt welches in dem Bitmap steht. Also erst laden und dann kann es manipuliert werden. Denn das ist es.
Ob die Berechnungen stimmen keine Ahnung. Ich würde es vom Code her wesentlich einfacher gestalten. Denn so etwas sorgt für mehr klarheit und reduziert mögliche Fehler. Hinzu kommt, dass du das Pixel, CEqual und RGB in jeweils einer Methode hast die du 3-4 mal Pro Pixel aufrufst. Du Berechnest also 3-4 mal die Position und musst das dann immer wieder vergleichen. Der Aufruf einer Methode kostet immer Zeit. Auch wenn es nicht viel ist. Bei einem Code der recht oft aufgerufen wird sumiert sich das recht schnell. RGB ist auch so ein Fall. Du erstellt für jedes Pixel jeweils einmal eine Struktur mit immer den gleichen Werten. Da wäre es sinnvoller die Werte zu mindest in Variablen zu sichern. Es sei denn das soll irgendwann wesentlich dynamischer werden. Aber das kann ich so von deinem Code her nicht erkennen.
Ich würde eine Methode machen an die den Namen und das Array übergibst. Das Array muss dabei ein eigener Typ sein und als var übergeben. In der Methode würde ich das Bitmap laden und dann durch die einzelnen Scanlines durchgehen. Die Scanline wäre dann vom Type PRGB. Wenn du diesen mit Inc erhöhst, dann vergrößert der Compiler den Pointer automatisch um die Größe des Records. Also 3.
Als kleine Optimierung kannst du das auch so machen, dass du zu erst durch alle Pixel gehst und dir die absoluten Positionen und die Position des Blauen speicherst. Anschließend gehst du durch die gefundenen Stellen durch und relativierst die Positionen. Gibt natürlich noch viel viel mehr Optimierungsmöglichkeiten. Aber Aufgrund der jetzigen Größe des Posts spare ich mir das.
Code:
type TBGR = packed record b,g,r: Byte; end; PBGR = ^TBGR;
TMask: Array of TMaskPixel;
procedure Blah(Name: String; var Mask: TMask); var pLine: PRGB; begin SetLength(Mask, 0);
b := TBitmap.Create; try b.LoadFromResourceName(hInstance, Name); b.PixelFormat := pf24bit;
for y := 0 to b.Height-1 do begin pLine := b.ScanLine[y];
for x := 0 to b.Width-1 do begin if (pLine^.B = 255) then // Blau merken mark := Point(X, Y) else if (pLine^.R = 255) or (pLine^.G = 255) then begin // punkt hinzufügen SetLength(Mask, Lenght(Mask) +1); Mask[High(Mask)] := ... end;
inc(pLine); end; end;
for Idx := Low(Mask) to High(Mask) do begin Mask[Idx].X := Mask[Idx].X - mark.X; Mask[Idx].Y := Mask[Idx].Y - mark.Y; end; finally b.Free; end; end;
var MaskLT, MaskRB: TMask
Blah('edge00'; MaskLT); Blah('edge11'; MaskRB);
So könnte das zum Beispiel aussehen. Ist nur ein Vorschlag. Wie du das machst ist deine Sache. Scanline benutze ich deswegen für jede Zeile seperat, da Bitmapzeilen auch 4Byte aligned sind und du deswegen am Ende einer Zeile auch mal 1-3 Byte Spacer haben kannst. In Abhängigkeit zur Breite des Bitmaps. Eventuell solltest du auch noch überprüfen ob überhaupt ein blauer Pixel gefunden wurde. Wenn nicht musst du deinem Code entsprechend auch reagieren und die Ergebnisse ignorieren oder Fehler werfen.
Registriert: So Jan 07, 2007 21:26 Beiträge: 130 Wohnort: mal hier mal da mal irgendwo
Im Endeffekt lag es daran dass ich das "packed" bei TBGR vergessen hab Es hat dann einwandfrei funktioniert, allerdings klingt Lossy's Empfehlung besser so das ich es nun auch so übernommen habe.
Danke für die Hilfe :]
_________________ Wenn Worte nichts als Worte sind, dann müssen's Steine sein! Solange - bis sie pleite sind - schmeißt Fensterscheiben ein! - Fidl Kunterbunt -
Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.