Mit OpenCV und Python habe ich ein Tool erstellt, das die Ausrichtungslöcher von Animationsvideopapier wie unten gezeigt erkennt und die Fehlausrichtung des gescannten Bildes beseitigt. Ein praktischer Artikel für Anfänger von OpenCV und Python. Siehe hier für OpenCV
Beim Erstellen einer Animation ist es einfach, die 2D-Keyframe-App wie 9VAe Kyubee zu verwenden. Wenn Sie jedoch eine nach der anderen auf Videopapier zeichnen, sind es mehrere hundert Es wird viel mehr als eins sein. Wenn Sie dies in einen Computer mit einem Scanner mit automatischem Einzug eingeben, verschiebt sich zwangsläufig die Position mehrerer Punkte, und das Bild wird bei der Wiedergabe unscharf.
Erstellen wir daher ein Tool "Peascan.py", das Löcher auf dem Videopapier erkennt und die Fehlausrichtung durch Bildverarbeitung korrigiert.
Eingang | Seriennummer mit Fehlausrichtung 100 JPEG-Bilder |
---|---|
Ausgabe | Seriennummer ohne Fehlausrichtung 100 JPEG-Bilder |
Umgebung | Windows |
Locherkennung, Bilddrehung und Korrektur von Fehlausrichtungen sollten mit OpenCV einfach sein.
Verfahren | Inhalt | Ergänzung |
---|---|---|
1.herunterladen | http://python-xy.github.io/downloads.htmlVonPython(x,y)-2.7.10.0.exe | KlickenSiehierfüreinedetaillierteInstallationsmethode |
2.Installation | Klicken Sie auf die Schaltfläche "Weiter" Klicken Sie im Bildschirm "Komponenten auswählen" rechts neben "Benutzerdefiniert" auf "↓" und dann auf "FullKlicken. Danach "Weiter" und "Installieren" |
Sie können auch Benutzerdefiniert öffnen und OpenCV aktivieren. |
Es installiert Python 2.7.10, OpenCV 2.4.12, was etwas früher ist, aber es funktioniert gut.
Lassen Sie uns ein einfaches Python + OpenCV-Programm erstellen.
Artikel | Punkt |
---|---|
Zeichencode | 「UTF8」。メモ帳で保存する場合、「ファイル」>「名前を付けて保存」>下の「Zeichencode」を「UTF-Speichern Sie als "8". |
Erweiterung | .py |
Lauf | An der Eingabeaufforderungpython xxx.py |
Speichern Sie den folgenden Text als "UTF-8" mit dem Namen "test.py". Wenn Japanisch im Pfad enthalten ist, funktioniert es möglicherweise nicht. Es empfiehlt sich daher, einen Ordner wie "c: \ pytest" zu erstellen und zu speichern. xx Beispielbild Bereiten Sie anstelle von xx eine entsprechende Bilddatei vor und geben Sie den Pfadnamen ein (c: /pytest/test.jpg usw.). Japanische Namen können nicht verwendet werden. Der Pfadbegrenzer ist "/".
import numpy as np
import cv2
img = cv2.imread('C:/xx Beispielbild xx.jpg')
print img.shape
print img.shape[0], img.shape[1]
cv2.imshow('Title',img)
cv2.waitKey(5000)
Jeder hat die folgenden Bedeutungen.
Artikel | Anwendungsbeispiel | Erläuterung |
---|---|---|
Numerische Berechnung | import numpy as np | Numerische Berechnungライブラリを使う |
Bildverarbeitung | import cv2 | OpenCV Bildverarbeitungライブラリを使う |
Bild laden | img = cv2.imread('C:/Beispielbild.jpg') | Japanisch kann nicht für Dateien und Pfadnamen verwendet werden. Der Pfadbegrenzer lautet "/」 |
Variable Anzeige | 「,Zeigen Sie alles an, indem Sie sie mit "" trennen | |
Bildgröße | img.shape | Bild img(Höhe, Breite, Anzahl der Kanäle) |
Bildschirm | cv2.imshow('Title',img) | Bild img im Fenster anzeigen |
Pause | cv2.waitKey(5000) | Halten Sie 5 Sekunden lang an und warten Sie auf die Tasteneingabe, wenn 0 |
python test.py
ein und drücken Sie die EingabetasteNachdem Sie das Bild angezeigt haben, schreiben Sie es wie folgt aus der Zeile nach "img =" in "test.py". Angenommen, im oberen linken Bereich (0,0) - (200.200) des Bildes befindet sich eine Markierung. Suchen Sie den Schwerpunkt. Passen Sie die Werte von frmX, toX, frmY, toY entsprechend der Größe des Bildes an.
import numpy as np
import cv2
img = cv2.imread('C:/xx Beispielbild xx.jpg')
frmX,toX = 0,200 #Markierungsbereich (Löcher)
frmY,toY = 0,200 #Markierungsbereich (Löcher)
mark = img[frmY:toY, frmX:toX] #Teilbild
gray = cv2.cvtColor(mark, cv2.COLOR_BGR2GRAY) #Einfarbig
ret, bin = cv2.threshold(gray, 127, 255, 0) #Binarisierung
cv2.imshow('out',bin) #Bereich markieren
cv2.waitKey(1000) #1 Sekunde Stopp
contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #Extraktion der Kontur
cnt = contours[0] #Erste Kontur
M = cv2.moments(cnt) #Moment
cx = int(M['m10']/M['m00']) #Schwerpunkt X.
cy = int(M['m01']/M['m00']) #Schwerpunkt Y.
cv2.circle(img,(cx,cy), 10, (0,0,255), -1)
print cx,cy
cv2.imshow('Title',img)
cv2.waitKey(5000) #5 Sekunden Anzeige
Artikel | Anwendungsbeispiel | Erläuterung |
---|---|---|
Mehrere gleichzeitige Aufgaben | frmX,toX = 200,600 | frmX=200 toX=Gleich wie 600 Mit einer Funktion können mehrere Werte zugewiesen werden |
Teilbild | img[frmY:toY, frmX:toX] | img(frmX,frmY)-(toX,toY)Mitnahme |
Einfarbig | gray = cv2.cvtColor(mark, cv2.COLOR_BGR2GRAY) | Erstellen Sie einfarbiges Grau aus der Farbbildmarkierung |
Binarisierung | ret, bin = cv2.threshold(gray, 127, 255, 0) | grayをBinarisierungして bin を作成 |
Schwarz-Weiß-Inversion | bin = ~bin |
Keine Operation für den gesamten Array-Bin |
Extraktion der Kontur | contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | Konturen haben Konturen |
Konturschwerpunkt | M = cv2.moments(cnt) cx = int(M['m10']/M['m00']) cy = int(M['m01']/M['m00']) |
M['m00']Ist der Bereich der Kontur |
Zeichne einen Kreis | cv2.circle(img,(cx,cy), 10, (0,0,255), -1) | 半径10ドットの赤いZeichne einen Kreis |
Schreiben wir "test.py" wie folgt um. Erkennt den Schwerpunkt der Markierung (Loch) im Bereich von 200 x 200 oben links und oben rechts im Bild und transformiert ihn so, dass er mit der Position des Referenzbilds übereinstimmt.
import numpy as np
import cv2
img = cv2.imread('C:/xx Beispielbild xx.jpg')
frmX,toX = 0,200 #Markierungsbereich (Löcher)
frmY,toY = 0,200 #Markierungsbereich (Löcher)
def searchMark(img, left): #Funktion, um eine Markierung (Loch) links zu finden==1 ist übrig
if left==1: #Suchen Sie die Markierung (Loch) links
mark = img[frmY:toY, frmX:toX]
else: #Finde die Markierung (Loch) rechts
mark = img[frmY:toY, img.shape[1]-toX:img.shape[1]-frmX]
gray = cv2.cvtColor(mark, cv2.COLOR_BGR2GRAY) #Einfarbig
ret, bin = cv2.threshold(gray, 127, 255, 0) #Binarisierung
cv2.imshow('out',bin) #Zeigen Sie den Bereich der Markierungen (Löcher) an.
cv2.waitKey(1000) #1 Sekunde Stopp
contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #Extraktion der Kontur
ax = ay = sum = 0. #Akkumulation des gesamten Schwerpunkts
for cnt in contours: #Ich suche den ganzen Schwerpunkt
M = cv2.moments(cnt)
ax += M['m10']
ay += M['m01']
sum += cv2.contourArea(cnt)
if left==1:
cx = ax/sum+frmX
cy = ay/sum+frmY
else:
cx = ax/sum + img.shape[1]-toX
cy = ay/sum + frmY
cv2.circle(img,(int(cx),int(cy)), 10, (0,0,255), -1) #Zeichnen Sie einen roten Kreis im Schwerpunkt
print cx,cy #Zeigen Sie den berechneten Schwerpunkt an
return cx,cy #Funktionsrückgabewert
#Affin-Konvertierungstest
cx0,cy0 = searchMark(img,1) #Schwerpunkt (Referenz) der Markierung (Loch) oben links
dx0,dy0 = searchMark(img,0) #Schwerpunkt (Referenz) der Markierung (Loch) oben rechts
cx1,cy1 = cx0,cy0
dx1,dy1 = dx0,dy0+10 #Angenommen, die Markierung (Loch) oben rechts ist um 10 Punkte nach unten verschoben.
cv2.circle(img,(int(dx1),int(dy1)), 10, (255,0,0), -1) #Zeichnen Sie am verschobenen Punkt einen blauen Kreis
pts2 = np.float32([[cx0,cy0],[dx0,dy0],[cx0-(dy0-cy0),cy0+(dx0-cx0)]])
pts1 = np.float32([[cx1,cy1],[dx1,dy1],[cx1-(dy1-cy1),cy1+(dx1-cx1)]])
height,width,ch = img.shape
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(width,height))
cv2.imshow('Title',img) #Zeigen Sie das Bild vor der Konvertierung an
cv2.waitKey(5000) #5 Sekunden Anzeige
cv2.imshow('Title',dst) #Zeigen Sie das konvertierte Bild an
cv2.waitKey(5000) #5 Sekunden Anzeige
Artikel | Anwendungsbeispiel | Erläuterung |
---|---|---|
Funktionsdefinition | def searchMark(img, left): | Das Innere der Funktion wird um einen Schritt abgesenkt. return cx,Kann mehrere Werte wie cy zurückgeben |
If-Anweisung | if left==1: else: | If-Anweisungの中は、一段下げる。 |
Für Schleife | for cnt in contours: | Führen Sie den gesamten Inhalt von Konturen aus. Das Innere von For wird um einen Schritt abgesenkt. |
Konturbereich | cv2.contourArea(cnt) | M['m00']Gleicher Wert wie |
Affin-Umwandlungskoeffizient | M = cv2.getAffineTransform(pts1,pts2) | M ist ein Umrechnungskoeffizient, bei dem 3 Punkte pts1 pts2 entsprechen |
Affin-Konvertierung | dst = cv2.warpAffine(img,M,(width,height)) | Bild img konvertieren, um Bild dst zu erstellen |
Bei der Ausführung wird das Bild so konvertiert, dass der absichtlich verschobene blaue Kreis den ursprünglichen roten Kreis überlappt. Damit ist der Markierungs- (Loch-) Erkennungs- und Konvertierungsprozess abgeschlossen.
Nachdem die grundlegende Verarbeitung abgeschlossen ist, verwenden wir sie wie folgt. Selbst wenn sich Hunderte von Bildern im Ordner befinden, können Sie diese problemlos konvertieren. Dieses Tool heißt "peascan.py". (Abkürzung für Position Error Correction After SCAN)
Wie benutzt man | "Peascan" der Ordner mit den Bildern.Durch Ziehen auf das Symbol "py" wird ein Ordner mit dem Namen "out" an derselben Stelle wie das Bild erstellt und das Korrekturergebnis mit demselben Bildnamen versehen. |
---|
Ausrichtungsmarkierungsbereich (Loch) frmX, toX =, frmY, toY = Bitte passen Sie die Zahlen danach entsprechend dem tatsächlichen Bild an.
peascan.py
import numpy as np
import cv2
import sys #Holen Sie sich argv
import os #Dateivorgang
argv = sys.argv #Rufen Sie eine Liste der Befehlszeilenargumente ab
argc = len(argv) #Anzahl der Argumente
if argc == 2: #Überprüfen Sie, ob es sich um einen Ordner handelt
if os.path.isdir(argv[1]) != True: #Wenn nicht ein Ordner
argc = -1 #Machen Sie einen Fehler
if argc != 2: #Verwendung anzeigen
print 'Usage: Drag Image folder onto this icon.'
key = raw_input('Hit Enter')
quit() #Ende
#Bereich zur Überprüfung der Ausrichtungsmarkierung (Loch) ★ Passen Sie die Einstellungen entsprechend an ★
frmX,toX = 10,200 #10 von der horizontalen Kante-200 Punkte (symmetrisch)
frmY,toY = 10,200 #10 von oben-200 Punkte
def searchMark(img, left): #Funktion, um eine Markierung (Loch) links zu finden==1 ist übrig
if left==1: #Suchen Sie die Markierung (Loch) links
mark = img[frmY:toY, frmX:toX]
else: #Finde die Markierung (Loch) rechts
mark = img[frmY:toY, img.shape[1]-toX:img.shape[1]-frmX]
gray = cv2.cvtColor(mark, cv2.COLOR_BGR2GRAY) #Einfarbig
ret, bin = cv2.threshold(gray, 127, 255, 0) #Binarisierung
cv2.imshow('out',bin) #Zeigen Sie den Bereich der Markierungen (Löcher) an.
cv2.waitKey(1000) #1 Sekunde Stopp
contours, hierarchy = cv2.findContours(bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) #Extraktion der Kontur
ax = ay = sum = 0. #Akkumulation des gesamten Schwerpunkts
for cnt in contours: #Ich suche den ganzen Schwerpunkt
M = cv2.moments(cnt)
ax += M['m10']
ay += M['m01']
sum += cv2.contourArea(cnt)
if left==1:
cx = ax/sum+frmX
cy = ay/sum+frmY
else:
cx = ax/sum + img.shape[1]-toX
cy = ay/sum + frmY
cv2.circle(img,(int(cx),int(cy)), 10, (0,0,255), -1) #Zeichnen Sie einen roten Kreis im Schwerpunkt
print cx,cy #Zeigen Sie den berechneten Schwerpunkt an
return cx,cy #Funktionsrückgabewert
#Hauptschleife
inpFolder = argv[1] #Bildordner eingeben
parent = os.path.dirname(argv[1])
outFolder = os.path.join(parent,'out') #Bildordner ausgeben
if os.path.exists(outFolder) != True: #Wenn es nicht existiert
os.mkdir(outFolder) #Ausgabeordner erstellen
files = [f for f in os.listdir(inpFolder)] #Bild eingeben
files.sort(key=os.path.basename) #Nach Dateinamen sortieren
cx0 = -1
for fn in files:
img = cv2.imread(os.path.join(inpFolder,fn))
if img is None: #Ich konnte es nicht lesen, also weiter
continue
if cx0 == -1: #Erinnern Sie sich an das erste Bild, wie es ist
cx0,cy0=searchMark(img,1)
dx0,dy0=searchMark(img,0)
cv2.imwrite(os.path.join(outFolder,fn), img)
else: #Das zweite und die nachfolgenden Bilder werden in Affin konvertiert, um mit dem ersten Bild übereinzustimmen.
cx1,cy1=searchMark(img,1)
dx1,dy1=searchMark(img,0)
pts2 = np.float32([[cx0,cy0],[dx0,dy0],[cx0-(dy0-cy0),cy0+(dx0-cx0)]])
pts1 = np.float32([[cx1,cy1],[dx1,dy1],[cx1-(dy1-cy1),cy1+(dx1-cx1)]])
height,width,ch = img.shape
M = cv2.getAffineTransform(pts1,pts2)
dst = cv2.warpAffine(img,M,(width,height))
cv2.imwrite(os.path.join(outFolder,fn), dst) #Bild schreiben
cv2.imshow('Title',dst) #Letztes Bild anzeigen
cv2.waitKey(5000) #5 Sekunden Anzeige
Artikel | Anwendungsbeispiel | Erläuterung |
---|---|---|
Befehlsargumente | import sys argv = sys.argv |
Fügen Sie Befehlszeilenargumente in ein Zeichenarray ein |
Dateivorgang | import os | |
Anzahl der Arrays | argc = len(argv) | argc ist die Anzahl der Inhalte im Array argv |
Ordnerurteil | os.path.isdir(argv[1]) | argv[1]True if ist der Pfad des Ordners |
Tasteneingabe | key = raw_input('Hit Enter') | Geben Sie ein, um eine Zeichenfolge in den Schlüssel einzugeben |
Ende | quit() | プログラムをEndeする |
Übergeordneter Ordner | os.path.dirname(argv[1]) | Pfad argv[1]Vom Ende bis zum zweiten herausnehmen |
Datei/Ordnernamen | os.path.basename(argv[1]) | Pfad argv[1]Extrahieren Sie den Nachnamen von |
Kombinieren Sie Ordner und Dateien | os.path.join(parent,'out') | Dateiname im übergeordneten Ordnerpfad'out'Verbinden |
Existenzprüfung | os.path.exists(outFolder) | True, wenn outFolder vorhanden ist |
Ordner erstellen | os.mkdir(outFolder) | Ordner outFolder erstellen |
Dateilistenerstellung | files = [f for f in os.listdir(inpFolder)] | Alle Dateinamen im Ordner inpFolder befinden sich in den Array-Dateien |
Nach Dateinamen sortieren | files.sort(key=os.path.basename) | 配列 files をNach Dateinamen sortieren |
Im Fehlerfall | if img is None: | Verwendung ist oder ist nicht im Vergleich zu Keine |
Zur Unterbrechung | continue | Unterbrechen Sie die Verarbeitung in der For-Anweisung und fahren Sie mit dem nächsten fort |
Bild speichern | cv2.imwrite(os.path.join(outFolder,fn), img) | Speichern Sie das Bild img als fn in outFolder |
――Das diesmal erstellte Werkzeug berechnet nur den Schwerpunkt der Markierungen oben links und oben rechts im Bild, sodass die Form völlig irrelevant ist. Selbst wenn es sich um eine Kreuzmarkierung wie eine Libelle handelt, kann sie zur Ausrichtung verwendet werden, wenn alle Bilder dieselbe Form haben.
Die meisten OpenCV-Informationen im Internet stammen von OpenCV 3, und in OpenCV 2.4 kann ein Fehler auftreten.
Artikel | OpenCV 3 | OpenCV 2.4 |
---|---|---|
Beschriftung | nLabels, labelImage = cv2.connectedComponents(bin) | verbundene Komponenten können nicht verwendet werden |
Konturextraktion | image, contours, hierarchy = cv2.findContours( thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) | contours, hierarchy = cv2.findContours( bin, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) 2 Ausgänge |
Zeichnung | img = cv2.circle(img, center, radius,(0,255,0),2) | cv2.circle(img, center, radius, (0,255,0),2) 出力はなし、imgに直接Zeichnungされる |
Recommended Posts