Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   Delphi Bitmap in SW umwandeln (https://www.delphipraxis.net/62688-bitmap-sw-umwandeln.html)

DocZenith 8. Feb 2006 10:15


Bitmap in SW umwandeln
 
Hi!

Muss ein Projekt für die Schule programmieren, indem Bilder von einer Serveranwendung zur Clientanwendung übers
Internet verschickt werden müssen. Dort werden die Bilder dann mit einem Sollbild verglichen. Wegen der Internetverbindung
soll die bildgröße des zu verschickenden bildes so klein wie möglich sein. daher möchte ich das bitmap mit 1 bit farbtiefe
als sw umwandeln. weiß aber nicht wie ich das genau realisieren soll.

hab es soweit dass das bild von der webcam eingelesen wird und in graustufen umgewandelt wird. nun weiß ich leider nicht weiter.
Kann mir jemand helfen bzw. tipps geben?

Klaus01 8. Feb 2006 10:19

Re: Bitmap in SW umwandeln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Nun, ich denke nicht, daß ein Graustufenbild so viel kleiner als
ein Farbbild ist. Hier werden nur die Farben in Graustufen dargestellt.
Eine reine schwart-weiß "Grafik" wäre das pcx Format. Das is quasi
ein bmp Bild mit einem bit Farbtiefe, halt schwarz oder weiß.
Ob man das Bild der Webcam dann noch erkennen kann, wage ich doch
zu bezweifeln.

Grüße
Klaus

Habe Dir mal eine Unit angehängt, vielleicht bringt die Dich ein wenig weiter.

DocZenith 8. Feb 2006 10:27

Re: Bitmap in SW umwandeln
 
Erst mal danke für die schnelle Antwort!


Es soll ein Füllstand optisch geregelt werden. daher werden regelmäßig bilder aufgenommen und zur clientanwendung geschickt.
mit einem 1 bit sw bild kann ich denk ich mal am besten ein vergleich feststellen (durch zählen der schwarzen pixel z.b.) außerdem wird das bild dann am schnellsten verschickt.

ich will das bitmap unter 3 kb größe bekommen, damit es nicht so lange dauert bis es übers i-net verschickt wird, da der regelungsprozess nicht unterbrochen werden darf und zeitlich beansprucht wird.

also gibt es jetzt ne möglichkeit umzuwandeln?

ibp 8. Feb 2006 10:35

Re: Bitmap in SW umwandeln
 
erstmal herzlich willkomen bei dp :dp:

ich denke du musst dir einen filter basteln, der den graustufenwert entweder schwarz oder weiss darstellt!

DocZenith 8. Feb 2006 10:51

Re: Bitmap in SW umwandeln
 
das würde heißen, ich errechne die anzahl aller farbwerte des bildes, also jeden farbwert von jedem
Pixel auf addieren und daraus einen mittelwert bilden. mit dem mittelwert dann jedes pixel vergleichen und
je nach dem das pixel dann schwarz oder weiß färben?!?. Gibt es bessere oder alternative ideen?

ibp 8. Feb 2006 11:04

Re: Bitmap in SW umwandeln
 
du gibst den mittelwert vor!

DocZenith 11. Feb 2006 19:07

Re: Bitmap in SW umwandeln
 
Also hab jetzt eine Prozedure geschrieben, die ein Videobild (Graustufen) aufnimmt,
es in ein 8Bit sw Bild umwandelt. Ich möchte aber das das Bild ein 1Bit sw Bild ist,
wobei 1 für weiß und 0 für schwarz steht, da es ja bei 1Bit nur 1 oder 0 geht.
Dadurch benötigt das Bild weniger speicher als ein 8 Bit bild. aber wenn die schleife durchläuft,
die das bild in 1 Bit runterrechnet, bleibt das bild leider immer schwarz. warum weiß ich leider
nicht. Vielleicht findet ihr den fehler. wäre froh wenn mir jemand helfen könnte.

Delphi-Quellcode:
procedure TMainForm.Timer1Timer(Sender: TObject);
var
  PixelLine: PByteArray;
  x, y,xzahl,yzahl: integer;
  Bitmap: TBitmap;
  schwellwert,bildpunkte: integer;
begin

  { neues Videobild holen und darstellen - Bild ist bereits Graustufen }
GrabVideoImage;
Bitmap := VideoImage;
bildpunkte := 0;

  { Schwellwert für Bild ermitteln - Mittelwert }
for y := 0 to Bitmap.height - 1 do
  begin
    yzahl := 1;
    PixelLine := Bitmap.ScanLine[y];
    yzahl := yzahl + y;
    for x := 0 to Bitmap.width - 1 do
    begin
       xzahl := 1;
       xzahl := xzahl + x;
       bildpunkte := bildpunkte + pixelline[x];
    end;
       schwellwert := xzahl * yzahl;
       schwellwert := bildpunkte div schwellwert;
end;

  { Bild nur mit schwarz und weiß darstellen }
Bitmap.PixelFormat := pf8Bit;
for y := 0 to Bitmap.height - 1 do
  begin
    PixelLine := Bitmap.ScanLine[y];

    for x := 0 to Bitmap.width - 1 do
    begin
       if PixelLine^[x] > schwellwert
       then begin
         pixelline^[x] := 255
           end
           else
         pixelline^[x] := 0;
         end;
    end;

  { Bildformat auf 1 Bit setzen, damit Speicher eingespart wird }
aBitmap.PixelFormat := pf1Bit;
for y := 0 to Bitmap.height - 1 do
  begin
    PixelLine := Bitmap.ScanLine[y];

    for x := 0 to Bitmap.width - 1 do
    begin
       if PixelLine^[x] = 255
       then begin
         pixelline^[x] := 1
           end
           else
         pixelline^[x] := 0;
         end;
    end;

 { Meldung ausgeben }
 OutputMessage('Es wurde ein Bild aufgenommen.');
 mainform.Label1.Caption := floattostr(bildpunkte);
 mainform.Label2.Caption := inttostr(schwellwert);
end;

DocZenith 11. Feb 2006 19:10

Re: Bitmap in SW umwandeln
 
ups, beim quellcode unten hab ich noch einen fehler (abitmap heißt bitmap!)

Delphi-Quellcode:
  { Bildformat auf 1 Bit setzen, damit Speicher eingespart wird }
[b]Bitmap[/b].PixelFormat := pf1Bit;
for y := 0 to Bitmap.height - 1 do
  begin
    PixelLine := Bitmap.ScanLine[y];

    for x := 0 to Bitmap.width - 1 do
    begin
       if PixelLine^[x] = 255
       then begin
         pixelline^[x] := 1
           end
           else
         pixelline^[x] := 0;
         end;
    end;

rantanplan99 11. Feb 2006 20:16

Re: Bitmap in SW umwandeln
 
Zitat:

Zitat von DocZenith
, bleibt das bild leider immer schwarz. warum weiß ich leider
nicht. Vielleicht findet ihr den fehler. wäre froh wenn mir jemand helfen könnte.

Delphi-Quellcode:
{ Schwellwert für Bild ermitteln - Mittelwert }
for y := 0 to Bitmap.height - 1 do
  begin
    yzahl := 1;
    PixelLine := Bitmap.ScanLine[y];
    yzahl := yzahl + y;
    for x := 0 to Bitmap.width - 1 do
    begin
       xzahl := 1;
       xzahl := xzahl + x;
       bildpunkte := bildpunkte + pixelline[x];
    end;
       schwellwert := xzahl * yzahl;
       schwellwert := bildpunkte div schwellwert;
end;

Also der Teil ist kompletter schwachsinn. sorry für die Wortwahl.
aber "yzahl := 1" im for-block macht keinen sinn, das die ja jedesmal wieder auf "1" gesetzt, und damit ist "yzahl := yzahl + y;" immer gleich "1 + y". selbest gilt für xzahl. irgendwie hab ich auch nicht verstanden wofür du xzahl und yzahl überhaupt benötigsts. Für was du "bildpunkte" verwendest weiss ich auch nicht.

das andere ist der "schwellwert" den du in jeder for-schleife von y neu berechnest.

ich vermute das soll den mittleren grauwert des Bildes berechnen. so sollte es klappen:

Delphi-Quellcode:
var
   grauwerte: integer; // integer ist eigentlich schlecht weil es bei entsprechender Bildgröße zu einem Overflow kommen kann!

[...]

{ mittleren Grauwert des Bildes berechnen }
grauwerte := 0;
for y := 0 to Bitmap.height - 1 do
begin
  PixelLine := Bitmap.ScanLine[y];
  for x := 0 to Bitmap.width - 1 do
  begin
    grauwerte := grauwerte + PixelLine[x];
  end;
end;
schwellwert := grauwerte div (Bitmap.height * Bitmap.width);
denke das sollte funktionieren. Ich habe es aber nicht getestet.

rantanplan

FAlter 11. Feb 2006 21:38

Re: Bitmap in SW umwandeln
 
Hi,

erstmal zu obiger falscher Äüßerung: Es gibt BMPs mit 1 Bit (2 Farben, meist Schwarz und weiss), 4 Bit, 8 Bit, 24 Bit und 32 Bit (seltener 15 und 16 Bit). Die Dateigröße einer 1Bit-BMP ist unschlagbar niedrig geghenüber Graustugen-JPEG (1% Qualität) oder 4-Bit-Gif (aber nur 2 Farben), und gegenüber der JPEG bei SW-Grafik extrem bessere Qualität (bei Fotos eher schlecht). Gezippt oder gar LZMA kanns nochmal verkleinern, da es immernoch unkomprimiert ist.

Delphi-Referenz durchsuchenTBitmap.PixelFormat (pf1bit..pf32bit)

Für das genannte Problem könnte man auch BMP.Monochrome setzen. Dann wird die BMP 2Frabig mit den Farben schwearz und weiss (bei pf1bit wird sie bei mir meist schwarz-dunkelrot, müsste man noch Palette bearbeiten).

Delphi-Quellcode:
with TBitmap.Create do
try
  LoadFromFile('TEST.BMP');
  Monochrome := true;
  SaveToFile('MONO-TEST.BMP');
finally
  Free;
end;
In einigen Fällen ist vorher eine Farbanpassung nützlich, optimalerweise mit Darstellung der Graustufen als Pixelmuster (so wie Schwarzweißdrucker für Graustufen Muster drucken).

Mfg
FAlter

Nachtrag:
Delphi-Quellcode:
procedure Schwarzweiss(Picture: TBitmap);
const
  Blau = 1;
  Gruen = 2;
  Rot = 3;
type
  PixArray = array[Blau..Rot] of Byte;
var
  h, w, Wert, i: integer;
  p: ^PixArray;
begin
  Picture.PixelFormat := pf24bit; //Temporär
  for h := 0 to Picture.Height - 1 do
  begin
    p := Picture.ScanLine[h];
    for w := 0 to Picture.Width - 1 do
    begin
      Wert := (p^[Blau] + p^[Gruen] + p^[Rot]) div 3;
      if Wert <= 85 then
        for i := Blau to Rot do p^[i] := 0
      else
      if Wert <= 170 then
      begin
        if (h mod 2) = (w mod 2) then
          for i := Blau to Rot do p^[i] := 0
        else
          for i := Blau to Rot do p^[i] := 255;
      end
      else
        for i := Blau to Rot do p^[i] := 255;
      inc(p);
    end;
  end;

  Picture.Monochrome := true;
end;
//Edit: Korrektur

DocZenith 12. Feb 2006 14:55

Re: Bitmap in SW umwandeln
 
@ FAlter:

deine idee ist ok, aber wie bekomm ich das standbild von der webcam, das als graustufen geliefert wird, in
ein 1 Bit sw umgewandelt? und was bedeutet bei dir der code bitmap.monochrome := true? :gruebel:

wenn ich mein oben angegebenen code bzw. deinen code benutze, hab ich zwar ein 2-farbiges bild, allerdings
ist es nicht im 1 Bit Format und es ist im Speicher durchschnittlich 3,6 kb groß. und das bei einem videoformat
von 240 x 176 pixel. ich brauch das Standbild unbedingt so klein wie möglich, damit pro sekunde mindestens 1 Standbild
über ne 56 k modem leitung verschickt werden kann.

@ rantanplan99:

du hast recht, yzahl und xzahl brauch ich nicht, und meine variable bildpunkte erfüllt ja den selben zweck wie
deine variable graustufen. hab wohl die variable schlecht benannt.

FAlter 12. Feb 2006 15:43

Re: Bitmap in SW umwandeln
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von DocZenith
wenn ich mein oben angegebenen code bzw. deinen code benutze, hab ich zwar ein 2-farbiges bild, allerdings
ist es nicht im 1 Bit Format und es ist im Speicher durchschnittlich 3,6 kb groß. und das bei einem videoformat
von 240 x 176 pixel. ich brauch das Standbild unbedingt so klein wie möglich, damit pro sekunde mindestens 1 Standbild
über ne 56 k modem leitung verschickt werden kann.

Hi,

es ist schon 1 Bit, bei 2 Bit wären es schon an die 10 kB. Rechnung mit 1 Bit:

Dein Bild hat 240*176=42240 Pixel

1 Bit pro Pixel = 1/8 Byte pro Pixel:
42240/8=5280 Bytes, das sind etwa 5,16 kBytes Rohdaten (!), dazu kommen bei einer BMP-Datei noch zusatzinformationen, die du jedoch nicht mit übertragen musst, wenn beim Empfänger das Format klar ist (Bildgröße, Farbtiefe, Farbpalette (hier S/W), Auflösung (hier eher irrelevant), dass du da im Speicher auf 3,6 kB kommst, ist schon eigenartig... Also bei deiner Bildgröße kannst du nur auf über 5 kB kommen mit 1 Bit Bildern. Oder du verwendest zusätzlich Komprimierung, dann kommst du je nach Bild auf 2 bis 4 kB bei deiner Bildgröße.

Das Monochrome setzen bewirkt folgendes:

- wandelt das Bild in 1 Bit pro Pixel um (ähnlich wie bei PixelFormat auf pf1Bit setzen), jedoch ohne benutzerdefinierte Schwellenwerte.
- passt die Palette so an, dass die beiden Farben schwarz und weiss sind.

Meine Procedure Schwarzweiss tut folgendes:
Das Bild wird mit 2 Schwellenwerten in SW umgewandelt, wobei ein mittleres Grau durch ein Pixelmuster (Schachbrettmuster) erreicht wird (wenn man weit genug vom Bildschirm weg sitzt und eine niedrige Auflösung eingestellt hat, wirkt es noch besser als grau).

Ein Beispielergebnis ist angehangen (gezippt auf weniger als 3 kB).

Mfg
FAlter

DocZenith 12. Feb 2006 16:59

Re: Bitmap in SW umwandeln
 
@ FAlter:
Hab eben nochmal die Bildgröße überprüft. Momentan ist das Bild um die 9 kb groß und nicht 3,6kb.
aber ich bräuchte halt theoretisch unter 3kb bildgröße, damit das bild schnell mit 56 k verschickt wird.
es muss ja nämlich noch an der clientsoftware ausgewertet werden und ein ergebnis zurückgesendet werden.
und wenn das zu lange dauert, läuft mein regelungsprozess nicht mehr richtig, der pro bild ausgewertet werden muss.

markusj 12. Feb 2006 17:16

Re: Bitmap in SW umwandeln
 
Noch eine Möglichkeit wäre, wenn du einfach jeden Pixel kontrollierst, und wenn sein Wert > 128 ist, machst du eine 1 und wenn < 128 dann eine 0 (oder umgekehrt, hängt davon ab, was Schwarz und was Weiß ist, das weis ich gerade nicht).

Dann kannst du dieses Array in einen Stream Speichern und hinterher wieder Auslesen.
Wenn du ganz ehrgeizig bist, kannst du dir auch entsprechende Prozeduren ausenrum Packen und standartgemäße Bitmaps erzeugen.
Ich hab vor ca. 3 Monaten genau das gemacht, eine Unit die ein Bitmap in ein Array lädt und auch wieder speichern kann, allerdings waren das 24-Bit Bitmaps.

mfG

Markus

PS: Egal welchen Weg du nimmst, dein Projekt hört sich sehr Interessant an ...

rantanplan99 12. Feb 2006 17:25

Re: Bitmap in SW umwandeln
 
Hi

zu 56k: Also du weisst schon dass ein 56k Modem diese Geschwindigkeit nur beim Downstream erreicht. Der Upstream ist bei 56k Modems aber auf 33,6k begrenzt.

zu den Bilddaten. Warum wertest du die Bilder nicht an dem PC aus an dem du das Bild machst und verschickst nur das Ergebnis der Füllhöhe?

Wenn du jedoch das Bild verschicken musst, dann wäre es gut wenn du mehr über das s/w-Bild sagen kannst. Verteilung der Bildpunkte, Höufigkeiten der Farben etc. Dann könnte man besser überlegen welche kompressionsmethode sich da anbietet. Beispielsweise RLE, oder arithmetische Kodierung, oder vielleicht auch ein Algorithmus aus dem Bereich LZW, LZ77, LZ78,...

rantanplan

DocZenith 12. Feb 2006 17:43

Re: Bitmap in SW umwandeln
 
@ rantanplan99:

es geht hier um ein schulprojekt. daher sind die aufgaben so definiert. das bild muss von der serveranwendung erfasst, und zur clientanwendung übers i-net versendet werden. es wird in regelmäßigen abständen per webcam ein standbild eines füllstandes gemacht, das standbild soll ausgewertet werden, ob der füllstand angestiegen ist oder gesunken ist. (dem füllstand wird in unregelmäßigen abständen, unregelmäßige wassermengen hinzugegeben) je nach auswertung der clientsoftware wird ein ereignis ausgelöst (wasser wird dazugepumpt oder abgelassen). daher muss meiner meinung nach mindestens 1 bild pro sekunde ausgewertet werden. und damit das bild schnell verschickt wird, sollte es meiner meinung nach sw sein und so klein wie nur möglich, so dass man es halt noch auswerten kann. hauptsache das bild kommt beim client schnell an.

Khabarakh 12. Feb 2006 17:49

Re: Bitmap in SW umwandeln
 
Zitat:

Zitat von markusj
Noch eine Möglichkeit wäre, wenn du einfach jeden Pixel kontrollierst, und wenn sein Wert > 128 ist, machst du eine 1 und wenn < 128 dann eine 0 (oder umgekehrt, hängt davon ab, was Schwarz und was Weiß ist, das weis ich gerade nicht).

:gruebel: Das ist doch nichts anderes als 1-Bit-Kodierung.

@DocZenith: Kann denn nicht schon der Server (oder wer auch immer an die Cam geschaltet ist) das Bild auswerten?

DocZenith 12. Feb 2006 19:38

Re: Bitmap in SW umwandeln
 
@ Khabarakh:

Es geht hier um ein Schulprojekt. die Regeln sind fest definiert.
Ein Software soll voll automatisch einen über das internet entfernen Prozess regeln.
Also muss die entfernte (client) software die Standbilder auswerten und entsprechende
steuersignale zurücksenden.

markusj 13. Feb 2006 08:09

Re: Bitmap in SW umwandeln
 
@Khabarakh

Ja, und SW ist meines erachtens nach eine 1Bit kodierung ...
siehe: BMP-Fileformat@daubnet
(Achtung, das bei 1-Bit Grafik stimmt, aber bei der 24-Bit Grafik ist ein Fehler drinne ...)

mfG

Markus

PS: Es gibt einige gute Seiten zum BMP-Fileformat ... GOOGLE!!!!

Khabarakh 13. Feb 2006 15:16

Re: Bitmap in SW umwandeln
 
Zitat:

Zitat von markusj
@Khabarakh

Ja, und SW ist meines erachtens nach eine 1Bit kodierung ...

Und darum dreht sich das Thema schon seit dem ersten Post, deswegen verstehe ich nicht, warum du es als andere Möglichkeit anpreist.

@DocZenith: Schade, wäre auch zu einfach gewesen :wink: .


Alle Zeitangaben in WEZ +1. Es ist jetzt 08:55 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