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.
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
Drucken und verteilen
Scannen Sie den gesammelten Fragebogen und wechseln Sie von PDF zu JPG Ich habe es auf einer kostenlosen Conversion-Site im Internet richtig konvertiert
Lesen Sie die Umfrageergebnisse aus der konvertierten JPG-Datei
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
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.
Bereiten Sie Fragen und Noten in Excel vor. Die Punkte sind wie folgt.
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
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
Ich werde drucken und verteilen, was ich so gemacht habe.
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.
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
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