Thema: Delphi Bewegungsmelder

Einzelnen Beitrag anzeigen

Benutzerbild von turboPASCAL
turboPASCAL

Registriert seit: 8. Mai 2005
Ort: Sondershausen
4.274 Beiträge
 
Delphi 6 Personal
 
#17

Re: Bewegungsmelder

  Alt 8. Okt 2005, 12:49
So einen "Bewegungsmelder" zu machen ist gar nicht so leicht. Wenn man bedenkt das jedes Bild zu dem vorherigen unterschiedlich ist welches von einer Kamera aufgenommen wird. Damit meine ich das Bildrauschen was in der Kamera entsteht. Jeder Pixel ist von den Farbwerten leicht unterschiedlich.
Um das zu umgehen müsste man die Farbwerte verringern, ein Graustufenbild mit 256 Farben wäre da eine Alternative.
Jetzt könnte man ein aufgenommenes Bild (Bitmap) mit einem davor aufgenommenen Bild vergleichen.

Dabei ist die nun die Frage wie diese beiden Bilder verglichen werden sollen.

- gesamte Bilder vergleichen Pixel für Pixel / hohe Fehlerrate bei viel Bewegungen

- Bilder in Bereiche aufteilen und anschließend diese vergleichen / hohe Genauigkeit geringe Fehlerrate

Zum vergleichen von zwei Bitmaps Pixel zu Pixel zwei einfache Varianten:

abfragen der Pixel uber die GDI mit:
Delphi-Quellcode:
for y := 0 to Bitmap1.Height -1 do
      for x := 0 to Bitmap1.Width -1 do
      begin
        Bitmap1_PixelColor := Bitmap1.Canvas.Pixels[x,y];
        Bitmap2_PixelColor := Bitmap2.Canvas.Pixels[x,y];
        if Bitmap1_PixelColor <> Bitmap2_PixelColor then ...
      end;
da diese Funktion sehr langsam ist sollte man sich für Scanline entscheiden. Das würde dann so aussehen:
Delphi-Quellcode:
function BitmapCompare(Bitmap1, Bitmap2: TBitmap; DifferentPixel: Integer): TRect;
var
  y, x, CountDifferentPixel: Integer;
  Bitmap1Pixel, Bitmap2Pixel: PRGBQuad; // PRGBQuad def. in Unit Windows;
  aRect: TRect;
begin
  // ein Rechteck auf Min-und Maxwerte vordef.
  aRect := Rect(65000, 65000, 0, 0);
  CountDifferentPixel := 0;

  for y := 0 to Bitmap1.Height - 1 do
  begin
    // Bitmaps Y Linie einlesen
    Bitmap1Pixel := Bitmap1.ScanLine[y];
    Bitmap2Pixel := Bitmap2.ScanLine[y];

    for x := 0 to Bitmap2.Width - 1 do
    begin
      // Pixel farbwerte vergleichen zw. Bitmap1Pixel u. Bitmap2Pixel
      if RGB(Bitmap1Pixel^.rgbRed, Bitmap1Pixel^.rgbGreen, Bitmap1Pixel^.rgbBlue) <>
        RGB(Bitmap2Pixel^.rgbRed, Bitmap2Pixel^.rgbGreen, Bitmap2Pixel^.rgbBlue) then
      begin
        // das Rechteck (aRect) auf die Werte der unterschiedlichen
        // Pixel erweitern die ausserhab des Bereiches des Rechtecks liegen
        if x < aRect.Left then aRect.Left := x;
        if y < aRect.Top then aRect.Top := y;
        if x > aRect.Right then aRect.Right := x;
        if y > aRect.Bottom then aRect.Bottom := y;
        Inc(CountDifferentPixel);
      end;
      // Zeiger auf nächsten Pixel setzen
      Inc(Bitmap1Pixel);
      Inc(Bitmap2Pixel);
    end;
  end;
  // keinen Unterschied gefunden dann kein Rechteck ansonsten
  // das Rechteck zurückgeben in dem sich die Pixel unterscheiden.
  if CountDifferentPixel > DifferentPixel // Grosse des Schwellwerts der Unterschiede
    then Result := TRect(0, 0, 0, 0)
    else Result := aRect;
end;


// Umwandeln eines Bitmaps in Grauwerte auf einfache Art und Weise (eine Möglichkeit von vielen)
procedure MakeGreyBitmap(aBitmap: TBitmap);
var
  PixelLine: PByteArray;
  x, y: integer;
begin
 aBitmap.PixelFormat := pf24Bit;
 for y := 0 to aBitmap.height - 1 do
  begin
    PixelLine := aBitmap.ScanLine[y];
    for x := 0 to aBitmap.width - 1 do
    begin
       PixelLine^[x*3] := (PixelLine^[x*3] + PixelLine^[x*3+1] + PixelLine^[x*3+2]) div 3;;
       PixelLine^[x*3+1] := PixelLine^[x*3];
       PixelLine^[x*3+2] := PixelLine^[x*3];
    end;
  end;
end;

// Aufruf zB. so, hier wir in ein Preview Bitmap ein
// Rechteck gezeichnet in dem ein Unterschied vorliegt.

// ...
MakeGreyBitmap(BitmapAlt);
MakeGreyBitmap(BitmapNeu);
PreviewBitmap.Canvas.Rectangle(BitmapCompare(BitmapAlt, BitmapNeu, 1000));
Der Code ist jetzt nur mal so zusammengetippt und nicht getest.

Wenn man die Farbwerte zu gering setzt also zB. 16 Farben ist durch das Umrechnen der Farbwerte die Fehlerquelle zu gross, da man beim umrechnen icht immer die selben Farbwerte erreicht wie bei der vorherigen Umrechnung, das kann man mal mit einem Paint Programm ausprobieren.

Matti
Meine Software-Projekte - Homepage - Grüße vom Rüsselmops -Mops Mopser
  Mit Zitat antworten Zitat