Depuis que j'ai décidé de faire un questionnaire papier au travail, je me réfère principalement à cet article (Making a simple OMR (mark sheet reader) with Python and OpenCV) Je l'ai fait. J'ai souvent mal reconnu les lignes vierges, alors j'apprécierais que vous puissiez vous y référer.
Créez un questionnaire avec un code QR intégré dans Excel J'ai mis des informations dans le code QR et je les ai intégrées pour identifier le numéro de page et l'individu du questionnaire
Imprimer et distribuer
Scannez le questionnaire collecté et passez du PDF au JPG Je l'ai converti correctement sur un site de conversion gratuit sur le net
Lisez les résultats de l'enquête à partir du fichier JPG converti
Comme il y a plusieurs feuilles de questions cette fois, afin de déterminer quelle question est pour quelle question et qui a écrit la feuille de questions, nous avons décidé d'intégrer le code QR dans la feuille de questions et de capturer la réponse en CSV avec les informations lors de la lecture. fait.
--Référence: Générer et enregistrer l'image de code QR avec Python, Pillow, qrcode
def makeQr(qrMessage, fileName='result.png', filePath='resultQrCode/'):
"""Créez un code QR avec l'argument qrMessage et enregistrez-le dans resultQrCode
Args:
qrMessage (str):Code QR à créer
fileName (str, optional):Nom du fichier de sortie. Defaults to 'result.png'.
filePath (str, optional):Chemin du fichier de sortie * À la fin de la 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]Caractère interdit "/:*?"<>|」')
elif 2 == len(args):
makeQr(args[1])
elif re.findall('[:*?"<>|]', args[2]):
print('[Error]Caractères interdits dans le nom de fichier ":*?"<>|」')
elif 3 == len(args):
makeQr(args[1],args[2])
elif re.findall('[*?"<>|]', args[3]):
print('[Error]Caractères interdits dans le nom du dossier "*?"<>|」')
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...]')
Utilisez ceci pour que quiconque puisse l'utiliser plus tard. Je l'ai transformé en un exe avec py2exe. (Pyinstaller va bien, mais il était lourd, j'ai donc choisi py2exe ici.) --Référence: Utilisation de py2exe avec python 3.5 --3.7
Découpez la plage de la feuille de notes afin que la question et la feuille de notes puissent être combinées. Préparez des images en noir et blanc caractéristiques aux quatre coins de la zone de découpe. Étant donné que le code QR est utilisé cette fois, les marqueurs (entourés d'un cadre rouge) utilisés dans le code QR de la figure ci-dessous ne peuvent pas être utilisés. De plus, comme j'utilise Excel, j'ai décidé que si je définissais ★ comme texte dans une figure (forme automatique), ce serait un marron, j'ai donc préparé ★ comme une figure. Puisqu'il est nécessaire de transmettre le marqueur ★ en tant que fichier image au programme d'analyse, j'ai collé la forme Excel avec de la peinture, etc. et l'ai enregistrée. Étant donné que la taille et les marges doivent être identiques à celles de la forme automatique, il est recommandé de minimiser la hauteur et la largeur avant de coller.
Préparez des questions et des notes dans Excel. Les points sont les suivants.
Comme il s'agit d'Excel, l'impression est agrandie ou réduite, et la taille du marqueur enregistré en tant qu'image et le marqueur au moment de l'impression sont différents, et il peut ne pas être bien reconnu, il est donc nécessaire d'obtenir (voir) le grossissement d'agrandissement pour chaque feuille. -Référence 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
Placez la source du marqueur sur une feuille et collez la source du marqueur aux quatre coins de la feuille que vous souhaitez attacher. Lorsque vous collez le marqueur, multipliez le grossissement acquis par le nombre inverse. Puisque le nombre de questions et d'options est variable, je l'ai fait avec vba sans le réparer.
Public Sub insertMaker(sheetName As String, pasteCellStr As String, _
printZoomPer As Integer)
' sheetName:Nom de feuille de la destination de collage
' paseteCellStr:Chaîne de caractères de cellule à coller Exemple: A4, B1, etc.
Dim srcShape As shape
Set srcShape = Worksheets("sheet1").Shapes("marker")
' sheet1:Nom de la feuille avec le marqueur Forme de la source de collage
' marker:Coller le nom du Shapenamae du marqueur source
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
Créez en saisissant "type de question + numéro de page du questionnaire + agence + numéro de personne + nombre de choix + nombre de questions" dans le code QR. Appelez le fichier exe créé en "1" à partir de la macro Excel avec WScript.Shell.
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
Après avoir fait diverses choses, le résultat est comme ci-dessous
Je vais imprimer et distribuer ce que j'ai fait comme ça.
Une fois le questionnaire rempli, une analyse sera effectuée. Puisqu'il y a un réglage de résolution sur le côté lecture de la feuille de repères, je l'ai fixé à 200 dpi cette fois. (De plus, comme la machine multifonction au travail ne pouvait pas être enregistrée directement au format jpg, elle a été convertie par Enregistrer au format PDF et PDF => site de conversion JPG. De plus, j'utilise openCV du côté lecture de la feuille de repère, mais veuillez noter que les caractères pleine largeur ne peuvent pas être utilisés dans le nom de fichier.
Placez les fichiers JPG agrégés dans un dossier, lisez le code QR et renvoyez-le en argument.
def qrCodeToStr(filePath):
"""Lire la chaîne de caractères du code QR
Args:
filePath (String):Chemin du fichier image contenant le code QR
Returns:
String:Résultat de la lecture du code QR(Échec de nullString)
"""
import cv2
img = cv2.imread(filePath, cv2.IMREAD_GRAYSCALE)
#Décodage du code QR
qr = cv2.QRCodeDetector()
data,_,_ = qr.detectAndDecode(img)
if data == '':
print('[ERROR]' + filePath + 'Impossible de trouver le code QR de')
else:
print(data)
return data
C'est presque le même que cet article (Créer un simple OMR (lecteur de feuille de marque) avec Python et OpenCV). Les changements sont les suivants.
def changeMarkToStr(scanFilePath, n_col, n_row, message):
"""Lisez la feuille de notes et définissez le résultat sur False,Renvoie comme un véritable tableau à deux dimensions
Args:
scanFilePath (String):Chemin du fichier JPEG, y compris le format de feuille de repère
n_col (int):Nombre de choix(Le nombre de colonnes)
n_row (int):Nombre de questions(Nombre de lignes)
Returns:
list:Résultat de la lecture de la feuille de notes Faux,Vrai tableau bidimensionnel
"""
### n_col = 6 #Nombre de marques par ligne
### n_row = 9 #Nombre de lignes de marque
import numpy as np
import cv2
###Paramètres des marqueurs
marker_dpi = 120 #Résolution d'écran(Taille du marqueur)
scan_dpi = 200 #Résolution d'image numérisée
#niveaux de gris(mode = 0)Lisez le fichier avec
marker=cv2.imread('img/setting/marker.jpg',0)
#Obtenez la taille du marqueur
w, h = marker.shape[::-1]
#Redimensionner le marqueur
marker = cv2.resize(marker, (int(h*scan_dpi/marker_dpi), int(w*scan_dpi/marker_dpi)))
###Charger l'image numérisée
img = cv2.imread(scanFilePath,0)
res = cv2.matchTemplate(img, marker, cv2.TM_CCOEFF_NORMED)
##Répéter l'extraction à partir de 3 points de fabrication Les conditions d'extraction sont les suivantes
margin_top = 1 #Nombre de lignes de marge supérieures
margin_bottom = 0 #Nombre de lignes de marge inférieure
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
#Ensuite, afin de faciliter le traitement ultérieur, marquez l'image découpée.
#Redimensionner à une taille qui est un multiple entier du nombre de colonnes et de lignes.
#Ici, le nombre de colonnes et de lignes est de 100 fois.
#Lorsque vous comptez le nombre de lignes, tenez compte de la marge entre la zone de marque et le marqueur.
n_row = n_row + margin_top + margin_bottom
img = cv2.resize(img, (n_col*100, n_row*100))
###Brouiller
img = cv2.GaussianBlur(img,(5,5),0)
###Binar avec 50 comme seuil
res, img = cv2.threshold(img, 50, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)
###Inversion noir et blanc
img = 255 - img
cv2.imwrite('img/res.png',img)
#Marquer la reconnaissance
###Préparez un tableau pour mettre le résultat
result = []
###Traitement ligne par ligne(Traiter en excluant les lignes de marge)
for row in range(margin_top, n_row - margin_bottom):
###Découpez uniquement la ligne à traiter
tmp_img = img [row*100:(row+1)*100,]
area_sum = [] #Un tableau pour mettre la valeur totale
###Traitement de chaque marque
for col in range(n_col):
###Calculez la valeur totale des images dans chaque zone de marque avec NumPy
area_sum.append(np.sum(tmp_img[:,col*100:(col+1)*100]))
###Jugez si la valeur totale de la zone d'image est 4 fois ou plus de la valeur moyenne
###Si vous cousez réellement la marque, 4.9 à 6 fois, il y en a eu 3 car il n'était pas du tout peint
###Si elle est 3 fois la valeur médiane, elle ne peut pas être utilisée lorsque 0 continue.
ressss = (area_sum > np.average(area_sum) * 4)
#Comme il est facile d'extraire plusieurs conditions dans les conditions ci-dessus, extraire plus de la moitié de la valeur maximale
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
C'est un gribouillage parce que c'est pour mon propre mémo, mais si ça aide
Recommended Posts