Bitmap unterschiedlich Linux und Windows

Für Probleme bezüglich Grafik, Audio, GL, ACS, ...
Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Ich bin dabei mich mit der Konvertierung von Bildern im Bayerformat zu Bitmap (oder) ähnlich zu beschäftigen. Dabei ist mir aufgefallen, das eine Bitmap unter Windows aus 3 Bytes hintereinander und unter Linux X64 auf 4 Bytes hintereinander im Speicher besteht.

Anbei ist das Testprogramm das auch einem Rohdatenbild das ganze in eine Bitmap konvertieren soll. Läuft unter windows mal so halbwegs. Mit dem Algorithmus bin ich noch nicht zufrieden, erst stört mich das verhalten der Bitmap.

Das Beispielbild muss ich erst woanders hochladen, da leider hier eine Platzbeschränkung ist und das Rohdatenbild 10MB groß ist.

Meine Frage ist, gibt es ein anders Format in Lazarus, das ich auch für die Konvertierung heranziehen könnte ? Es müsst einen zusammenhängenden RGB Bytebereich bereitstellen.

Edit: Bild= https://drive.google.com/file/d/1qLslG9 ... sp=sharing
Dateianhänge
TestConvert.zip
(6.03 KiB) 5-mal heruntergeladen
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 621
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Winni »

Hallo!

Unter Linux gibt es interessante Artefakte.

Das war wohl nicht im Sinne des Erfinders.

Siehe Anhang.

Winni
Dateianhänge
convertRAW.png
convertRAW.png (811.08 KiB) 444 mal betrachtet

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Das ist kein Artefakt, änder mal den Divisor in der srggb82rgb.pas

Code: Alles auswählen

procedure SGBRG8_to_BGRA(src: PByte; dest: PByte; w, h: integer);
var
  //blue,
  //start_with_green:cint;
  res : integer;
  x: cvsize;
  wx: cint;
begin
  x.width:=w;
  x.height:=h;
  wx:= w * 4;  // 4 * for RGB unter Linux
  res := icvBayer2BGR_8u_C1C3R(src,w ,dest, wx ,x,-1,1);
end;
Das ist genau der Unterschied den ich meinte zwischen Windows und Linux.
Screenshot
Screenshot
Screenshot.jpg (57.28 KiB) 434 mal betrachtet
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 621
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Winni »

Hi!

Nö. Anpassung für Linux ergibt genau das gleiche Bild.
Da muss der Wurm woanders sitzen-

Winni

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Mein Bild mit der Änderung stammt von Debian Buster X64. Das passt schon. Zusätzlich habe ich auch in der Wiki gefunden, das ein pf24bit Bild unter Linux Gtk2 4 Bytes statt 3 im Speicher belegt. Sozusagen 3x8=32 :shock:
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 621
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Winni »

Hi!

Ich hab auch Deine Änderung vorgenommen, aber es bleibt beim "4-fachBild " von oben.

Hast Du noch ne weitere Änderung vorgenommen?

Lin64 auf Suse Tumbleweed. fpc 3.2, laz 2.0.12

Winni

Michl
Beiträge: 2387
Registriert: Di 19. Jun 2012, 12:54

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Michl »

Habs eben getestet. Man könnte auch sowas machen (TlazIntImage, TRawImage) und das dann einfach dem TBitmap übergeben:

Code: Alles auswählen

procedure TForm1.Button1Click(Sender: TObject);
var
  aRect:TRect;
  w,h,s, y, x: integer;
  LImage: TLazIntfImage;
  LRawImage: TRawImage;
  ImgHandle, ImgMaskHandle: HBitmap;
  b: Byte;
begin
  w:= 3872;
  h:= 2764;
  s:= w*h;

  LRawImage.Init;
  {$IFDEF Windows}
  LRawImage.Description.Init_BPP24_R8G8B8_BIO_TTB(w, h);
  {$ELSE}
  LRawImage.Description.Init_BPP32_B8G8R8A8_M1_BIO_TTB(w, h);
  {$ENDIF}
  LRawImage.CreateData(True);
  LImage := TLazIntfImage.Create(0, 0);
  LImage.SetRawImage(LRawImage);

  BMP:=TBitmap.Create;
  try
//    BMP.PixelFormat:=pf24bit;
//    BMP.SetSize(w,h);
    // Stream read
    aMS:= TMemoryStream.Create;
    try
      aMS.LoadFromFile('SGRBG8.raw');
      LImage.SetSize(w, h);
      if aMS.Size = s then
      begin
        aMS.Position:= 0;
        for y := 0 to h - 1 do
          for x := 0 to w - 1 do
          begin
            b := aMS.ReadByte;
            LImage.Colors[x, y] := TColorToFPColor(RGBToColor(b, b, b));
          end;
        LImage.CreateBitmaps(ImgHandle,ImgMaskHandle,false);
        BMP.Handle:=ImgHandle;
        BMP.MaskHandle:=ImgMaskHandle;
