Servus!
Ich habe eine Bitmap (640x480, 32Bit) in einem TMemoryStream vorliegen. Die ersten 54 Bytes enthalten die Header-Informationen, dann folgt der Rot-Anteil des linken unteren Pixels und das letzte Byte ist der Blau-Anteil des rechten oberen Bildpunkts. Damit ist die Größe 640 (Breite) x 480 (Höhe) x 4 (32Bit) + 54 = 1.228.854 Bytes.
Nun möchte ich das Bild in 4x4=16 Sektionen aufteilen, wobei das Teil links unten die Nummer 1, und das rechts oben die Nummer 16 ist. Alle Pixel-Daten werden nun der Reihe nach bearbeitet und hier ist mein Problem: Ich muß wissen, zu welchem Teilstück die gerade bearbeiteten Daten gehören. Das Ganze mit if-Abfragen aus der Position im Stream zu machen scheidet aus, einerseits ist das viel zu aufwendig, andererseits dauert das auch viel zu lang. Unter Umständen könnte ich mit einer Art Look-Up arbeiten.
Sollte jedoch jemand eine Idee haben, wie man die Sektion schnell berechnen kann, dann wäre mir diese Information höchst willkommen.
Gruß,
Adrian
Anm.: Formel und Header-Bytes korrigiert
Bitmap, Pixel-Position im Stream
-
- Beiträge: 31
- Registriert: Mo 12. Nov 2007, 12:41
- OS, Lazarus, FPC: Winux (L 2.0.6 FPC 3.0.4)
- CPU-Target: 64Bit
Bitmap, Pixel-Position im Stream
Zuletzt geändert von Adrian am Do 21. Sep 2017, 08:19, insgesamt 1-mal geändert.
-
- Beiträge: 1102
- Registriert: Di 5. Aug 2008, 09:37
- OS, Lazarus, FPC: Windows ,Linux,FreeBSD,Dos (L trunk FPC trunk)
- CPU-Target: 32/64,PPC(+64), ARM
- Wohnort: Eindhoven (Niederlande)
Re: Bitmap, Pixel-Position im Stream
( y div (480 div 4))*4+(x div (640 div 4)) ?
-
- Beiträge: 758
- Registriert: Di 23. Aug 2016, 14:25
- OS, Lazarus, FPC: Windows 11
- CPU-Target: 64Bit
- Wohnort: Berlin
Re: Bitmap, Pixel-Position im Stream
Unter Windows würde es mit der BitBlt Funktion recht einfach gehen:
So in etwa sollte das funktionieren:
Es wird das komplette Bild in eine Bitmap geladen,
dann werden die einzelnen Ausschnitte mittels BitBlt in separate Bitmaps kopiert.
Mit folgendem Code, bei OnPaint, kann man sich das Ergebnis dann ansehen:
getesteter Beispiel Code:
So in etwa sollte das funktionieren:
Code: Alles auswählen
var QuellBitmap : TBitmap;
var ZielBitmap : Array[0..3,0..3] of TBitmap;
procedure TForm1.FormCreate(Sender: TObject);
var b:TBitmap;
var x,y,w,h:Integer;
var q:TBitmap;
begin
QuellBitmap:=TBitmap.create;
QuellBitmap.LoadFromFile('TestBild.bmp');
w:=640 DIV 4;
h:=480 DIV 4;
{ Ziel Bitmap Objekte erzeugen }
for x:=0 to 3 do for y:=0 to 3 do begin
ZielBitmap[x,y]:=TBitmap.create;
ZielBitmap[x,y].SetSize(w,h); { Breite und Höhe der Bitmaps setzen }
BitBlt(
ZielBitmap[x,y].canvas.handle, { Handle der Ziel Bitmap }
0, { Ziel Koordinate X = 0 }
0, { Ziel Koordinate Y = 0 }
w, { Breite der ZielBitmap }
h, { Höhe der ZielBitmap }
QuellBitmap.canvas.Handle, { Handle der Quell Bitmap }
w*x, { Quellposition X Position innerhalb der großen Bitmap }
h*y, { Quellposition Y Position innerhalb der großen Bitmap }
SRCCOPY); { Kopierfunktion }
end;
dann werden die einzelnen Ausschnitte mittels BitBlt in separate Bitmaps kopiert.
Mit folgendem Code, bei OnPaint, kann man sich das Ergebnis dann ansehen:
Code: Alles auswählen
for x:=0 to 3 do for y:=0 to 3 do
canvas.Draw(x*200,y*200,ZielBitmap[x,y]);
getesteter Beispiel Code:
Zuletzt geändert von siro am Mi 20. Sep 2017, 11:32, insgesamt 1-mal geändert.
Grüße von Siro
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Bevor ich "C" ertragen muß, nehm ich lieber Lazarus...
Re: Bitmap, Pixel-Position im Stream
Wieder ein schönes Ratespiel, was du genau vorhast... Aus der Bemerkung "Bitmap in einem Memorystream" vermute ich, dass du vielleicht die Blockeinteilung direkt aufgrund der Stream-Position vornehmen möchtest, ohne den Stream in ein TBitmap einzulesen. Für den Spezialfall eines unkomprimierten 32-bit-Bitmaps der Breite AWidth kann man die Pixel-Koordinaten X, Y folgendermaßen berechnen:
Anschließend kannst du mit Marco's Formel die Block-Nr berechnen. Das folgende Programm ordnet der Blocknummer eine Farbe zu und schreibt diese direkt in den Stream (Form mit 1 Image und zwei Buttons, beide mit derselben OnClick-Prozedur):
Übrigens: der BMP-Header ist 54 byte lang, nicht 64.
Code: Alles auswählen
uses
bmpcomn;
procedure StreamPosToXY(AStream: TStream; AWidth: Integer; out X,Y: Integer);
const
HeaderSize = SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader); // ist 54, nicht 64!
PixelSize = 4; // 1 Pixel umfasst 32 Bit, also 4 Byte
var
pixelNr: Integer;
begin
pixelNr := (AStream.Position - HeaderSize) div PixelSize;
X := pixelNr mod AWidth;
Y := pixelNr div AWidth;
end;
Code: Alles auswählen
uses
bmpcomn;
const
HEADER_SIZE = SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfoHeader); // ist 54, nicht 64!
procedure StreamPosToXY(AStream: TStream; AWidth: Integer; out X,Y: Integer);
const
PIXEL_SIZE = 4; // 1 Pixel umfasst 32 Bit, also 4 Byte
var
pixelNr: Integer;
begin
pixelNr := (AStream.Position - HEADER_SIZE) div PIXEL_SIZE;
X := pixelNr mod AWidth;
Y := pixelNr div AWidth;
end;
function BlockNr(X, Y, AWidth, AHeight: Integer): Integer;
begin
Result := (Y div (AHeight div 4))*4 + X div (AWidth div 4);
end;
{ TForm1 }
procedure TForm1.Button1Click(Sender: TObject);
const
BLOCK_COLOR: array[0..15] of TColor = (
clBlack, clMaroon, clGreen, clOlive,
clNavy, clPurple, clTeal, clGray,
clSilver, clRed, clLime, clYellow,
clBlue, clFuchsia, clAqua, clLtGray);
W = 640;
H = 480;
var
bmp: TBitmap;
ms: TMemoryStream;
c: TColor;
x, y: Integer;
block: Integer;
begin
ms := TMemoryStream.Create;
try
bmp := TBitmap.Create;
try
bmp.PixelFormat := pf32Bit; // GANZ wichtig!
bmp.SetSize(W, H);
bmp.canvas.Brush.Color := clMoneyGreen;
bmp.Canvas.FillRect(0, 0, bmp.Width, bmp.Height);
bmp.SaveToStream(ms);
if Sender = Button1 then begin
Image1.Picture.Assign(bmp);
exit;
end;
finally
bmp.Free;
end;
ms.Position := HEADER_SIZE;
while ms.Position < ms.Size do begin
StreamPosToXY(ms, W, x, y);
block := BlockNr(x, y, W, H);
c := BLOCK_COLOR[block];
ms.Write(c, Sizeof(TColor));
end;
ms.Position := 0;
Image1.Picture.LoadFromStream(ms);
finally
ms.Free;
end;
end;
-
- Beiträge: 31
- Registriert: Mo 12. Nov 2007, 12:41
- OS, Lazarus, FPC: Winux (L 2.0.6 FPC 3.0.4)
- CPU-Target: 64Bit
Re: Bitmap, Pixel-Position im Stream
Danke, vor allem an marcov, das war genau die Lösung, die ich nicht gefunden habe.
Gruß,
Adrian
Gruß,
Adrian