Bildvergleich

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.
Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Bildvergleich

Beitrag von Christian »

So, ich such mal wieder nach n paar Ideen.
Ich überlege gerade n recht simplen Bildvergleich zu basteln.
Problem dabei ist das das zu vergleichende Objekt nicht genau positioniert werden kann.
Das heisst ich muss das Musterbild und das aktuelle Soweit verschieben und drehen das beide höchstmögliche Übereinstimmung haben.
Hat dafür jemand ne Idee ?
Bzw mehrere Ideen sind auch erlaubt :p
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

Schwierige Sache. Das kann man wahrscheinlich nicht allgemein beantworten mit diesen Angaben, wenn überhaupt.
Was willst du denn genau vergleichen?
Fotographisches, Schwarz-Weiss-Objekte, Linien....
Ich glaub da googelst du am besten mal.

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Beitrag von Christian »

Konkret, leiterplatten sollte aber recht universell angesetzt sein.

Hab schon gegoogelt dachte eigentlich das es da schon mehr Lösungen gibt schließlich brauchen die Roboter Kiddies doch sowas ständig dachte ich.

Schlussendlich bin ich auf dem Stand:

Kantenerkennung entweder es gibt nen fertigen Algorythmus hab da nur Ansätze gefunden wenn nicht Kontrast vom bild Hoch und die verbleibenden Punkte verbinden...

Das einmal für ein Musterbild und dann für das gerade aufgenommene.

Mithilfe z.b. der Resultierenden Linienlängen dürfte es möglich sein Einzelne Linien vom Zielbild zum Quellbild zuzuordnen und daraus einen Rotations und Skalierungswinkel zu errechnen.

Wenn man das Zielbild erstmal rotiert und skaliert hat will ich einfach nur nen Pixelvergleich machen und je nach Abweichungshöhe einfärben. So dürfte man z.b. unbestückte Bauteile schön raus erkennen können.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

Kantenerkennung z.B. hier: http://www.swissdelphicenter.ch/torry/s ... hp?id=1704" onclick="window.open(this.href);return false;

Hab's kurz testweise mit OPBitmap versucht auf Laz zu übertragen:
Klappt!!!
Nen TButton und ein TImage auf die Form und "opbitmapforlaz" in die Package - Abhängigkeit des Projekts aufnehmen.

Code: Alles auswählen

unit Unit1; 
 
{$mode delphi}{$H+}
 
interface
 
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs, opbitmap, opbitmapformats, lazbridge,
  Buttons, ExtCtrls;
 