//        BMP.BeginUpdate;
//        cnt:=BMP.RawImage.DataSize;
//        SGBRG8_to_BGRA(aMS.Memory , BMP.RawImage.Data, w, h);
//        BMP.EndUpdate;
        // Zeichnen
        aRect.Left:=0;
        aRect.Top:=0;
        aRect.Height:=PaintBox.Height;
        aRect.Width:=Paintbox.Width;
        PaintBox.Canvas.StretchDraw(aRect,BMP);
      end
      else
        ShowMessage('Kein Bild gefunden');
    finally
      aMS.Free;
      aMS:= nil;
    end;
  finally
    BMP.Free;
    BMP:= nil;
    LImage.Free;
  end;
end; 
Siehe https://wiki.freepascal.org/Developing_ ... TLazCanvas

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Die ist gut, nur ich habe das Bild normalerweise nur als Pointer zur Verfügung. Das laden über den Stream simuliert nur den Vorgang, den ich normalerweise von V4L bekomme. Deswegen muss ich auch mit der Funktion die Umwandlung vom Bayerformat nach RGB bzw. BGR machen. Die Conversion ist das wichtige. Das ist eigentlich ein Farbbild, auch wenn es noch nicht so aussieht. Das deBayering des Buffers ist mein Target. Nur haben mir das die Unterschiede Windows und Linux kräftig dazwischengefunkt.

Edit: Das ist der Originalcode um die Daten aus V4L2 zu bekommen. Ich erhalte original einen Buffer der klassischerweise Byteorientiert ist und darf dann die Rohdaten entsprechend der Kodierung des Systems umwandeln. Ist verleichsweise so, als würdest du ein RAW-Bild einer Spiegelreflexkamera bekommen. Von der Kamera und V4L bekommst du also einen Block mit Bytes, den du dann entsprechend Umwandeln musst. Ich habe mir nur die Daten mal im Rohdatenformat herausschreiben lassen, damit ich das ohne dem ganzen Overhead testen kann.

Der Basiscode ist von (Don) Alfred(o) (der von fpcupdeluxe) und hier https://github.com/LongDirtyAnimAlf/ZXing.Delphi zu finden.

Code für DeBayering ist von marcov aus dem englischen Forum (SRGGB8_to_BGRA). Original eine Umsetzung aus dem OpenCV Code.

Code: Alles auswählen

procedure TFormVideoTmp.VideoFrameSynchronized(Sender: TObject;
  Buffer: pointer; Size: integer; Error: boolean);
var
  IsDebug: boolean;
  aRect:TRect;
begin
  // Verhindert retrigger
  if (FScanInProgress) then begin
    Debugln(DateTimeToStr(now) + {$I %FILE%} + '->' +{$I %CURRENTROUTINE%} + ' retrigger inhibit');
    exit;
  end;
  // Prüfen wir ob gerade das Fenster offen haben, weil dann wollen wir was sehen
  IsDebug:= self.IsVisible;
  if (PicFinished) then begin
    FFrameTake:=0;
    if IsDebug then PicFinished:= false;
    exit;
  end;
  { This code will take every 2 frames. }
  inc(FFrameTake);
  if ((FFrameTake mod 2) <> 0) then begin
    exit;
  end;
  FScanInProgress:=True;
  try
    {$IfDef deBayer}
    // V4L2_PIX_FMT_SRGGB8 für theImageSource möglich
    if Video.PixelFormat = V4L2_PIX_FMT_SRGGB8 then
    begin
     //aMS.Clear;
      //aMS.Position:=0;
      //aMS.WriteBuffer(Buffer^,Size);
      //aMS.Position:=0;
      //aMS.SaveToFile('/tmp/SRGGB8.raw');
      BMP.BeginUpdate;
      SRGGB8_to_BGRA(PByte(Buffer), PByte(BMP.RawImage.Data), BMP.Width, BMP.Height);
      BMP.EndUpdate;
    end;
    //V4L2_PIX_FMT_SGBRG8
    if Video.PixelFormat = V4L2_PIX_FMT_SGRBG8 then
    begin
      //aMS.Clear;
      //aMS.Position:=0;
      //aMS.WriteBuffer(Buffer^,Size);
      //aMS.Position:=0;
      //aMS.SaveToFile('/tmp/SGRBG8.raw');
      BMP.BeginUpdate;
      SGBRG8_to_BGRA(PByte(Buffer), PByte(BMP.RawImage.Data), Video.Width, Video.Height);
      BMP.EndUpdate;
    end;
    {$EndIf}

    if Video.PixelFormat = V4L2_PIX_FMT_YUYV then
    begin
      BMP.BeginUpdate;
      YUYV_to_BGRA(PLongWord(Buffer), PLongWord(BMP.RawImage.Data), BMP.Width*BMP.Height);
      BMP.EndUpdate;
    end;

    if Video.PixelFormat = V4L2_PIX_FMT_MJPEG then
    begin
      aMS.Clear;
      aMS.Position:=0;
      aMS.WriteBuffer(Buffer^,Size);
      aMS.Position:=0;
      aImage.LoadFromStream(aMS,aImgReader);
      aMS.Clear;
      aMS.Position:=0;
      aImage.SaveToStream(aMS,aImgWriter);
      aMS.Position:=0;
      BMP.BeginUpdate;
      Move(aMS.Memory^,PByte(BMP.RawImage.Data)^,Video.Width*Video.Height*aImgWriter.Bpp);
      BMP.EndUpdate;
    end;
    if IsDebug then begin
      aRect.Left:=0;
      aRect.Top:=0;
      aRect.Height:=PaintBox.Height;
      aRect.Width:=Paintbox.Width;
      PaintBox.Canvas.StretchDraw(aRect,BMP);
    end;
    PicFinished:= True;
  finally
    FScanInProgress:=False;
  end;
