[PYTHON] Une histoire qui prend en charge la notation électronique des examens avec reconnaissance d'image

Bienvenue au 23ème jour du Calendrier de l'Avent des nouveaux diplômés de Yuruyuru 2019. Je suis un jeune diplômé, @NamedPython

Aujourd'hui, c'est mon exploit caché ** Reconnaissance d'image avec OpenCV **.

J'avais décidé à l'avance d'écrire sur la reconnaissance d'image, mais il était difficile de trouver quelque chose de nouveau, alors j'ai fait de mon mieux pour l'écrire en classe, mais je ne l'ai proposé nulle part ~~ ** Feuille de réponses Je vais laisser un enregistrement de l'extraction de la zone ** ici: crayon2:

Qu'essayais-tu de faire

J'ai dit que c'était une classe, mais le nom de la classe est ** Application de programmation **, et travaillons en équipe pour résoudre des problèmes grâce au développement de logiciels, impliquant ce que nous apprenons habituellement en classe et les compétences de nos étudiants. est.

Alors, quel est le thème de la résolution de problèmes?

** Facilitez-vous la notation électronique de vos examens **: priez:

C'était ça. En premier lieu, au moment de la notation électronique, c'est assez maintenant et jeune, mais si vous résumez les exigences

C'était comme ça.

équipe

En fait, un an avant ce cours,

--Backend API, web front @NamedPython --iOS @Taillook --Android @ youta1119

Nous avons formé l'équipe la plus solide et avons reçu de vives critiques. En conséquence, le nombre de membres de l'équipe était limité: froncement de sourcils2:

Malgré tout, j'ai attiré @Taillook et un autre bon camarade de classe pour former une équipe de trois personnes.

Solution

Avec l'équipe de l'équipe mentionnée ci-dessus, j'ai tiré ** le gars qui peut écrire iOS **.

Comme c'est un gros problème, j'ai proposé un système avec la configuration suivante qui vous permet de piloter iOS de n'importe quoi à n'importe quoi (extrait de la présentation de l'annonce finale). Merci pour l'implémentation autour d'iOS, @Taillook.

image.png

J'ai fait de mon mieux avec Keynote pour ce chiffre. Les polices sont ** M + ** et ** Tsukushi B Maru Gothic **.

Aperçu de la reconnaissance

Image cible

À ce moment-là, j'ai reçu une véritable feuille de réponses pour la vérification des opérations, mais j'avais le sentiment que les droits autour de moi seraient gris pour l'apporter ici, alors j'ai utilisé le pouvoir des ** artisans de Pages ** pour générer un échantillon.

image.png

la mise en oeuvre

Eh bien, c'est presque ennuyeux, donc Dawn et le code source. Nous avons préparé un Dockerfile tel que FROM jjanzic / docker-python3-opencv afin que vous puissiez le développer n'importe où. Au final, la partie reconnaissance d'image était exagérée car je l'ai entièrement développée.

Le contenu de Docker est le suivant.

source.py


import os
import cv2
import numpy as np

DIR = os.path.dirname(os.path.abspath(__file__))

image = cv2.imread(f'{DIR}/image/sample_answer_sheet.png')
if image is None:
    print("File not found.")
    exit()


def write_out(img, name):
    cv2.imwrite(f'{DIR}/image/result/{name}.png', img)


def extract_inside(contours, hierarchy, debug=False):
    extracted = []
    contours_drawed = image.copy()
    if debug:
        print(f'len: {len(contours)}')
        print(hierarchy)

    for index in range(len(contours)):
        if hierarchy[0, index, 2] != -1 or cv2.contourArea(contours[index]) < 8000:
            continue
        extracted.append(contours[index])

        if debug:
            cv2.drawContours(contours_drawed, contours, index, (255, 0, 255), 10)

        print(f'{index} : {cv2.contourArea(contours[index])}')

    if debug:
        write_out(contours_drawed, 'out_contours')

    return extracted


width, height = image.shape[:2]

extracted = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)[:, :, 1]

write_out(extracted, 'after_cvt')

ret, thrshld_ex = cv2.threshold(extracted, 0, 255, cv2.THRESH_OTSU)

write_out(thrshld_ex, 'thrshld')

kernel = np.ones((3, 1), np.uint8)
thrshld_ex = cv2.morphologyEx(thrshld_ex, cv2.MORPH_OPEN, kernel)

write_out(thrshld_ex, 'thrshld_ex')

_, contours, hierarchy = cv2.findContours(thrshld_ex, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

inside_contours = extract_inside(contours, hierarchy, True)

print(f'extracted {len(inside_contours)} countours')

clr_img_cp = image.copy()
for circle in inside_contours:
    colors = []
    av_color = 0
    M = cv2.moments(circle)
    center_of_circle = (int(M['m10']/M['m00']), int(M['m01']/M['m00']))
    cnt = 0
    for approx in circle:
        if cnt == 20:
            break
        cv2.circle(clr_img_cp, (approx[0, 0] - 1, approx[0, 1] - 1), 1, (255, 0, 255), 1)
        colors.append(image[approx[0, 1] - 1, approx[0, 0] - 1])
        cnt += 1
    cav = np.mean(colors, axis=0)
    cv2.circle(clr_img_cp, center_of_circle, 100, cav, 20)

write_out(clr_img_cp, 'out')

Cela ressemble à ceci lorsque je dépose ce que j'ai écrit dans le résumé de reconnaissance plus tôt dans le code source. Après avoir prototypé avec Python comme celui-ci, je l'ai porté sur ʻObjective-C` et ai demandé à @Taillook de le relier à Swift.

résultat

--Convertir en espace colorimétrique «HSV» et extraire uniquement «S» --Validation par "méthode d'analyse de discrimination"

Les résultats de chacun des quatre processus sont affichés.

Convertir en espace colorimétrique «HSV» et extraire uniquement «S»

extract_s_of_hsv.py


cv2.cvtColor(image, cv2.COLOR_BGR2HSV)[:, :, 1] # 0: H, 1: S, 2: V

image.png

À ce stade, il est presque binarisé. C'est trop.

Binarisation par "méthode d'analyse de discrimination"

Spécifiez simplement cv2.THRESH_OTSU. Facile.

thresold_with_otsu.py


cv2.threshold(extracted, 0, 255, cv2.THRESH_OTSU)

image.png

S'il y a un peu de bruit, appliquez la «morphologie EX» pour supprimer le bruit.

Détection latérale

OpenCV est déjà incroyable. «findContours» est incroyable. J'ai lu le journal pour le moment, mais il est trop perverti pour reconnaître même les informations structurelles des côtés.

find_contours_with_structure.py


_, contours, hierarchy = cv2.findContours(thrshld_ex, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)

Dans hierarchy, ** quel côté d'index dans contours est ** à côté du côté d'index ** ou ** est inclus ** est stocké. C'est trop.

image.png

Les côtés sont représentés par un ensemble de points et sont dessinés en violet.

Extraire la couleur du côté + dessiner

C'est une poussée. Merci à numpy pour avoir rendu si facile la moyenne des couleurs.

sampling_color_and_averaging_and_plotting.py


clr_img_cp = image.copy()
for circle in inside_contours:
    colors = []
    av_color = 0
    M = cv2.moments(circle)
    center_of_circle = (int(M['m10']/M['m00']), int(M['m01']/M['m00']))
    cnt = 0
    for approx in circle:
        if cnt == 20:
            break
        cv2.circle(clr_img_cp, (approx[0, 0] - 1, approx[0, 1] - 1), 1, (255, 0, 255), 1)
        colors.append(image[approx[0, 1] - 1, approx[0, 0] - 1])
        cnt += 1
    cav = np.mean(colors, axis=0)
    cv2.circle(clr_img_cp, center_of_circle, 100, cav, 20)

image.png

Le centre de la figure est déterminé et un cercle y est dessiné avec la couleur moyenne. (En fait, si vous regardez attentivement cette image, les pixels cibles de 20 échantillons sont colorés en violet.) Cela fait du bien avec presque la même couleur que le côté.

Résumé

Donc, j'ai fait un service commémoratif ici pour le programme de traitement d'image que j'ai fait quand j'étais étudiant: cercueil:

C'était une réflexion de mon point de vue, mais j'espère que vous pourrez lire ceci et sentir la possibilité de Python + ʻOpenCV`.

La seule mise en garde est que «OpenCV» peut être utilisé en apprenant de nombreux cas sans connaître la théorie, mais j'estime que la théorie est la première étape pour dériver la voie la plus courte pour appliquer des moyens pour résoudre des problèmes. Par conséquent, ** l'ingénierie de l'information est importante **. Je n'ai que la théorie de dernière minute parce que j'étais léger et léger.

Cependant, ce qui suit peut être dit à coup sûr.

―― ʻOpenCV est incroyable --Python + ʻOpenCV est facile à faire

à propos de ça. En fait, avant d'écrire cet article, j'ai essayé ʻOpenCV de Rust, mais ce n'était pas bon comparé à la facilité d'utilisation de Python + ʻOpenCV. Eh bien, je ne suis pas habitué à implémenter Rust, donc cela peut ne pas être utile, mais: yum:

C'est "Python", n'est-ce pas lent? Il semble y avoir une histoire, mais hors dessin, elle est d'environ ** 0,3 [sec] **. C'est juste une "liaison C". Génial. Même sur le site de vente de vélos cyma-cyma-, dont je suis impliqué dans le développement, je me sens plus motivé pour reconnaître les images, je voudrais donc montrer ma force.

@shimura_atsushi a écrit 2 articles dans Ateam cyma Advent Calendar 2019, donc si vous êtes intéressé, s'il vous plaît.

en conclusion

Yuruyuru New Graduate 1st Grade Advent Calendar 2019, comment s'est passé votre 23e jour?

Le 24ème jour est au tour de l'ingénieur front-end @ cheez921, qui comprend également le back-end. Duel, veille!

Bon ** Noël **, bon ** fin d'année **, bon ** nouvel an **, bon ** reconnaissance d'image **.

Recommended Posts

Une histoire qui prend en charge la notation électronique des examens avec reconnaissance d'image
L'histoire de la création d'un module qui ignore le courrier avec python
Une histoire qui visualise le présent de Qiita avec Qiita API + Elasticsearch + Kibana
J'ai essayé la reconnaissance d'image de CIFAR-10 avec Keras-Learning-
J'ai essayé la reconnaissance d'image de CIFAR-10 avec la reconnaissance d'image Keras-
L'histoire de la création d'une application Web qui enregistre des lectures approfondies avec Django
Une histoire qui réduit l'effort de fonctionnement / maintenance
Reconnaissance d'image avec keras
Une histoire qui a eu du mal avec l'ensemble commun HTTP_PROXY = ~
Créez un chatbot prenant en charge la saisie gratuite avec Word2Vec
Une histoire qui a analysé la livraison de Nico Nama.
Une histoire qui a trébuché lorsque j'ai créé un bot de chat avec Transformer
Technologie qui prend en charge Jupyter: Tralets (histoire d'essayer de déchiffrer)
L'histoire de la création d'un bot de boîte à questions avec discord.py
Application de la reconnaissance d'image CNN2
Reconnaissance d'image avec Keras + OpenCV
Un aperçu de DELG, une nouvelle méthode d'extraction de caractéristiques d'image qui attire l'attention avec Kaggle
Une histoire que j'ai eu du mal à afficher des graphiques les uns sur les autres avec matplotlib
L'histoire de la création d'un Bot qui affiche les membres actifs dans un canal spécifique de Slack avec Python
Une histoire coincée avec l'installation de la bibliothèque de machine learning JAX
[Statistiques] Saisir l'image de la théorie de la limitation du pôle central avec un graphe
L'histoire de la création d'un pilote standard pour db avec python.
L'histoire de la création d'un site qui répertorie les dates de sortie des livres
L'histoire de la création d'un outil pour charger une image avec Python ⇒ l'enregistrer sous un autre nom
Reconnaissance d'image des fruits avec VGG16
L'histoire de l'exportation d'un programme
Comment appeler une requête POST prenant en charge le japonais (Shift-JIS) avec des requêtes
Technologie qui prend en charge un service de jet d'argent qui peut monétiser un blog avec une seule balise
L'histoire d'un capteur de stationnement en 10 minutes avec le kit de démarrage GrovePi +
L'histoire de la création d'un robot LINE pour le petit-déjeuner d'une université de 100 yens avec Python
Créez un classificateur avec un taux de reconnaissance de l'écriture manuscrite de 99,2% à l'aide du réseau neuronal convolutif TensorFlow
L'histoire du développement d'une application WEB qui génère automatiquement des copies de capture [MeCab]
L'histoire de la création d'une caméra sonore avec Touch Designer et ReSpeaker
L'histoire de la création d'un package qui accélère le fonctionnement de Juman (Juman ++) & KNP