type
 
  { TForm1 }
 
  TForm1 = class(TForm)
    Button1: TButton;
    Image1: TImage;
    procedure Button1Click(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end; 
 
var
  Form1: TForm1; 
 
type
  TRGBTripleArray = array[0..10000] of TRGBTriple;
  PRGBTripleArray = ^TRGBTripleArray;
 
  T3x3FloatArray = array[0..2] of array[0..2] of Extended;
 
 
implementation
 
function Convolve(ABitmap: TOPBitmap; AMask: T3x3FloatArray;
  ABias: Integer): TOPBitmap;
var
  LRow1, LRow2, LRow3, LRowOut: PRGBTripleArray;
  LRow, LCol: integer;
  LNewBlue, LNewGreen, LNewRed: Extended;
  LCoef: Extended;
begin
  LCoef := 0;
  for LRow := 0 to 2 do
    for LCol := 0 to 2 do
      LCoef := LCoef + AMask[LCol, LRow];
  if LCoef = 0 then LCoef := 1;
 
  Result := TOPBitmap.Create;
 
  Result.Width := ABitmap.Width - 2;
  Result.Height := ABitmap.Height - 2;
  Result.PixelFormat := pf24bit;
 
  LRow2 := ABitmap.ScanLine[0];
  LRow3 := ABitmap.ScanLine[1];
 
  for LRow := 1 to ABitmap.Height - 2 do
  begin
    LRow1 := LRow2;
    LRow2 := LRow3;
    LRow3 := ABitmap.ScanLine[LRow + 1];
 
    LRowOut := Result.ScanLine[LRow - 1];
 
    for LCol := 1 to ABitmap.Width - 2 do
    begin
      LNewBlue :=
        (LRow1[LCol - 1].rgbtBlue * AMask[0,0]) + (LRow1[LCol].rgbtBlue * AMask[1,0]) +
        (LRow1[LCol + 1].rgbtBlue * AMask[2,0]) +
        (LRow2[LCol - 1].rgbtBlue * AMask[0,1]) + (LRow2[LCol].rgbtBlue * AMask[1,1]) +
        (LRow2[LCol + 1].rgbtBlue * AMask[2,1]) +
        (LRow3[LCol - 1].rgbtBlue * AMask[0,2]) + (LRow3[LCol].rgbtBlue * AMask[1,2]) +
        (LRow3[LCol + 1].rgbtBlue * AMask[2,2]);
      LNewBlue := (LNewBlue / LCoef) + ABias;
      if LNewBlue > 255 then
        LNewBlue := 255;
      if LNewBlue < 0 then
        LNewBlue := 0;
 
      LNewGreen :=
        (LRow1[LCol - 1].rgbtGreen * AMask[0,0]) + (LRow1[LCol].rgbtGreen * AMask[1,0]) +
        (LRow1[LCol + 1].rgbtGreen * AMask[2,0]) +
        (LRow2[LCol - 1].rgbtGreen * AMask[0,1]) + (LRow2[LCol].rgbtGreen * AMask[1,1]) +
        (LRow2[LCol + 1].rgbtGreen * AMask[2,1]) +
        (LRow3[LCol - 1].rgbtGreen * AMask[0,2]) + (LRow3[LCol].rgbtGreen * AMask[1,2]) +
        (LRow3[LCol + 1].rgbtGreen * AMask[2,2]);
      LNewGreen := (LNewGreen / LCoef) + ABias;
      if LNewGreen > 255 then
        LNewGreen := 255;
      if LNewGreen < 0 then
        LNewGreen := 0;
 
      LNewRed :=
        (LRow1[LCol - 1].rgbtRed * AMask[0,0]) + (LRow1[LCol].rgbtRed * AMask[1,0])
        + (LRow1[LCol + 1].rgbtRed * AMask[2,0]) +
        (LRow2[LCol - 1].rgbtRed * AMask[0,1]) + (LRow2[LCol].rgbtRed * AMask[1,1])
        + (LRow2[LCol + 1].rgbtRed * AMask[2,1]) +
        (LRow3[LCol - 1].rgbtRed * AMask[0,2]) + (LRow3[LCol].rgbtRed * AMask[1,2])
        + (LRow3[LCol + 1].rgbtRed * AMask[2,2]);
      LNewRed := (LNewRed / LCoef) + ABias;
      if LNewRed > 255 then
        LNewRed := 255;
      if LNewRed < 0 then
        LNewRed := 0;
 
      LRowOut[LCol - 1].rgbtBlue  := trunc(LNewBlue);
      LRowOut[LCol - 1].rgbtGreen := trunc(LNewGreen);
      LRowOut[LCol - 1].rgbtRed   := trunc(LNewRed);
    end;
  end;
end;
 
{ TForm1 }
 
procedure TForm1.Button1Click(Sender: TObject);
var
  LMask: T3x3FloatArray;
  OPP:TOPPicture;
  OPB:TOPBitmap;
begin
  LMask[0,0] := -1;
  LMask[1,0] := -1;
  LMask[2,0] := -1;
  LMask[0,1] := -1;
  LMask[1,1] := 8;
  LMask[2,1] := -1;
  LMask[0,2] := -1;
  LMask[1,2] := -1;
  LMask[2,2] := -1;
  OPP:=TOPPicture.Create;
  OPP.LoadFromFile('/home/theo/logoop.bmp');
  OPP.Bitmap.PixelFormat:=pf24bit;
  OPB:=Convolve(OPP.Bitmap, LMask, 0);
  AssignOpBitmapToBitmap(OPB,Image1.Picture.Bitmap);
  OPB.free;
  OPP.free;
end;
 
initialization
  {$I unit1.lrs}
 
end.
Zuletzt geändert von theo am Sa 25. Aug 2007, 20:36, insgesamt 1-mal geändert.

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

Beitrag von af0815 »

Ich arbeite in der Firma mit Vision Control Systemen (OMRON, DVT, COGNEX) . Da habe ich schon einige Ideen mitbekommen.

Die erste Frage ist, wie viel Zeit hast du für eine Auswertung ? Wie nimmst Du das Bild auf, welche Auflösung wird verwendet. Synchroniesierung mit externen Einheiten ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Beitrag von Christian »

Die Zeit spielt kaum ne rolle, das ding wird in den ersten Versionen Einach ne gute Webcam auf nem Ständer über ner weissen Oberfläche sein wo die Leute ne Platine draufschmeissen, nen Knopf drücken und aufm Bildschirm das Ergebnis sehn. Sollte < 10 Sek sein aber das sollte machbar sein. Wenn das ganze später Förderbandtauglich wird bin ich nicht böse aber vorerst nicht.

Auflösung min 800x600 würd ich sagen. Vorerst keine Anbindung externer Komponenten.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Beitrag von Christian »

Theo ich frag mich echt wie du immer an den kram kommst ich denk immer viel zu kompliziert lande immer nach den ersten 3 Suchanfragen auf Hochschulseiten und du... Findest was auf den Standart Delphi Tip Seiten...
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

Tja, Googeln will eben gelernt sein! ;-)

Hab noch ne Mini-Korrektur in dem Code oben angebracht, falls du den testen willst. Das OPB muss man nicht in Button1.Click createn, wird ja von der Funktion gemacht.

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

Beitrag von af0815 »

Ok, Theo hat mal den Code für Kantenerkennung gebracht.

Mit einer multiplen Kantenerkennung kann du feststellen ob dort wirklich eine Kante ist. Am besten ein Rechteck definieren und von einer Seite die Erkennung kommen lassen. Dann dieses Rechteck um einen Betrag plus und minus schwenken und jedesmal die Kanten versuchen zu erkennen. Die Länge der Vektoren (Kante gefunden) vergleichen.

Was man alledings zuerst machen sollte, ist die Bilder vorbereiten. Leuchtbereiche strecken/verdichten. Wenn es möglich ist, die Kontraste soweit wie möglich erhöhen. Helle bzw. dunkle Flächen schliessen.

Übrigends haben einige der Hersteller von Vision Controll Systemen voll funktionsfähige Simulatoren, mit denen man alles ausprobieren kann und so sich auch die Wirkung von Filtern und Tools mal ansehen kann. Also Simulation aufsetzen, Bilder richtig vorbereiten und man kann damit arbeiten. Dort kann ich dir helfen, da es am Anfang meistens nicht so einfach ist, was vernünftiges heraus zu bekommen.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Benutzeravatar
theo
Beiträge: 10927
Registriert: Mo 11. Sep 2006, 19:01

Beitrag von theo »

Einfach wird's nicht werden. Zumal die Bilder in Rotation und Skalierung noch unterschiedlich sein können.
Ohne eindeutige Referenzpunkte auf den Leiterplatten wohl ziemlich schwierig.

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

Beitrag von af0815 »

Ich würde es trotzdem mal auf ner Simulation ausprobieren und dann die Algorithmen suchen. Alles was du siehst und weisst wo es mit welcher Toleranz ist kannst Du als Referenz nehmen. Ich muß mich da oft an Sachen orientieren, das du dir an den Kopf greifst. Es scheint leichter zu sein, denn es muß nichts vermessen werden, sondern nur verglichen - Objekt da / nicht da.

Wenn es geht, dann drei Stifte nehmen, an den die Bediener die Leiterplatten anlgen können. Damit schränkst du Positionsfehler und Verdrehung extrem ein. Schon eine einfache Box aufgezeichnet auf die Oberfläche zur Orientierung hilft den oft den Fehler von +- 180 Grad auf +- 15 Grad zu bringen. Das hilft extrem.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Beitrag von Christian »

Nein, ich will keine Positionierung weil man dazu für jede Art von Objekt eine Aufnahme braucht. Wenn das mit der Kantenerkennung nicht klappt werd ich mich von aussen an das Objekt tasten und somit die umrisse erfassen mit denen dürft es auch leicht sein den Drehwinkel rauszubekommen. Allerdings möcht ich das so universell wie möglich haben, also versuch ich erstmal die Kantenerkennung.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

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

Beitrag von af0815 »

Ich fasse mal zusammen:

Auflösung 800 x 600 (farbe ?!)
kein Zeitlimit (vorerst)
keine Anbindung an extern (vorerst)
keine Vorpositionierung ?!
Erkennung von fehlenden Objekten

Frage:
Kamera Farbe oder SW ?
Wie groß ist die Platine, wie groß sind die gesuchten Objekte.
Mußt du nur fehlende Objekte finden oder mehr ?
Welcher Kontrast besteht zwischen den Objekten und der Platine ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Christian
Beiträge: 6079
Registriert: Do 21. Sep 2006, 07:51
OS, Lazarus, FPC: iWinux (L 1.x.xy FPC 2.y.z)
CPU-Target: AVR,ARM,x86(-64)
Wohnort: Dessau
Kontaktdaten:

Beitrag von Christian »

Schwarz weiss würde sich schlecht machen da man dann zuwenig Kontrast zu den Bauteilen hätte.
Platinengrösse soll egal sein.
Ich will gar nichts finden ich will einfach einen 1:1 Pixelvergleich machen und die abweichenden Stellen je nach Abweichung einfärben. Da sollte man dann denk ich super sehn wo was fehlt. So kann man das später auch für andere Sachen nehmen z.b. rausfinden ob in einer Mechanik ne schraube fehlt oder ähnliches.
W.m.k.A.h.e.m.F.h. -> http://www.gidf.de/

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

Beitrag von af0815 »

Die maximale Platinengröße hat was mit der Auflösung zu tun. Für das kleinste zu überprüfende Objekt müssen entsprechend Bildpunkte vorhanden sein.

Beispiel 600 Bildpunkte und 300 mm Objektlänge ergebe, daß du 0,5 mm je Bildpunkt hast. Wenn du jetzt ein Objekt mit 1 mm suchst, so sind das nur 2 Bildpunkte und das kann zu wenig sein. Bei Objekten mit leichten unschärfen, sage ich mal, das ich zumindest 3-5 Bildpunkte benötige, auch abhängig davon ob und welche Filter ich in der Vorverarbeitung benötige.
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Antworten