end;
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Michl
Beiträge: 2387
Registriert: Di 19. Jun 2012, 12:54

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Michl »

Bin da jetzt nicht gerade ein Profi was Grafik angeht, aber so richtig weiß ich nicht, warum es nicht gehen sollte, selber die Bytes, die du roh bekommst, in die Daten zu schreiben. Wenn ich dich richtig verstanden habe, ist die Rohdatenreihenfolge hierbei, egal ob Windows/Linux, doch identisch?!

Falls es hilft, soviel ich weiß, kann man dem TBitmap in Linux die 32bit nicht austreiben, jedoch kann man dem TBitmap unter Windows einen Alphakanal zufügen. Dann würden es zumindest 32bit sein. Testen müsste man aber noch, ob es dann RGBA, BGRA, ARGB oder sonstwas ist - das weiß ich nicht mehr.

Hast du eigentlich mal versucht, das TBGRABitmap https://wiki.freepascal.org/BGRABitmap zu nehmen? Ich könnte mir vorstellen, daß dieses plattformunabhängiger reagiert - ist aber nur ins Blaue geraten.

Code: Alles auswählen

type
  TLiveSelection = (lsMoney, lsChilds, lsTime);
  TLive = Array[0..1] of TLiveSelection; 

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Ich komme bei den meisten Systemen keinen pointer auf einen zusammenhängenden Block. Bei Bitmap geht das unter gewissen Voraussetzungen. Die ganze Pointerarithmetik wird deswegen verwendet, weil es hier genaugenommen um ein 'live' Bild geht und es keinen Überhang geben soll. Zusätzlich habe ich das System nicht erfunden, sondern bin nur dabei weitere 'Codecs' erstellen zu müssen. Damit ist die Schnittstelle von der Eingangsseite und der Ausgangsseite vorgegeben.

Aber zumindest mehr Ahnung habe ich mal. Das die internen Formate so abweichen hatte ich zuerst nicht gefunden. Erst jetzt, nachdem ich ich weis nach was ich suchen muss, habe ich die spärliche Info auch gefunden.

Das mit TlazIntImage, TRawImage werde ich mir ansehen. Auch das BGRABitmap habe ich mir schon kurz angesehen, nur dort nicht die tiefe Schnittstelle gefunden.

Grundlegend geht es um das hier https://de.wikipedia.org/wiki/Bayer-Sensor . Das Problem ist, das du dort ziemlich stark interpolieren musst um aus einer 2x2 Information volle Bildpunkte zu bekommen, sonst verlierst du Auflösung.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 621
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Winni »

Hi!

Nun hab ich mich schlau gelesen und hab einen ganz anderen Ansatz.

Wir betrachten das Ganze mal LowLevel als array of byte und laden das Bild in den RAM.

Wir kennen die Anordnung zweier übereinander liegender Byte -Reihen, jeweils von Null bis Width -1

A) GRGRGRGR.... Width - 1
B) BGBGBGBG..... Width -1

Die vier Byte -Werte haben Anordung:

GR
BG

das macht im Byte array die Werte (w = width)

i | i+1
i+w | i+w+1

Hieraus kann man also die RGB-Werte errechnen,
die zweimal Green müssen nach der Addition also durch 2 dividiert werden.

Da ich nicht zur Meditation neige, habe ich nicht eine Bitmap, sondern eine BGRAbitmap genommen.
Die Prozentanzeige erweist sich als ziemlich überflüssig. So schnell ist es.

