Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Multimedia (https://www.delphipraxis.net/16-multimedia/)
-   -   FreePascal Grafiken erkennen. Library ? (https://www.delphipraxis.net/168095-grafiken-erkennen-library.html)

stiftII 4. Mai 2012 15:27

Grafiken erkennen. Library ?
 
Hallo,

ich müsste für ein Projekt Grafiken erkennen.

Das soll so funktionieren, dass die zu erkennende Grafik als .bmp eingelesen wird, und diese Grafik soll in einer anderen Grafik (zB auf dem Desktop) erkannt werden.

Das ganze soll auch funktionieren, wenn sich die Größe der gesuchten Grafik verändert.

Gibt es für diese Aufgabe irgendwelchen libs ?

Wie kann man so eine optische Erkennung am besten umsetzen.. TBitmap ist ja auch nicht alzu flexibel... und jeden Pixel einzeln auszulesen macht jetzt auch nicht viel Sinn und ist auch recht langsam !?

~stiftII

PS: Arbeite mit Lazarus

Jens01 4. Mai 2012 16:53

AW: Grafiken erkennen. Library ?
 
Zitat:

Gibt es für diese Aufgabe irgendwelchen libs ?
Also Graphics32 hat viele Tools, die Du gebrauchen kannst. Eine direkte Lösung wird das aber nicht sein.

Ansonsten finde ich oft hier was für solche Graphik-Sachen.

Zitat:

und jeden Pixel einzeln auszulesen macht jetzt auch nicht viel Sinn und ist auch recht langsam
Warum nicht?

freeway 4. Mai 2012 17:18

AW: Grafiken erkennen. Library ?
 
man kann jedes Pixel auslesen, man kann aber auch scanline verwenden (schneller)

shmia 4. Mai 2012 17:29

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von freeway (Beitrag 1164904)
man kann jedes Pixel auslesen, man kann aber auch scanline verwenden (schneller)

Kommt drauf an, ob der Algorithmus es erlaubt sich im Bitmap horizontal zu bewegen.

Auf jeden Fall ist Pattern Matching sehr anspruchsvoll und übersteigt die Fähigkeiten eines "normalen Programmierers".

Codewalker 4. Mai 2012 18:22

AW: Grafiken erkennen. Library ?
 
Es muss nicht direkt pattern matching sein, es reicht ja eine Ähnlichkeitssuche. Das Schlagwort hier wäre "Korrelationsfunktion" (nicht die aus der Statistik, sondern die Umkehrung zur Convolution/Faltung in der Bildverarbeitung).
Leichte Kost ist das auch nicht gerade. Man sollte in der Lage sein, ein Bild per Fourier-Transformation (FFT) in den Frequenzraum zu transformieren (und wieder zurück) und auch komplexe Zahlen sollte einem nicht fremd sein. Zur Belohnung kann man dann ein kleineres Bild in einem größeren suchen und bekommt X- und Y-Koordinaten am Ende raus (als Maxima der Funktion, die die Ähnlichkeit der Bilder darstellt).
Zum schnellen Testen, kann man MatLab hernehmen:
Code:
functiong = dftcorr(f,w)
[M,N] = size(f);
F = fft2(f);
G = conj(fft2(w,M,N));
g = real(ifft2(G.*F));
gs= im2uint8(mat2gray(g));
figure; imtool(gs);
[I,J]= find(g == max(g(:)))
wobei hier w das gesuchte Muster und f das Gesamtbild ist. In I und J stehen dann nachher die Koordinaten (I=Y, J=X, weil Matlab spaltenweise arbeitet).
Das ganze in fertiger Form für Delphi kenne ich leider nicht, aber wenn dich das bisher nicht abgeschreckt hat: Zumindest zur Theorie dahinter hab ich noch ein wenig rumfliegen.

fkerber 4. Mai 2012 19:29

AW: Grafiken erkennen. Library ?
 
Hi,

die eierlegende Wollmilchsau zum Thema Bilderkennung etc. dürft vermutlich Bei Google suchenOpenCV sein...

LG, Frederic

stiftII 4. Mai 2012 19:37

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von Codewalker (Beitrag 1164912)
Es muss nicht direkt pattern matching sein, es reicht ja eine Ähnlichkeitssuche. Das Schlagwort hier wäre "Korrelationsfunktion" (nicht die aus der Statistik, sondern die Umkehrung zur Convolution/Faltung in der Bildverarbeitung).
Leichte Kost ist das auch nicht gerade. Man sollte in der Lage sein, ein Bild per Fourier-Transformation (FFT) in den Frequenzraum zu transformieren (und wieder zurück) und auch komplexe Zahlen sollte einem nicht fremd sein. Zur Belohnung kann man dann ein kleineres Bild in einem größeren suchen und bekommt X- und Y-Koordinaten am Ende raus (als Maxima der Funktion, die die Ähnlichkeit der Bilder darstellt).
Zum schnellen Testen, kann man MatLab hernehmen:
Code:
functiong = dftcorr(f,w)
[M,N] = size(f);
F = fft2(f);
G = conj(fft2(w,M,N));
g = real(ifft2(G.*F));
gs= im2uint8(mat2gray(g));
figure; imtool(gs);
[I,J]= find(g == max(g(:)))
wobei hier w das gesuchte Muster und f das Gesamtbild ist. In I und J stehen dann nachher die Koordinaten (I=Y, J=X, weil Matlab spaltenweise arbeitet).
Das ganze in fertiger Form für Delphi kenne ich leider nicht, aber wenn dich das bisher nicht abgeschreckt hat: Zumindest zur Theorie dahinter hab ich noch ein wenig rumfliegen.

Das klingt ja schonmal genial :D...

Würde mich interessieren, was du noch so zum Thema hast. Und vllt kannste ja sogar eine Beispielfunktion in FPC basteln ??

Und was macht diese "Ähnlichkeitssuche" genau ?. Wandelt sie das Bild in ein verainfachtes Format um, und vergleicht gefundene Muster und formen ? Oder geht die im Endeffekte jeden Pixel durch und vergleicht ?

Danke schonmal.

~stiftII

stiftII 4. Mai 2012 19:46

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von fkerber (Beitrag 1164919)
Hi,

die eierlegende Wollmilchsau zum Thema Bilderkennung etc. dürft vermutlich Bei Google suchenOpenCV sein...

LG, Frederic

Das klingt auch klasse.. Aber so wie ich das sehe gibt es keine fpc implementation.

Würde das ganze gerne in Lazarus umsetzen.

Aphton 4. Mai 2012 20:42

AW: Grafiken erkennen. Library ?
 
Wie performant muss das ganze sein, wo willst du es genau einsetzen?
Darf das gesuchte Bild Abweichungen haben oder ist es exakt so im Bild enthalten?

himitsu 4. Mai 2012 22:40

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von shmia (Beitrag 1164907)
Zitat:

Zitat von freeway (Beitrag 1164904)
man kann jedes Pixel auslesen, man kann aber auch scanline verwenden (schneller)

Kommt drauf an, ob der Algorithmus es erlaubt sich im Bitmap horizontal zu bewegen.

Auch bei Scanline kann man ist man nicht auf eine horizontale Bearbeitung beschränkt.

- vorher in einem Pointer-Array alle Scanlines zwischenspeichern und schon hat man eine Art zweidimensionales Array

- sich den Zeiger auf die letzte Scanline holen (diese Bitmaps werden von unten nach oben gespeichert) und schon kann man über eine Art eindimensionales Array drauf zugreifen (alle Zeilen hintereinander)

Aphton 4. Mai 2012 23:01

AW: Grafiken erkennen. Library ?
 
xD
Genau dies habe ich implementiert und warte nun auf seine Antwort auf meine letzte Frage ^^ (+SAD, einfach und langsam)

Medium 5. Mai 2012 02:08

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von stiftII (Beitrag 1164920)
Wandelt sie das Bild in ein verainfachtes Format um, und vergleicht gefundene Muster und formen ? Oder geht die im Endeffekte jeden Pixel durch und vergleicht ?

An der Art und Weise wie du fragst, lässt sich zumindest schon mal gut erkennen, dass du eher nach einer fertigen Lib schauen solltest, als es zu versuchen selbst zu implementieren.
Nein, diese Suche transformiert die Bilder vom Ortsraum in den Frequenzraum, führt eine skaleninvariante Minimabestimmung einer Differenz der Faltung durch, und transformiert das gefundene Minimum zurück in den Ortsraum. Edit: Oder ist das das Maximum im Sinne einer Autokorrelation im Frequenzraum? Der Wein... Was mich brennend interessieren würde: Gibt es dafür auch eine skalen- und rotationsinvariante Version in ähnlicher Einfachheit?

bernhard_LA 5. Mai 2012 09:52

AW: Grafiken erkennen. Library ?
 
der Algorithmus zum Finden eines Suchbildes in einer großen Vorlage ist :
NORMALIZED CROSS CORRELATION - BZW. FAST NCC

unter http://sourceforge.net/projects/nccfastncc/ gibt eine Demo Application dazu in DELPHI.
Für unser Testbild benötigt die Version auf Source forge ~ 30 sec auf meinem Laptop, aktuell haben wir eine optimierte Version von FAST NCC entwickelt, die Suche
geht ca. 500 x schneller, dh. ist aber aktuell kein Open Source code. Falls Di ein Suchprojekt bearbeitest reicht Dir event. die Public Version des Algorithmuses.

Aphton 5. Mai 2012 14:13

AW: Grafiken erkennen. Library ?
 
Hier, die einfache Variante mit SAD (Sum of Absolute Differences (siehe Wikipedia))

Delphi-Quellcode:
function findPicture(const Source, Picture: TBitmap): TPoint;
type
  TPRGBTripleRow = Array of PRGBTriple;
var
  SourceScanlineRow  : TPRGBTripleRow;
  PictureScanlineRow : TPRGBTripleRow;
  function getRGBDifference(const ColorA, ColorB: PRGBTriple): Integer;
  begin
    Result := abs(ColorA.rgbtBlue  - ColorB.rgbtBlue) +
              abs(ColorA.rgbtGreen - ColorB.rgbtGreen) +
              abs(ColorA.rgbtRed   - ColorB.rgbtRed);
  end;
  function getPColor(const ScanlineRow: TPRGBTripleRow; const X, Y: Integer): PRGBTriple;
  begin
    Result := PRGBTriple(Integer(ScanlineRow[y]) + x * 3);
  end;
  procedure buildScanlineRows;
  var
    y: Integer;
  begin
    SetLength(SourceScanlineRow, Source.Height);
    for y := 0 to Source.Height - 1 do SourceScanlineRow[y] := Source.ScanLine[y];
    SetLength(PictureScanlineRow, Picture.Height);
    for y := 0 to Picture.Height - 1 do PictureScanlineRow[y] := Picture.ScanLine[y];
  end;
  function _findPicture: TPoint;
  var
    x, y, i, j : Integer;
    SAD        : Integer;
    curSAD     : Integer;
  begin
    SAD := -1; // not assigned
    for y := 0 to Source.Height - Picture.Height do
      for x := 0 to Source.Width - Picture.Width do
      begin
        curSAD := 0;
        for j := 0 to Picture.Height - 1 do
          for i := 0 to Picture.Width - 1 do
            inc(curSAD, getRGBDifference(getPColor(SourceScanlineRow, x + i, y + j), getPColor(PictureScanlineRow, i, j)));
        if (SAD = -1) or (curSAD < SAD) then
        begin
          SAD    := curSAD;
          Result := Point(x, y);
          if SAD = 0 then Exit;
        end;
      end;
  end;
begin
  if (Picture.Width > Source.Width) or (Picture.Height > Source.Height) or
     (Picture.PixelFormat <> pf24bit) or (Source.PixelFormat <> pf24bit) then
    Result := Point(-1, -1)
  else
  begin
    buildScanlineRows;
    Result := _findPicture;
  end;
end;
Edit: Das liefert die linke obere Ecke des Bereiches. Der Bereich hat klarerweise dieselbe Dimension wie "Picture"

taveuni 6. Mai 2012 11:15

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von stiftII (Beitrag 1164888)
Gibt es für diese Aufgabe irgendwelchen libs ?

Bei Mitov gibt es Bibliotheken für Delphi und .net.
Allerdings weiss ich nicht ob das Lazarus kompatibel ist.
Es gibt da auch Möglichkeiten mit opencv zu linken. Allerdings muss das training "von Hand" gemacht werden.
Ähnlichkeitssuche ist aber out of the box möglich.

Edit: Soeben habe ich gesehen dass nun sogar das Training für neuronale Netze implementiert ist.

stiftII 10. Mai 2012 18:46

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von Aphton (Beitrag 1164930)
Wie performant muss das ganze sein, wo willst du es genau einsetzen?
Darf das gesuchte Bild Abweichungen haben oder ist es exakt so im Bild enthalten?

Es darf minimale abweichungen haben. Und muss vorallem in jeder Größe gefunden werden.

Was macht die Funktion, die du gepostet hast genau ?

PS: Wenn ich die ausprobieren möchte bekomme ich ein "PRGBTriple not found"

Aphton 10. Mai 2012 19:54

AW: Grafiken erkennen. Library ?
 
Welche Delphiversion verwendest du?

Ich schätz mal, eine etwas ältere, in der es diesen Typ nicht gibt.

Du kannst sie hier definieren:

Delphi-Quellcode:
type
  PRGBTriple = ^TRGBTriple;
  TRGBTriple = record
    rgbtBlue: Byte;
    rgbtGreen: Byte;
    rgbtRed: Byte;
  end;
  TPRGBTripleRow = Array of PRGBTriple;
Die Funktion liefert dir die Koordinaten der linkeren oberen Ecke im Bild, wo es halt gefunden wurde.

Anwendung:

Delphi-Quellcode:
var
  Position: TPoint;
begin
  Position := findPicture(RiesengroßesBild, SuchBild);
  ShowMessage('Gefunden an der Stelle: ' + IntToStr(Position.X) + ' - ' + IntToStr(Position.Y));
end;
Edit: Skalierung wird nicht berücksichtigt! Dies ginge aber auch ganz einfach (jedoch übelst unperformant) indem man das Suchbild zuerst mal richtig runterskaliert, dann schrittweise hochskaliert bis man dieselben Dimensionen wie das "RiesngroßeBild" hat und meine Suchfunktion drüberjagt!

Edit2: Das Ganze ist mehr oder weniger die Implementierung von dem hier (Anwendung: hier)

stiftII 10. Mai 2012 20:14

AW: Grafiken erkennen. Library ?
 
Zitat:

Edit: Skalierung wird nicht berücksichtigt! Dies ginge aber auch ganz einfach (jedoch übelst unperformant) indem man das Suchbild zuerst mal richtig runterskaliert, dann schrittweise hochskaliert bis man dieselben Dimensionen wie das "RiesngroßeBild" hat und meine Suchfunktion drüberjagt!
Das ist eine interessante vorgehensweise.

Wie genau würde diese Funktion denn das skalierte Bilder erkennen ?

Beim skallieren gibt es ja auch immer einen qualitätsverlust, wenn das Original-Bild zB kleiner ist als das zu suchende "fragment".

PS: Ich arbeite mit Lazarus (fpc) und hab gerade festgestellt, dass es scanline dort nicht gibt :x ....

Aphton 10. Mai 2012 20:22

AW: Grafiken erkennen. Library ?
 
Pff, um ehrlich zu sein, habe ich keine Lust, dir das anzupassen =/
Scanline ist einfach ein direkterer Weg, auf den Farbspeicher zuzugreifen. Evt. gibts unter Lazarus Pixels[]?

stiftII 11. Mai 2012 00:13

AW: Grafiken erkennen. Library ?
 
Zitat:

Zitat von Aphton (Beitrag 1165971)
Pff, um ehrlich zu sein, habe ich keine Lust, dir das anzupassen =/
Scanline ist einfach ein direkterer Weg, auf den Farbspeicher zuzugreifen. Evt. gibts unter Lazarus Pixels[]?

ich hab ne Möglichkeit gefunden scanline zu implementieren :x..
jetzt fehlt aber "PixelFormat"


Alle Zeitangaben in WEZ +1. Es ist jetzt 22:00 Uhr.

Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz