[PYTHON] Winkelkorrektur (Projektionskonvertierung) der Lizenz mit OpenCV - Binarisierungsschwelle automatisch ermitteln-

Motivation

Überblick

Unterscheidungspunkte zu anderen ähnlichen Artikeln

Angenommener Leser

Arbeitsablauf

  1. ** Umweltbau **
  2. ** Binarisierung ** [^ Binarisierung]
  3. ** Konturextraktion **
  4. ** Projektionskonvertierung **

Umgebung

Ich benutze Pipenv.

Pipenv

brew install pipenv

Beziehungspaket

pipenv install numpy matplotlib opencv-contrib-python pyocr
pipenv install jupyterlab --dev

Verzeichnisaufbau

Drei Bilder mit der folgenden Konfiguration

--nanaco.jpeg (auf einfachste Weise aufgenommen) --nanaco_skew.jpeg (so aufgenommen, dass die Form der Karte aus einem Winkel verzerrt ist) --nanaco_in_hand.jpeg (aufgenommen, während Sie es auf einem weißen Hintergrund in der Hand halten)

Ich werde versuchen. Der Quellcode verwendet das Jupyter-Notizbuch "card.ipynb".

.
├── Pipfile
├── Pipfile.lock
├── images
│   ├── nanaco.jpeg
│   ├── nanaco_in_hand.jpeg
│   └── nanaco_skew.jpeg
└── notebooks
    └── card.ipynb

Versuchen Sie, ein Bild der Karte in OpenCV anzuzeigen

  1. Starten Sie Jupyter Lab
pipenv run jupyter lab
  1. Erstellen Sie notebooks / card.ipynb und führen Sie Folgendes in der Zelle aus (führen Sie alle anderen Skripte in der Zelle aus).
%matplotlib inline
import cv2
import matplotlib.pyplot as plt
img = cv2.imread('../images/nanaco_skew.jpeg')
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

image.png

Ich bin neugierig auf die Skala von "matplotlib", aber es ist mir egal, aber die Koordinaten sind leicht zu verstehen, also werde ich so weitermachen, wie es diesmal ist.

Binarisierung

Graustufen

#Graustufen
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
plt.imshow(gray_img)
plt.gray()

Bestimmen des Schwellenwerts für die Binärisierung

In vielen Tutorials und Artikeln wurde der Schwellenwert für die Binärisierung auf einen Wert von etwa "200" fest codiert und so behandelt, als ob er manuell bestimmt worden wäre. In diesem Artikel habe ich ** Logik aufgenommen, die dynamisch (automatisch) den Schwellenwert bestimmt **

import numpy as np
#Nanaco ist 0.Über 2 sieht gut aus. Wenn Sie eine Lizenz haben, müssen Sie diese möglicherweise erneut einstellen
card_luminance_percentage = 0.2

# TODO:Leistungsausblick
def luminance_threshold(gray_img):
    """
Wert in Graustufen(Helligkeit genannt)Aber`x`Die Anzahl der oben genannten Punkte beträgt 20%Berechnen Sie das maximale x, das überschreitet
Jedoch,`100 <= x <= 200`Zu
    """
    number_threshold = gray_img.size * card_luminance_percentage
    flat = gray_img.flatten()
    # 200 -> 100 
    for diff_luminance in range(100):
        if np.count_nonzero(flat > 200 - diff_luminance) >= number_threshold:
            return 200 - diff_luminance
    return 100

threshold = luminance_threshold(gray_img)
print(f'threshold: {threshold}')

Die Schwellenwerte für die drei Bildtypen wurden diesmal wie folgt berechnet.

Zum Beispiel funktionierte es in "nanaco_skew.jpeg " nicht, wenn der Schwellenwert (üblicherweise) "200" war, wahrscheinlich aufgrund der Menge des reflektierten Lichts. Wenn Sie "138" verwenden, das aus dem obigen Quellcode berechnet wurde, können Sie später den Umriss der Karte erhalten.

nanaco.jpeg nanaco_skew.jpeg nanaco_in_hand.jpeg
Binarisierungsschwelle 200 138 199
Bild nanaco.jpeg nanaco_skew.jpeg nanaco_in_hand.jpeg

Binarisierung


_, binarized = cv2.threshold(gray_img, threshold, 255, cv2.THRESH_BINARY)
plt.imshow(cv2.cvtColor(binarized, cv2.COLOR_BGR2RGB))

image.png

Konturextraktion

contours, _ = cv2.findContours(binarized, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

#Wählen Sie die mit der größten Fläche aus
card_cnt = max(contours, key=cv2.contourArea)

#Zeichnen Sie Konturen auf das Bild
line_color = (0, 255, 0)
thickness = 30
cv2.drawContours(img, [card_cnt], -1, line_color, thickness)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))

image.png

Projektionstransformation

Die Projektionskonvertierung (Winkelkorrektur) wird basierend auf den oben erfassten Konturinformationen durchgeführt.

#Ungefähre Kontur mit konvex
#Fester Wert von 0 für die Gesamtlänge der Kontur.Das Multiplizieren eines Koeffizienten von 1 reicht aus
#Es scheint, dass die Einstellung des Koeffizienten unter der Voraussetzung, dass die Karte bis zu einem gewissen Grad ordnungsgemäß kopiert wird, fast unnötig ist.(Kann für die OCR-Anpassung erforderlich sein)
epsilon = 0.1 * cv2.arcLength(card_cnt, True)
approx = cv2.approxPolyDP(card_cnt, epsilon, True)

#Kartenbreite(Da die Karte im Bild vertikal ist, werden Breite und Höhe während der Projektionskonvertierung umgekehrt.)
card_img_width = 2400 #Angemessener Wert
card_img_height = round(card_img_width * (5.4 / 8.56)) #Lizenzration(=Nanaco-Verhältnis)Berechnet durch Teilen durch

src = np.float32(list(map(lambda x: x[0], approx)))
dst = np.float32([[0,0],[0,card_img_width],[card_img_height,card_img_width],[card_img_height,0]])

projectMatrix = cv2.getPerspectiveTransform(src, dst)

#Da die Zeile früher überschrieben wurde, holen Sie sich das Bild erneut
img = cv2.imread('../images/nanaco_skew.jpeg')
transformed = cv2.warpPerspective(img, projectMatrix, (card_img_height, card_img_width))
plt.imshow(cv2.cvtColor(transformed, cv2.COLOR_BGR2RGB))

image.png

**erledigt! !! ** Die schrägen Buchstaben sind jetzt gerade!

Bonus

Danach denke ich darüber nach, den Inhalt mit OCR unter Verwendung einer tatsächlichen Lizenz zu lesen, aber ich habe auch ein wenig mit dem aktuellen Nanaco versucht. Obwohl es notwendig ist, den zu lesenden Teil einzuschränken, ist dies grob getan.

Unter Verwendung des Bildes von "nanaco_in_hand.jpeg " habe ich OCR auf das zuletzt erhaltene Bild angewendet, wobei "pyocr" für das gesamte Bild verwendet wurde. Sie können dies erreichen, indem Sie dasselbe Skript wie oben für nanaco_in_hand.jpeg ausführen (leicht diagonal ...) image.png

Ich habe versucht, dieses Bild mit "pyocr + tesseract" gemäß dem Tutorial in Text umzuwandeln. [^ ocr]

Ergebnis ist ...

Innerhalb dieses Plans zur Verwendung der Nanaco-Karte
Weitere Informationen zur Verwendung der Kieferkarte finden Sie in der Mitgliedschaftsvereinbarung. Fünf
Akos Karte ist ein Mitgliedsshop mit der Nanaco-Markierung auf der rechten Seite. Sie können das elektronische Management und den elektronischen Manager auf der Karte verwenden.
Sie können Ihr Guthaben bestätigen.
Biegen Sie die Karte nicht, geben Sie ihr keinen großen Aufprall und lassen Sie sie nicht bei hohen Temperaturen oder wenn sie magnetisiert ist.
Akos Karte und der elektronische Manager auf der Karte sind nicht einlösbar.
Die maximale Gebühr für Akos Karte beträgt 50.000 Yen.
Die Ako-Karte kann nur von dem Mitglied verwendet werden, das die Mitgliedervereinbarung genehmigt und das Feld für den Namen des Mitgliedsbüros unterschrieben hat.
Das Eigentum an Akos Karte gehört der Aktiengesellschaft Seven Card Service und kann nicht verliehen oder an eine andere Person übergeben werden.

Ist es ein Ort, der schlampig ist, obwohl man es grob macht? Ich werde die Genauigkeit dieses Bereichs mit einer Lizenz verbessern und fortfahren. (Es ist ziemlich interessant, dass "●" als "A" erkannt wird)

[^ Binärisierung]: RGB-Bild mit Informationen zu jedem Punkt (256x256x256) → Konvertiert das Binärbild der Binärinformationen zu jedem Punkt (2 = 1/0). Dies ist ein Prozess, der die Konturextraktion erleichtert. [^ opencv]: opencv-Contrib-Python importiert das Contrib-Modul zusätzlich zu Open-Python. Es scheint, dass "cv2" für "opencv-python" in Ordnung ist. Soweit das offizielle Dokument ersichtlich ist, scheint es jedoch besser zu sein, diese Notation für neue Elemente zu verwenden. (Referenz: https://pypi.org/project/opencv-python/) [^ ocr]: Dieser Artikel war ebenfalls hilfreich! Eine Installation wie tesseract ist erforderlich.

Recommended Posts

Winkelkorrektur (Projektionskonvertierung) der Lizenz mit OpenCV - Binarisierungsschwelle automatisch ermitteln-
Bestimmen Sie die Anzahl der Klassen mithilfe der Starges-Formel
Bestimmen Sie den Schwellenwert mithilfe der P-Tile-Methode in Python