Project und verkleinertes Bild im Anhang.
Ach ja: In das Projectverzeichnis muss das RawImage 'SGRBG8.raw' von 08/15 kopiert werden.

Winni
Dateianhänge
BayerTestWB.zip
(127.01 KiB) 2-mal heruntergeladen
Bayer.png
Bayer.png (369.86 KiB) 270 mal betrachtet

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Der Ansatz ist gut, ändert aber die Auflösung. Ich werde mir das mit dem BGRABitmap ansehen.

Die Kunst bein Debayering ist, die Auflösung zu erhalten und die Zellen richtig zu interpoliert. Du muß man für jeden Punkt die richtigen Nachbarn interpoliert. Da wird es dann zur Kunst.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
Winni
Beiträge: 621
Registriert: Mo 2. Mär 2009, 16:45
OS, Lazarus, FPC: Laz2.06, fpc 3.04
CPU-Target: 64Bit
Wohnort: Fast Dänemark

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von Winni »

Hi!

Auch das noch: Auflösung beibehalten, obwohl nur 1/4 der Daten vorhanden sind.
Also: Schrott-Hardware mit Software besser aussehen lassen. Mal wieder.

Wenn Du Dir sowieso BGRAbitmap ansiehst, dann sieh Dir auch die Filter für BGRAbitmap.resample an:
Copy (bottom up):

Code: Alles auswählen

{* List of resample filter to be used with ''rmFineResample'' }
  TResampleFilter = (
    {** Equivalent of simple stretch with high quality and pixel-centered coordinates }
    rfBox,
    {** Linear interpolation giving slow transition between pixels }
    rfLinear,
    {** Mix of ''rfLinear'' and ''rfCosine'' giving medium speed stransition between pixels }
    rfHalfCosine,
    {** Cosine-like interpolation giving fast transition between pixels }
    rfCosine,
    {** Simple bi-cubic filter (blurry) }
    rfBicubic,
    {** Mitchell filter, good for downsizing interpolation }
    rfMitchell,
    {** Spline filter, good for upsizing interpolation, however slightly blurry }
    rfSpline,
    {** Lanczos with radius 2, blur is corrected }
    rfLanczos2,
    {** Lanczos with radius 3, high contrast }
    rfLanczos3,
    {** Lanczos with radius 4, high contrast }
    rfLanczos4,
    {** Best quality using rfMitchell or rfSpline }
    rfBestQuality);               
Das gibt erstauniche gute Ergebnisse beim resample.
Simpler und brutale Test: 2x2 Bitmap mit 4 verschiedenen farbigen Pixeln erzeugen.
Auf Bildschirmgröße hochziehen. Astrein.

Falls da noch andere Ideen im Spiel sind (wie ich gelesen habe):
Ich würde eine 25% Bitmap - wie in meinem Beispiel - erzeugen.
Und dann mir eigene Filter mittels BGRA schreiben.

Aber ich bin kein Freund davon, fehlende Daten aus dem nichts zu erzeugen.
Für Bilder mag das erlaubt sein.
Mit Meinngsumfragen liegt man damit oft auf der Schnauze. Wie wir gesehen haben.

Winni

Benutzeravatar
six1
Beiträge: 342
Registriert: Do 1. Jul 2010, 19:01

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von six1 »

Das PAL System hat auch nur ein (relativ) scharfes SW Bild übertragen und im Hintergrund großflächig bunte Kleckse erzeugt.
SW sieht das Auge 10.000 mal besser als Farbe.
Gruß, Michael

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 4517
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Niederösterreich
Kontaktdaten:

Re: Bitmap unterschiedlich Linux und Windows

Beitrag von af0815 »

Winni hat geschrieben:
Do 8. Apr 2021, 23:43
Auch das noch: Auflösung beibehalten, obwohl nur 1/4 der Daten vorhanden sind.
Also: Schrott-Hardware mit Software besser aussehen lassen. Mal wieder.
Das hat nichts mit Schrott-Kameras zu tun, wenn du einen Ausflug in die Welt der Kameras und RAW-Formate machst, wirst du sehen, das das nicht unüblich ist. Viel von der Qualität von teuren Kameras hat mit der Software und dem Betrügen des Auges zu tun.

Was ich hier habe, ist eine Kamera, die diese Aufgabe in die Software verschiebt.

Zum Bayerfilter:

https://en.wikipedia.org/wiki/Bayer_filter

https://web.archive.org/web/20160308114 ... aic_de.pdf

Edit:
Die Sourcen mit dem Demobild liegen mal hier https://github.com/afriess/GSTCamera/tr ... sv4l/demos
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten