Hi Leute, Ich würde gerne ein Programm schreien in dem ich ein Arkustisches Signal bekomme wenn ich einen bestimmten String im Bildschirm habe. Zb. wenn ich auf einer beliebigen Internetseite surfe und durch scrolle und dann irgendwo das wort "Hallo" steht soll ein Ton erklingen. Habt ihr irgend einen plan was es da für Befehle gibt um den aktuellen Bildschirm nach Strings zu durchsuchen?? Bin Leider nur im Bereich Mikrocontroller unterwegs und hab daher fast keinen Plan von Windows bzw PC programmierung. mfg Matthias
Matthias P. schrieb: > Zb. wenn ich auf einer beliebigen Internetseite surfe und durch scrolle > und dann irgendwo das wort "Hallo" steht soll ein Ton erklingen. > Habt ihr irgend einen plan was es da für Befehle gibt um den aktuellen > Bildschirm nach Strings zu durchsuchen?? geht im zweifelsfall überhaupt nicht. Es gibt programme die Rendern den Text als Bild. Da bräuchte man eine OCR. sonst könnte man es über http://msdn.microsoft.com/en-us/library/db50wx7h(v=vs.80).aspx versuchen-
Wenn es nur um Webseiten geht, kann Proxomitron Text erkennen und auch ändern, und ist da relativ einfach machbar. Hm, über den Ton müßte man nochmal nachdenken. Reicht ein Alert-Dialog? Das geht auf jeden Fall. Hm hm, Sound abspielen können Webseiten doch auch, dann gehts auch in Proxomitron.
Eventuell würde dir Javascript + GreaseMonkey helfen. Da könntest du mit Javascript ein HTML-5-Element erzeugen und das direkt abspielen. Dürfte auch mit einer Datei auf dem eigenen Rechner funktionieren
Danke schon mal. Also um es komplett auf zu klären. Das ganze soll für Diablo3 sein ich möchte quasi ein Programm im hintergrund laufen lassen das mir einen Ton gibt wenn bestimmte Itemnamen auftauchen.
Tja, dann sind alle Vorschläge natürlich sinnlos. Deshalb ist es manchmal nützlich, das Problem gleich zu nennen... Solch ein Vorhaben halte ich für relativ knifflig, also zumindest von komplett außerhalb des Spiels. Den Framebuffer kannst du jedenfalls nicht die ganze Zeit durch OCR jagen*, das ist performancetechnisch total unmachbar. Selbst periodisch Screenshots aufzunehmen, sagen wir, alle halbe Sekunde... ich bin nicht sicher, ob das nicht ziemliche Ruckler verursachen würde. Und dann muss man natürlich auf den Screenshots ein OCR machen. Das ist nochmal ziemlich schwierig, bei dem ganzen Kram der da rumfliegt (das OCR-Programm weiß ja erstmal gar nicht wo der Text überhaupt ist). Fazit, nichts, von dem ich denke, dass ein Freizeitprogrammierer es in wenigen Tagen schreiben könnte. Eine weitere Möglichkeit wäre allerdings, die Diablo-APIs zu durchstöbern -- vielleicht gibt's ja da was, was alle Items auf dem Bildschirm auflistet oder so. Keine Ahnung. Oh, oder den Netzwerktraffic mitschneiden und dort nach dem Namen des Items greppen. Das könnte potentiell relativ einfach sein -- vorausgesetzt, die Kommunikation erfolgt unverschlüsselt (oder ist zumindest ohne viel Reverse-Engineering entschlüsselbar). Und falls die Namen der Items überhaupt über's Netzwerk gesendet werden, das muss ja auch nicht unbedingt der Fall sein. Grüße, Sven _____ * ... außer vielleicht, man implementiert OCR in einem Shader! Das klingt doch interessant, ein OCR-Shader, oder?
mhh ja ka ich weiß nur das es funktioniert weil ich es in nem youtube Vid. gesehen habe :) Naja dachte das man einfach den Outstream von der Grafikkarte druchsuchen könnte :-P Hab ich mich wohl getäuscht. Aber Trotzdem danke :-P
Es gibt im Web ein Open Source Projekt zum Scannen von Autonummern "automate number plate scanning" im laufenden Verkehr, das beruht auf der mittlerweile freien OCR-Software Tesseract. Da dürften die Anforderungen änhlich sein ... vlt. lässt sich davon etwas ableiten. http://www.youtube.com/watch?v=9vzR_H-jjHk
Tesseract braucht bei mir ca. 1.6 Sekunden, um ein Fullscreen-Bild zu durchsuchen. Gut, angenommen man hat 8 CPU-Cores und kann irgendwie 4 davon komplett für 4 parallel laufende Tesseract-Instanzen abzweigen... trotzdem irgendwie zweifelhaft, ob das zufriedenstellend funktioniert ;)
die Itemnamen werden mit Sicherheit nicht übers Netzwerk übertragen, da die Sprache am Client hängt. Außerdem ist die Kommunikation mit Sicherheit verschlüsselt. Auch von Direktmanipulation (Debugger, Prozessspeicher auslesen, oder gar patchen des Prozessspeichers) des Diablo-Prozesses würde ich absehen. Das größte Problem ist imho das live-grabben eines screenshots. dafür gibt es sicherlich tools, die vielleicht auch eine API haben. Der Rest ist ein wenig Bildverarbeitung. die Items heben sich ja relativ gut vom Hintergrund ab und haben nur bestimmte Farben und definierte Schriftgröße. Einfacher ist es wahrscheinlich ohne OCR sondern eher mit Templatematching mit gespeichertem Screenshot-Ausschnitt des gesuchten Wortes. Was für einen Einfluss das am Ende in Summe auf die Framerate hat, kann ich nicht abschätzen, glaub aber nicht, dass das ein Problem ist mit vielleicht 20Hz auf einem eigenen Core das Bild zu verarbeiten. Man sollte natürlich nicht über die screenshot auf Festplatte speichern-Funktion von Diablo gehen. Als erstes würde ich schauen, ob ein normales Print-Screen das Fenster erfasst, glaubs aber fast nicht, weil das im Direct3d läuft. Ich finde das ganze aber relativ riskant. Blizzard sperrt gerne mal Accounts, wenn der Verdacht aufkommt, dass sich jemand mit Hilfe von Zusatzprogrammen Vorteile verschafft. was für Items willst du denn Finden? die Farbkodierung grau, weiß, hellblau, blau, gelb und golden ist imho recht gut gewählt und Ausreichend. Edit: Das Abspielen des Sounds am Ende ist ein Kleinigkeit.
Matthias P. schrieb: > mhh ja ka ich weiß nur das es funktioniert weil ich es in nem youtube > Vid. gesehen habe :) dann frag doch den Autor, was er für ein Programm benutzt.
Vlad Tepesch schrieb: > die Itemnamen werden mit Sicherheit nicht übers Netzwerk übertragen, da > die Sprache am Client hängt. Ok, guter Einwand -- vielleicht wird aber eine ID o.ä. übertragen, die sich äquivalent verwenden lässt. > Außerdem ist die Kommunikation mit Sicherheit verschlüsselt. Weißt du das oder vermutest du das? ;) > Auch von Direktmanipulation (Debugger, > Prozessspeicher auslesen, oder gar patchen des Prozessspeichers) des > Diablo-Prozesses würde ich absehen. Wieso? Auch nicht "riskanter" als Screenshots auswerten, wenn man es richtig macht, oder? > Das größte Problem ist imho das live-grabben eines screenshots. dafür > gibt es sicherlich tools, die vielleicht auch eine API haben. Hier sehe ich überhaupt kein Problem, zumindest nicht bei der Machbarkeit -- bloß bei der Performance. Es gibt sicherlich tausende Tools die das können. > Einfacher ist es wahrscheinlich ohne OCR sondern eher mit > Templatematching mit gespeichertem Screenshot-Ausschnitt des gesuchten > Wortes. Das ist ebenfalls eine sehr gute Idee, die ist so gut, dass sie fast funktionieren könnte. ;) Das ist dann natürlich auch viel schneller als OCR. Ja, das könnte fast funktionieren: 2D-Cross Correlation von den beiden Bildern ausrechnen sollte relativ fix gehen, und dann einfach schauen ob das irgendwo einen bestimmten Wert überschreitet. Wenn man dann noch vermeidet, den Screenshot erst in PNG zu komprimieren und auf der Platte zu speichern, und stattdessen direkt die Pixel aus dem Speicher kopiert... könnte gehen. Aber anscheinend ist der TO daran ja nicht so wirklich interessiert. ;) Grüße, Sven
Evtl. kann man sich zwischen Diablo und DirectX einklinken, und den Text abfangen bevor er zu Texturen verwustet wird? => Keine OCR nötig? Bei OpenGL/Linux wär das z.B. ein LD_PRELOAD, welches z.B. "glutBitmapCharacter"&co überwacht, oder entsprechende freetype-Funktionen. Halt je nachdem wie im Programm das Text-Zu-Textur implementiert ist. Aber wenn's nur für exakt ein Programm laufen soll, viel einfacher als OCR, und kostet (fast) keine Rechenzeit extra.
ist das ein Online Spiel? die haben doch sicher (einige) Vorkehrungsmaßnahmen um solche Cheats zu verhindern..
Robert L. schrieb: > ist das ein Online Spiel? > > die haben doch sicher (einige) Vorkehrungsmaßnahmen um solche Cheats zu > verhindern.. Deine Hardware zeichnet den Text, also kann dich prinzipiell nichts daran hindern, das zu überwachen wie du willst.
Ich weiss von anderen Online Games dass man dort Addons schreiben kann. Geht das nicht auch für Diablo III? Dass Addon müsste nur den Chat parsen und entsprechend eine Rückmeldung geben.
Sven B. schrieb: >> Außerdem ist die Kommunikation mit Sicherheit verschlüsselt. > Weißt du das oder vermutest du das? ;) ich weiß es nicht, bin mir aber extrem sicher, da Blizzard einiges an Aufwand treibt um Bots oder ähnliches zu unterbinden. Deswegen würde ich alles vermeiden, was irgendwie in den Prozess eingreift. Also auch: Εrnst B✶ schrieb: > Evtl. kann man sich zwischen Diablo und DirectX einklinken, und den Text > abfangen bevor er zu Texturen verwustet wird? Sven B. schrieb: >> Das größte Problem ist imho das live-grabben eines screenshots. dafür >> gibt es sicherlich tools, die vielleicht auch eine API haben. > Hier sehe ich überhaupt kein Problem, zumindest nicht bei der > Machbarkeit -- bloß bei der Performance. Genau deswegen sehe ich da ein Problem, da fehlt mir aber die Erfahrung. man könnte mal nach Open-Source Game-Screen-Recordern schauen. Sven B. schrieb: > Ja, das könnte fast funktionieren: 2D-Cross Correlation von den beiden > Bildern ausrechnen sollte relativ fix gehen, und dann einfach schauen ob > das irgendwo einen bestimmten Wert überschreitet. Ich würde versuchen, mit einem möglichst billigem Verfahren sämtliche Item-Textboxen zu finden. Dann in X-Richtung mein Template über die Boxen schieben und die Übereinstimmung berechnen. Die Templates über das gesamte Bild zu schieben ist zu rechenzeitaufwendig. Ein Problem könnte sein, dass man die Box bei dunklem Hintergrund nicht erkennen kann. Hier könnten die genauen Farbwerte der Schrift einen Anhaltspunkt liefern um eine Box zu generieren, in der man dann eventuell aber 2-dimensional das Template drüber schieben muss. Den Einfluss des Hintergrundes hinter der teil-transparenten Box müsste man auch noch untersuchen. Das kriegt man aber sicher durch durch geschickte Bildverarbeitung weg. Ebenso wie die unterschiedlichen Farben, damit man nicht von jedem Typ ein Screenshot braucht. Ich glaub ich probiere das heute Abend mal auf ein paar Beispiel Screenshots aus. Mich würde trotzdem interessieren wofür er das will. Mir würden nur die Rezepte einfallen, die in der Farbe des Items, das sie generieren fallen und die man eventuell übersieht, wenn man keine blauen sammelt. oder die dämonischen Essenzen, die man übersieht, wenn man gelb auch nicht aufhebt.
Deshalb Cross Correlation: Mit der Box-Methode bist du auf jeden Fall in n², weil du im Endeffekt jeden Pixel ausprobieren musst. Nimmst du ein FFT-basiertes Verfahren [1], bist du in n log n -- ich denke sogar, dass das relativ einfach zu implementieren ist, wenn man die 2D-FFT schon hat (und die gibt's überall). Grüße, Sven ___ [1] http://www.mathworks.com/products/demos/image/cross_correlation/imreg.html?nocookie=true
was ich beschreibe ist doch auch eine Cross Correlation Analyse. Auf das Vergleichskriterium hab ich mich doch gar nicht festgelegt. Ich hatte aber eher SAD im Sinn. Mir ist aber auch nicht klar, wie du auf nlogn kommst. 2d-cross correlation an sich ist doch schon n²
Wieso? Eine FFT von n Pixeln sollte in n log n sein. Die Bilder pixelweise übereinander zu schieben und zu vergleichen kostet dich n² -- ein n für jeden Schritt, und n Schritte. 2D Cross Correlation sollte eigentlich bloß zwei FFTs und eine Multiplikation sein. Edit: Ach so, wahrscheinlich ist das ein Missverständnis: Ich meinte mit n die Anzahl der Pixel, du wahrscheinlich die Seitenlänge vom Bild. Dann ist das sowas wie n^2 log n vs n^4.
ach so, ich meinte mit n tatsächlich die Bildkantenlänge (wobei es natürlich nicht quadratisch ist) eigentlich gibts hier 2 Größen B Anzahl Pixel im Bild (zB: 1960*1080 = 2.116.800) T Anzahl Pixel des Templates (je nach Buchstabenzahl <4000) ein einziger Vergleich hat mit FFT also T log T Aufwand (laut dir - keine Ahnung ob das stimmt. FTs sind nicht so meins) ein einziger Vergleich mit SAD hat den Aufwand T Diesen Vergleich macht man je nach Ansatz - über das gesamte Bild ~B mal oder - nur an Fundstellen von Textboxen n*b*h mal n - Anzahl Textboxen(kandidaten) n<200 b - Breite der Textboxen - Templatebreite b<150 h - Höhe der Textboxen - Templatehöhe h<10 Die Frage ist, wie aufwendig die Detektion von Itemtextboxen ist. wenn man mehrere Templates hat hat man auf jeden Fall durch die Einschränkung der möglichen Positionen schon mal enorm gewonnen.
Ne! Der Witz an der FFT-Methode ist, dass sie das Template gleichzeitig mit allen Stellen vom Bild vergleicht. Du musst nur die beiden Fouriertransformierten ausrechnen, die eine komplex konjugieren, mit der anderen multiplizieren, rücktransformieren, Betrag bilden, und da wo der größte Wert ist, ist die beste Übereinstimmung zwischen den beiden Bildern. Man muss das nicht für jeden Pixel machen, sondern braucht nur genau 3 FFTs pro Template und Bild. Für eine FFT von einer Million Punkten braucht numpy etwa eine zehntel Sekunde, also könnte das performancetechnisch machbar sein. Grüße, Sven
Ok, das raff ich nicht. kannst du das mal mit Matlab/Octave Code ausführen? Ich kann es mir aber auch nicht wirklich vorstellen. Wenn das so einfach wäre, würde es ja jeder fürs Template-Matching verwenden. Bin gestern habend nicht zu so viel gekommen. Die Boxen zu Extrahieren ist nicht ganz so einfach, das sie ziemlich schmal um den Text sind und scheinbar einem Transparenz-Gradienten haben. Am erfolgversprechendsten sieht da noch eine Farbsegmentierung im HSV-Farbraum aus, wobei hier bei meinem Testbild bei der Unique-Farbe ziemlich viel Schrott mit aufsammelt wird. rare und set sieht ganz gut aus. Übrigens: die oben von dir verlinkte normxcross2 Funktion faltet auch das Eingabebild mit dem Template
Hab das mal in python implementiert (Code unten). Das erste Bild ist ein Beispiel-Bild was ich mit Gimp gemalt habe. Das zweite ist dasselbe Bild um ein Stück verschoben (könnte auch ein Ausschnitt sein, kannst du gern ausprobieren). Das dritte Bild ist die Cross correlation, die in n log n (n -> Anzahl der Pixel) berechnet werden kann (siehe Code für den Nachweis dafür, es werden nur FFTs und punkteweise Multiplikationen verwendet). Das vierte Bild zeigt die Cross Correlation über das ursprüngliche Bild gelegt; der rote Punkt markiert, wie weit man example2.png verschieben muss, sodass es sich mit example1.png deckt. Es ist gut zu sehen, dass der hellste Punkt der Cross Correlation sich mit diesem roten Punkt gerade deckt. Die Ausgabe vom hellsten Punkt in numpy passt irgendwie nicht, ich glaube man muss das noch spiegeln oder so, hatte jetzt aber keine Lust mehr das hinzubiegen. Viel Spaß damit und viele Grüße, Sven
1 | #!/usr/bin/env python2
|
2 | # -*- Coding:utf-8 -*-
|
3 | |
4 | # you need numpy and PIL to run this
|
5 | import numpy as np |
6 | import Image, ImageOps |
7 | |
8 | def imageToArray(image): |
9 | grey = ImageOps.grayscale(image) |
10 | data = grey.tostring() |
11 | # there should be 1 byte for each pixel in that data
|
12 | assert len(data) == grey.size[0] * grey.size[1] |
13 | # convert to an array, data type is unsigned char (8-bit greyscale)
|
14 | arr = np.fromstring(data, dtype=np.uint8) |
15 | arr = arr.reshape(grey.size[0], grey.size[1]) |
16 | assert arr.shape == grey.size |
17 | return arr |
18 | |
19 | def arrayToImage(array): |
20 | size = array.shape |
21 | array -= array.min() |
22 | array = array / array.max() * 255 |
23 | array = np.array(array, dtype=np.uint8).flatten() |
24 | data = array.tostring() |
25 | return Image.fromstring("L", size, data) |
26 | |
27 | def register(image1, image2): |
28 | input1 = imageToArray(image1) |
29 | input2 = imageToArray(image2) |
30 | |
31 | # do fourier transform on both images
|
32 | fft1 = np.fft.fft2(input1) |
33 | fft2 = np.fft.fft2(np.fliplr(np.flipud(input2))) |
34 | |
35 | arrayToImage(abs(fft1)).save("fft1.png") |
36 | arrayToImage(abs(fft2)).save("fft2.png") |
37 | |
38 | # calculate F(im1) element-wise-multiply F(im2)
|
39 | fft_result = fft1 * fft2 |
40 | output = np.abs(np.fft.ifft2(fft_result)) |
41 | output = output / np.max(output) * 255 |
42 | |
43 | print(np.unravel_index(np.argmax(output), output.shape)) |
44 | return arrayToImage(output) |
45 | |
46 | if __name__ == '__main__': |
47 | register(Image.open('example.png'), Image.open('example2.png')).save("result.png") |
Ich glaube der Thread hat sich inzwischen weit genug vom ursprünglichen Thema entfernt, dass es hier kaum mehr um's cheaten geht :D
@Sven: Wenn man nun deinen Ansatz nimmt und noch eine Maximumssuche durchführt (hellster pixel in der crosscorrelation) und darauf einen entscheider aufsetzt, kann man die Texte finden ;) und damit sind wir wieder beim cheaten :P
Ja, aber wer von den Leuten hier in dem Thread, die in der Lage sind, das Proof-of-Concept-Skript zum funktionierenden Cheat-Tool umzubauen, wird das tun? Ich jedenfalls nicht. ;)
Sven B. schrieb: > Hab das mal in python implementiert (Code unten). kannst du die bilder mal erklären? die fft-Bilder sind komplett schwarz (wert 0) des result-bild sagt was aus? Ich seh da zwei überlappte eingangsbilder. wenn man nur ein paar dickere linien einzeichnet (ohne das pattern zu zerstören) findet er es schon nicht mehr. AUf den Originalbildern aus dem Spiel funktioniert ganze natürlich überhaupt nicht. Dann zeigt die ausgegebene Position auf weißen Bereich, wo überhaupt nix zu sehen ist. wirklich überzeugt bin ich von dem Ansatz nicht. Da Dieter schrieb: > Cheater haben kleine Schwänze. was soll daran ein cheat sein? Man erkennt, wenn ein bestimmtes item gedropt wird - und? Außer den Vorteil, dass man es so nicht übersieht hat das genze überhaupt keinen Einfluss.
Vlad Tepesch schrieb: > Sven B. schrieb: >> Hab das mal in python implementiert (Code unten). > > kannst du die bilder mal erklären? > die fft-Bilder sind komplett schwarz (wert 0) Das bezweifle ich, schau mal genauer hin. Es sind viele Pixel schwarz, ja, aber nicht alle. Die beiden Bilder sind die Fouriertransformierten der zwei Eingangsbilder. > des result-bild sagt was aus? Das ist das rücktransformierte Korrelations-Bild, der hellste Punkt ist der Punkt bester Korrelation. > Ich seh da zwei überlappte eingangsbilder. Hm? Poste mal eins davon. > wenn man nur ein paar dickere linien einzeichnet (ohne das pattern zu > zerstören) findet er es schon nicht mehr. > AUf den Originalbildern aus dem Spiel funktioniert ganze natürlich > überhaupt nicht. Dann zeigt die ausgegebene Position auf weißen Bereich, > wo überhaupt nix zu sehen ist. Soweit ich weiß, muss der Pattern im Muster-Bild links oben vom Vorkommen im tatsächlichen Bild sein. Dazu kommt halt, dass einfach so mit harten Kanten einen Pattern rausschneiden nicht so gut ist, man sollte ein geeignetes Fenster wählen (quadratusch oder exponentiell oder was auch immer). In meinem Beispiel hab ich mir das gespart, indem ich das Bild gar nicht zerschnitten habe. > wirklich überzeugt bin ich von dem Ansatz nicht. Mathematisch gesehen ist die Methode perfekt. Klar ist natürlich, dass das so ohne geeignete Filter in der Realität nicht funktionieren wird. Damit muss man sich halt noch beschäftigen ;) Insbesondere ist es wichtig, für den gewählten Bildausschnitt die Kanten auf die richtige Weise zu glätten. Davon abgesehen bin ich mir zugegebenermaßen auch nicht hundertprozentig sicher, dass ich das richtig implementiert habe, vielleicht ist da noch was falsch *g Grüße, Sven
Ah, hier ist der Fehler: fft2 mag keine nicht-quadratischen Bilder, nimm mal quadratische Eingabedateien, dann funktioniert es sehr gut. Daher kommen auch die komischen Streifen. Im Anhang nochmal ein Beispiel für Text. Wegen der FFT-Bilder, hm, ja irgendwas ist da schon komisch, es sind zuviele Pixel schwarz, da hast du Recht (nicht alle!). Finde das Problem aber gerade nicht... Ah, doch, ersetze mal das abs durch np.abs in der Zeile wo die ausgegeben werden. Dann passt es.
Sven B. schrieb: > Ah, hier ist der Fehler: fft2 mag keine nicht-quadratischen Bilder, nimm > mal quadratische Eingabedateien, dann funktioniert es sehr gut. Daher > kommen auch die komischen Streifen. ahh, hetzt sind die bilder nachvollziehbar. im anhang mal zwei praxisbeispiele. schwarzweis ist natürlich nicht optimal, da die Farbe hier sehr viel Information trägt. Man könnte im HSV Farbraum die 3 Kanäle separat bearbeiten und die Ergebnisse verunden und dann Maxima suchen.
Zurück zum ursprünglichen Tema: Nein, es geht nicht. Zu Zeiten der ersten PC's gab es noch einen Bildschirmspeicher, in dem tatsächlich die dargestellten Zeichen standen - lang, lang ist's her. Wenn heutzutage überhaupt Zeichen dargestellt werden, so sind die durch den gerade aktuellen Zeichensatz, Renderer und anderes kräftig durchgerührt worden. Ein einfacher Versuch, den Du jederzeit machen kannst ist: Rufe ein beliebiges Textdokument auf und Fummel am Zeichensatz rum. Der Text bleibt zwar der gleiche, das Aussehen ist aber, je nach Zeichensatz oder Zeichengröße, verschieden. Jedes Programm, das das lesen wollte, müsste sich mit dem "Aussehen" rumärgern. Im Grunde gibt es nur zwei Möglichkeiten, zu lesen was auf dem Bildschirm angezeigt ist. 1. Du kommst irgendwie an die Quelldaten (txt, html ...) ran und liest diese. 2. Du lässt einen Screenreader (OCR) auf deinen Bildschirm los.
Hä? Wie nahe am ursprünglichen Thema sollten wir denn noch sein? -- Ha! Jetzt hab ich's aber komplett verstanden: was hier noch fehlte, war eine Normalisierung des Produkts. Deshalb war die Korrelation auch immer scheinbar dort größer, wo die Bilder heller waren, was natürlich keinen Sinn macht (um das nochmal klar zu sagen: der Code, den ich oben gepostet habe, funktioniert nicht vernünftig). Jetzt aber funktioniert es perfekt! Deine Bilder habe ich noch leicht trivial modifiziert, um Randeffekte zu vermeiden, und habe das perfekt zur weiteren Verarbeitung geeignete Ergebnis aus dem Anhang erhalten (man muss Rechtsklick -> view image machen und dann vergrößern, sonst sieht man nix -- sind nur wenige helle Pixel). Um das nochmal klar zu erwähnen: Die bearbeiteten Bilder dürfen keine künslichen scharfen Kanten haben. Solche scharfen Kanten verursachen in der FFT große Störungen und beeinträchtigen die Qualität des Ergebnisses enorm. Grüße, Sven Ach, hier noch der korrigierte Code:
1 | #!/usr/bin/env python2
|
2 | # -*- Coding:utf-8 -*-
|
3 | |
4 | import numpy as np |
5 | import Image, ImageOps |
6 | |
7 | def imageToArray(image): |
8 | grey = ImageOps.grayscale(image) |
9 | data = grey.tostring() |
10 | # there should be 1 byte for each pixel in that data
|
11 | assert len(data) == grey.size[0] * grey.size[1] |
12 | # convert to an array, data type is unsigned int
|
13 | arr = np.fromstring(data, dtype=np.uint8) |
14 | arr = arr.reshape(grey.size[0], grey.size[1]) |
15 | assert arr.shape == grey.size |
16 | return arr |
17 | |
18 | def arrayToImage(array): |
19 | size = array.shape |
20 | array -= array.min() |
21 | array = array / array.max() * 255 |
22 | array = np.array(array, dtype=np.uint8).flatten() |
23 | data = array.tostring() |
24 | return Image.fromstring("L", size, data) |
25 | |
26 | def register(image1, image2): |
27 | input1 = imageToArray(image1) |
28 | input2 = imageToArray(image2) |
29 | # normalize images
|
30 | input1 = ( input1 - np.mean(input1) ) / np.std(input1) |
31 | input2 = ( input2 - np.mean(input2) ) / np.std(input2) |
32 | |
33 | # do fourier transform on both images
|
34 | fft1 = np.fft.fft2(input1) |
35 | fft2 = np.fft.fft2(np.fliplr(np.flipud(input2))) |
36 | |
37 | # calculate F(im1) element-wise-multiply F(im2)
|
38 | fft_result = fft1 * fft2 / np.abs(fft1 * fft2) |
39 | output = np.abs(np.fft.ifft2(fft_result)) |
40 | output = output / np.max(output) * 255 |
41 | |
42 | print(np.unravel_index(np.argmax(output), output.shape)) |
43 | return arrayToImage(output) |
44 | |
45 | if __name__ == '__main__': |
46 | register(Image.open('example.png'), Image.open('example2.png')).save("result.png") |
Heh, noch ein Beitrag, zum Abschluss der Verwirrung: Das Problem kam daher, dass man nicht die Cross Correlation, sondern die punktweise normierte Cross Correlation berechnen muss. Dieser Artikel erklärt das Verfahren [1]. Man nimmt also nur die Phase von dem Produkt im Frequenzraum, und wirft die Amplitude weg. Grüße, Sven __ [1] http://en.wikipedia.org/wiki/Phase_correlation
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.