Erstellen eines Markierungsblatts mit Python OpenCV (Tipps zum guten Lesen)

Da ich mich entschlossen habe, bei der Arbeit einen Papierfragebogen zu erstellen, verweise ich hauptsächlich auf diesen Artikel (Erstellen eines einfachen OMR (Mark Sheet Reader) mit Python und OpenCV). Ich habe es gemacht. Ich habe Leerzeilen oft falsch erkannt, daher würde ich mich freuen, wenn Sie sich darauf beziehen könnten.

Ablauf des gesamten Fragebogens

  1. Erstellen Sie einen Fragebogen mit einem in Excel eingebetteten QR-Code Ich habe Informationen in den QR-Code eingefügt und eingebettet, um die Seitenzahl und die Person des Fragebogens zu identifizieren

  2. Drucken und verteilen

  3. Scannen Sie den gesammelten Fragebogen und wechseln Sie von PDF zu JPG Ich habe es auf einer kostenlosen Conversion-Site im Internet richtig konvertiert

  4. Lesen Sie die Umfrageergebnisse aus der konvertierten JPG-Datei

Umgebung

1. Fragebogen erstellen

2. Scannen

3. Markieren Sie das Lesen des Blattes

Punkt

1. Punkte beim Erstellen eines Fragebogens

2. Punkte beim Scannen

3. Punkte beim Lesen des Markenblatts

Einzelheiten

1. Fragebogen erstellen

1. Erstellen Sie einen QR-Code

Da es diesmal mehrere Fragebögen gibt, haben wir beschlossen, den QR-Code in das Fragenblatt einzubetten und die Antwort zusammen mit den Informationen beim Lesen in CSV zu erfassen, um festzustellen, welche Frage für welche Frage gilt und wer das Fragenblatt geschrieben hat. tat.

--Referenz: QR-Code-Bild mit Python, Pillow, qrcode erstellen und speichern

def makeQr(qrMessage, fileName='result.png', filePath='resultQrCode/'):
    """Erstellen Sie einen QR-Code mit dem Argument qrMessage und speichern Sie ihn in resultQrCode
    Args:
        qrMessage (str):QR-Code zu machen
        fileName (str, optional):Name der Ausgabedatei. Defaults to 'result.png'.
        filePath (str, optional):Ausgabedateipfad * Am Ende der Liste "/」. Defaults to 'resultQrCode/'.
    """
    import qrcode
    import os

    img = qrcode.make(qrMessage)
    if not os.path.isdir(filePath):
        os.makedirs(filePath)
    if not(filePath[-1] == '\\' or filePath[-1] == '/'):
        filePath = filePath + '\\'
    
    img.save(filePath + fileName)
    print('File out:' + filePath + fileName)

if __name__ == '__main__':
    import re
    import sys
    
    args = sys.argv
    if 1 < len(args):
        if re.findall('[/:*?"<>|]', args[1]):
            print('[Error]Verbotener Charakter "/:*?"<>|」')
        elif 2 == len(args):
            makeQr(args[1])
        elif re.findall('[:*?"<>|]', args[2]):
            print('[Error]Verbotene Zeichen im Dateinamen ":*?"<>|」')
        elif 3 == len(args):
            makeQr(args[1],args[2])
        elif re.findall('[*?"<>|]', args[3]):
            print('[Error]Verbotene Zeichen im Ordnernamen "*?"<>|」') 
        elif 4 == len(args):
            makeQr(args[1],args[2],args[3])
        else:
            qrMessage = args[1]
            for qrMessageList in args[4:]:
                qrMessage = qrMessage + '\r\n' + qrMessageList
            makeQr(qrMessage,args[2],args[3])
    else:
        print('error: args is one')
        print('usage1: makeQr.exe [QR_Text]')
        print('usage2: makeQr.exe [QR_Text] [Output_FileName]')
        print('usage3: makeQr.exe [QR_Text] [Output_FileName] [Output_FilePath]')
        print('usage4: makeQr.exe [QR_Text] [Output_FileName] [Output_FilePath] [QR_Text_Line2...]')

Verwenden Sie diese Option, damit jeder sie später verwenden kann. Ich habe es mit py2exe zu einer Exe gemacht. (Pyinstaller ist in Ordnung, aber es war schwer, also habe ich hier py2exe gewählt.) --Referenz: Verwenden von py2exe mit Python 3.5 --3.7

2. Vorbereitung der Marker

Schneiden Sie den Bereich des Markenblatts aus, damit die Frage und das Markenblatt kombiniert werden können. Bereiten Sie charakteristische Schwarzweißbilder an den vier Ecken des Ausschnittbereichs vor. Da diesmal der QR-Code verwendet wird, können die im unten gezeigten QR-Code verwendeten Markierungen (im roten Rahmen eingeschlossen) nicht verwendet werden. Da ich Excel verwende, habe ich beschlossen, dass ★ als Text in einer Figur (automatische Form) eine Kastanie ist, also habe ich ★ als Figur vorbereitet. Da der Marker ★ als Bilddatei an das Analyseprogramm übergeben werden muss, habe ich die Excel-Form mit Farbe usw. eingefügt und gespeichert. Da Größe und Ränder mit der automatischen Form übereinstimmen müssen, wird empfohlen, vor dem Einfügen Höhe und Breite zu minimieren.

3. Vorbereitung der Marke

Bereiten Sie Fragen und Noten in Excel vor. Die Punkte sind wie folgt.

4. Passen Sie die Größe des Markers an die Papierbreite an und fügen Sie den Marker ein

Da es sich um Excel handelt, wird der Druck vergrößert oder verkleinert, und die Größe des als Bild gespeicherten Markers und des Markers zum Zeitpunkt des Drucks sind unterschiedlich. Möglicherweise wird er nicht gut erkannt. Daher muss für jedes Blatt die Vergrößerungsvergrößerung ermittelt werden (siehe). -Referenz ExecuteExcel4Macro "Page.Setup ()"

Public Function getPrintZoomPer(sheetName As String) As Integer
    Worksheets(sheetName).Activate
    ExecuteExcel4Macro "Page.Setup(,,,,,,,,,,,,{1,#N/A})"
    ExecuteExcel4Macro "Page.Setup(,,,,,,,,,,,,{#N/A,#N/A})"
    getPrintZoomPer = ExecuteExcel4Macro("Get.Document(62)")
End Function

Platzieren Sie die Markierungsquelle auf einem Blatt und fügen Sie die Markierungsquelle an den vier Ecken des Blattes ein, das Sie anhängen möchten. Multiplizieren Sie beim Einfügen des Markers die erfasste Vergrößerung mit der inversen Zahl. Da die Anzahl der Fragen und Optionen variabel ist, habe ich es mit vba gemacht, ohne es zu reparieren.

Public Sub insertMaker(sheetName As String, pasteCellStr As String, _
         printZoomPer As Integer)
    ' sheetName:Blattname des Einfügeziels
    ' paseteCellStr:Zellenzeichenfolge zum Einfügen in Beispiel: A4, B1 usw.
    Dim srcShape As shape
    Set srcShape = Worksheets("sheet1").Shapes("marker") 
    ' sheet1:Blattname mit dem Marker Form der Einfügequelle
    ' marker:Fügen Sie den Quellmarker Shapenamae-Namen ein
    srcShape.Copy
    With Worksheets(sheetName).Pictures.Paste
        .Top = Worksheets(sheetName).Range(pasteCellStr).Top
        .Left = Worksheets(sheetName).Range(pasteCellStr).Left
        .Name = "marker"
        .Width = .Width * 100 / printZoomPer
    End With
End Sub

5. Geben Sie den QR-Code ein

Erstellen Sie, indem Sie im QR-Code "Fragetyp + Fragebogenseitenzahl + Zweig + Personennummer + Anzahl Auswahlmöglichkeiten + Anzahl Fragen" eingeben. Rufen Sie die in "1." erstellte exe-Datei aus dem Excel-Makro mit WScript.Shell auf.

Public Function makeQr(ByVal QrMessage As String, ByVal fileName As String) As String
    Dim WSH, wExec, sCmd As String
    Set WSH = CreateObject("WScript.Shell")
    
    sCmd = ThisWorkbook.Path & "makeQR.exe " & QrMessage & " " & fileName & " " & _
           ThisWorkbook.Path & "resultQrCode"
    Set wExec = WSH.Exec("%ComSpec% /c " & sCmd)
    
    Do While wExec.Status = 0
        DoEvents
    Loop
    makeQr = wExec.StdOut.readall

    Set wExec = Nothing
    Set WSH = Nothing

End Function

Nachdem Sie verschiedene Dinge getan haben, ist das Ergebnis wie folgt Enquete.PNG

Ich werde drucken und verteilen, was ich so gemacht habe.

2. Scannen

Nach dem Ausfüllen des Fragebogens wird ein Scan durchgeführt. Da es auf der Seite zum Lesen des Markierungsblatts eine Auflösungseinstellung gibt, habe ich diese diesmal auf 200 dpi festgelegt. (Da das Multifunktionsgerät bei der Arbeit nicht direkt im JPG-Format gespeichert werden konnte, wurde es außerdem von Als PDF und PDF speichern => JPG-Konvertierungssite konvertiert. Außerdem verwende ich openCV auf der Seite zum Lesen des Markierungsblatts. Beachten Sie jedoch, dass im Dateinamen keine Zeichen in voller Breite verwendet werden konnten.

3. Markieren Sie das Lesen des Blattes

1. Lesen Sie den QR-Code

Legen Sie die aggregierten JPG-Dateien in einem Ordner ab, lesen Sie den QR-Code und geben Sie ihn als Argument zurück.

def qrCodeToStr(filePath):
"""Lesen Sie die Zeichenfolge aus dem QR-Code
Args:
    filePath (String):Pfad der Bilddatei mit QR-Code
Returns:
    String:Ergebnis des Lesens des QR-Codes(Fehlgeschlagener nullString)
"""
import cv2

img = cv2.imread(filePath, cv2.IMREAD_GRAYSCALE)
#QR-Code-Decodierung
qr = cv2.QRCodeDetector()
data,_,_ = qr.detectAndDecode(img)

if data == '':
    print('[ERROR]' + filePath + 'Der QR-Code von konnte nicht gefunden werden')
else:
    print(data)
return data

2. Markieren Sie das Lesen des Blattes

Dies ist fast dasselbe wie in diesem Artikel (Erstellen eines einfachen OMR (Mark Sheet Reader) mit Python und OpenCV). Die Änderungen sind wie folgt.

--Looping des Schwellenwerts vom höchsten in der for-Anweisung, um einen funktionierenden Wert zu finden ――Dieses Mal haben wir unbeantwortete Antworten akzeptiert und nicht mehrere Antworten akzeptiert. Daher haben wir einmal mit dem 4-fachen oder mehr des Durchschnittswerts extrahiert und bei mehreren Antworten die Hälfte des Maximalwerts. Das ist alles.

def changeMarkToStr(scanFilePath, n_col, n_row, message):
    """Lesen Sie das Markierungsblatt und setzen Sie das Ergebnis auf False,Gibt als echtes zweidimensionales Array zurück
    Args:
        scanFilePath (String):Pfad der JPEG-Datei einschließlich Markierungsblattformat
        n_col (int):Anzahl der Auswahlmöglichkeiten(Anzahl der Spalten)
        n_row (int):Anzahl der Fragen(Anzahl der Zeilen)
    Returns:
        list:Ergebnis des Lesens des Markenblatts Falsch,Echtes zweidimensionales Array
    """
    ### n_col = 6 #Anzahl der Markierungen pro Zeile
    ### n_row = 9 #Anzahl der Markierungslinien
    import numpy as np
    import cv2

    ###Markereinstellungen
    marker_dpi = 120 #Bildschirmauflösung(Markergröße)
    scan_dpi = 200 #Auflösung des gescannten Bildes

    #Graustufen(mode = 0)Lesen Sie die Datei mit
    marker=cv2.imread('img/setting/marker.jpg',0) 

    #Holen Sie sich die Größe des Markers
    w, h = marker.shape[::-1]

    #Ändern Sie die Größe des Markers
    marker = cv2.resize(marker, (int(h*scan_dpi/marker_dpi), int(w*scan_dpi/marker_dpi)))

    ###Gescanntes Bild laden
    img = cv2.imread(scanFilePath,0)

    res = cv2.matchTemplate(img, marker, cv2.TM_CCOEFF_NORMED)

    ##Wiederholen Sie die Extraktion an 3 Stellen des Herstellers. Die Bedingungen für die Extraktion sind wie folgt
    margin_top = 1 #Anzahl der oberen Randlinien
    margin_bottom = 0 #Anzahl der unteren Randlinien
 
    for threshold in [0.8, 0.75, 0.7, 0.65, 0.6]:
    
        loc = np.where( res >= threshold)
        mark_area={}
        try:
            mark_area['top_x']= sorted(loc[1])[0]
            mark_area['top_y']= sorted(loc[0])[0]
            mark_area['bottom_x']= sorted(loc[1])[-1]
            mark_area['bottom_y']= sorted(loc[0])[-1]

            topX_error = sorted(loc[1])[1] - sorted(loc[1])[0]
            bottomX_error = sorted(loc[1])[-1] - sorted(loc[1])[-2]
            topY_error = sorted(loc[0])[1] - sorted(loc[0])[0]
            bottomY_error = sorted(loc[0])[-1] - sorted(loc[0])[-2]
            img = img[mark_area['top_y']:mark_area['bottom_y'],mark_area['top_x']:mark_area['bottom_x']]

            if (topX_error < 5 and bottomX_error < 5 and topY_error < 5 and bottomY_error < 5):    
                break
        except:
            continue

    #Markieren Sie als Nächstes das ausgeschnittene Bild, um die nachfolgende Verarbeitung zu erleichtern.
    #Ändern Sie die Größe auf eine Größe, die ein ganzzahliges Vielfaches der Anzahl der Spalten und Zeilen ist.
    #Hier beträgt die Anzahl der Spalten und Zeilen das 100-fache.
    #Berücksichtigen Sie beim Zählen der Anzahl der Zeilen den Rand vom Markierungsbereich bis zur Markierung.

    n_row = n_row + margin_top + margin_bottom
    img = cv2.resize(img, (n_col*100, n_row*100))

    ###Verwischen
    img = cv2.GaussianBlur(img,(5,5),0)

    ###Binar mit 50 als Schwelle
    res, img = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

    ###Schwarz-Weiß-Inversion
    img = 255 - img
    cv2.imwrite('img/res.png',img)

    #Markieren Sie die Erkennung

    ###Bereiten Sie ein Array vor, um das Ergebnis zu platzieren
    result = []
    
    ###Zeilenweise Verarbeitung(Prozess durch Ausschließen von Randlinien)
    for row in range(margin_top, n_row - margin_bottom):
        
        ###Schneiden Sie nur die zu verarbeitende Zeile aus
        tmp_img = img [row*100:(row+1)*100,]
        area_sum = [] #Ein Array, um den Gesamtwert zu setzen

        ###Bearbeitung jeder Marke
        for col in range(n_col):

            ###Berechnen Sie mit NumPy den Gesamtwert der Bilder in jedem Markierungsbereich
            area_sum.append(np.sum(tmp_img[:,col*100:(col+1)*100]))

        ###Beurteilen Sie, ob der Gesamtwert des Bildbereichs das 4-fache oder mehr des Durchschnittswerts beträgt
        ###Wenn Sie die Marke tatsächlich nähen, 4.9 bis 6 Mal gab es 3 Mal, weil es überhaupt nicht gemalt wurde
        ###Wenn es das Dreifache des Medianwerts ist, kann es nicht verwendet werden, wenn 0 fortgesetzt wird.
        ressss = (area_sum > np.average(area_sum) * 4)
        #Da es unter den oben genannten Bedingungen einfach ist, mehrere Bedingungen zu extrahieren, extrahieren Sie mehr als die Hälfte des Maximalwerts
        if np.sum(ressss == True) > 1:
            ressss = (area_sum > np.max(area_sum) * 0.5)
        result.append(ressss)

    for x in range(len(result)):
        res = np.where(result[x]==True)[0]+1
        if len(res)>1:
            message.append('multi answer:' + str(res))
        elif len(res)==1:
            message.append(res[0])
        else:
            message.append('None')
    message.insert(0,scanFilePath)
    print(message)
    return message

Es ist eine Skizze, weil es für mein eigenes Memo ist, aber wenn es hilft

Recommended Posts

Erstellen eines Markierungsblatts mit Python OpenCV (Tipps zum guten Lesen)
Erstellen Sie mit Python und OpenCV ein einfaches OMR (Mark Sheet Reader)
Versuchen Sie, eine komprimierte Datei mit Python und zlib zu erstellen
Nehmen Sie Zeitraffer von einer PC-Kamera mit Python, OpenCV auf
[Python] Zugreifen auf und Zuschneiden von Bildpixeln mit OpenCV (für Anfänger)
[TouchDesigner] Tipps für die Anweisung von Python
Erstellen Sie eine gestreifte Illusion mit Gammakorrektur für Python3 und openCV3
Tipps zur Verwendung von Selen und Headless Chrome in einer CUI-Umgebung
Tipps zur Verwendung von Python + Caffe mit TSUBAME
Vorgehensweise zum Erstellen eines mit Python erstellten LineBot
Erstellen Sie eine Webmap mit Python und GDAL
Ich habe versucht, eine CSV-Datei mit Python zu lesen
[Hikari-Python] Kapitel 09-02 Klassen (Erstellen und Instanziieren von Klassen)
Befehle zum Erstellen einer Python3-Umgebung mit virtualenv
Verfahren zum Erstellen einer Python-Isolationsumgebung (venv-Umgebung)
Tipps für eine gute Verwendung von Elastic Search
Hinweise zum Erstellen einer Python-Umgebung durch Anfänger
Lassen Sie uns mit SWIG ein Modul für Python erstellen
Grundeinstellungen für die Verwendung von Python3.8 und pip unter CentOS8
Durchsuchen von Pixiv-Tags und Speichern von Illustrationen mit Python
Erweiterbare Skelette für Vim mit Python, Click und Jinja2
Python-Textlesung für mehrere Zeilen und eine Zeile
Erstellen einer R- und Python Docker-Arbeitsumgebung
Ich habe eine VM erstellt, auf der OpenCV für Python ausgeführt wird
Erstellen Sie ein Diagramm mit der Plot-Schaltfläche und dem Schieberegler
Implementieren eines Generators mit Python> Link> Yield und next ()> Yield
Informationen zum Erstellen und Ändern von benutzerdefinierten Designs für Python IDLE
Laden / Anzeigen und Beschleunigen von GIF mit Python [OpenCV]
Konstruktionsnotiz für eine maschinelle Lernumgebung von Python
Erstellen Sie mit OpenCV und TensorFlow einen Sato Yohei-Diskriminator
OpenCV für Python-Anfänger
Erstellen einer Python-Umgebung auf einem Mac bis zur Verwendung von Jupyter Lab
[Python] Erstellen Sie eine Datums- und Zeitliste für einen bestimmten Zeitraum
[Python] Kapitel 01-03 Über Python (Schreiben und Ausführen eines Programms mit PyCharm)
Probieren Sie die ähnliche Suche von Image Search mit Python SDK [Search] aus.
Ein Hinweis beim Erstellen eines gerichteten Diagramms mit Graphviz in Python
Tipps zum Codieren kurz und einfach in Python zu lesen
Bibliothek zur Angabe eines Nameservers in Python und Dig
Ich habe Chatbot mit LINE Messaging API und Python erstellt
[Python] Verwenden von OpenCV mit Python (Basic)
OpenCV3-Installation für Python3 @macOS
[Python + Selen] Tipps zum Scraping
~ Tipps für Python-Anfänger mit Liebe von Pythonista ③ ~
Verwenden von OpenCV mit Python @Mac
Erstellen einer Docker-Arbeitsumgebung für R und Python 2: Japanische Unterstützung
Erstellen und testen Sie eine CI-Umgebung für mehrere Versionen von Python
Python: Einführung in Flask: Erstellen einer Nummernidentifizierungs-App mit MNIST
Erstellen Sie mit dem Serverless Framework eine lokale Entwicklungsumgebung für Lambda + Python
Pydroid 3 - Ich habe die OpenCV- und TensorFlow-Optionen von IDE für Python 3 (Android) ausprobiert.
Verarbeiten Sie das Ausführungsergebnis von Splunk mit Python und speichern Sie es in einer Datei
Versuchen Sie es mit virtualenv, mit dem eine virtuelle Umgebung von Python erstellt werden kann
entwurzeln: Python / Numpy-basierte Bibliothek zum Lesen und Schreiben von ROOT-Dateien
So erstellen Sie eine Überwachungskamera (Überwachungskamera) mit Opencv und Python
Ein bisschen mehr über Referenzen ~ Verwenden von Python und Java als Beispiele ~
Erstellen Sie einen einfachen geplanten Stapel mit Dockers Python Image und parse-crontab
[Bildverarbeitung] Poo-san ist durch Kantenerkennung mit Python und OpenCV nackt!
Zeichnen Sie eine Aquarellillusion mit Kantenerkennung in Python3 und openCV3
Erstellen und testen Sie mit Docker in wenigen Minuten eine OpenCV- und Python-Umgebung