[PYTHON] Décrypter le code QR avec CNN

introduction

CNN utilisant la convolution est relativement bon pour extraire les caractéristiques des images bidimensionnelles en noir et blanc. Un code QR est l'une des images en noir et blanc, voyons donc si la valeur de ce code QR peut être lue par CNN. En fait, quel bit en noir et blanc est la valeur qui peut être lue sur une base de règles, et NN sans convolution est suffisant, mais ici, j'ose utiliser CNN.

Ceci et cela du code QR

La version du code QR dépend de la taille du code QR et du nombre de caractères qu'il peut contenir. Par exemple, version = 1 a une taille de 21 x 21 et peut contenir "www.wikipedia.org" et une chaîne de 17 caractères comme indiqué ci-dessous. Puisque E1 à E7 sont une correction d'erreur, la lecture n'est pas essentielle. En d'autres termes, dans ce cas, chaque caractère est de 8 bits, donc si vous vérifiez la valeur de 136 bits au total, vous pouvez lire ce qui est écrit dans cette taille même sur la base de règles. Pour l'instant, le but est de lire les chiffres inscrits sur ce QR code minimum 21x21. 1280px-QR_Character_Placement.svg.png

code

J'ai écrit ce qui suit à Keras. J'ai converti le nombre à 6 chiffres en une chaîne de caractères et créé 40000 codes QR avec la plus petite taille à utiliser comme données d'entraînement et de test. De plus, s'il s'agit du CNN d'origine, il peut être nécessaire d'utiliser le regroupement pour réduire de moitié la taille de l'image, mais dans ce cas, la taille d'entrée est aussi petite que 21 × 21, donc conv2d constitue à lui seul la partie de convolution.

qr.py


import qrcode
import numpy as np
import random
from keras.utils import np_utils
from keras.layers import Input, Conv2D, MaxPooling2D, AveragePooling2D, BatchNormalization, Concatenate
from keras.models import Model

batch_size = 128
num_classes = 10
epochs = 30

X, Y = [], []
sample_list = random.sample(range(10**6), k=40000)
for i in sample_list:
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=1, border=0 )

    qr.add_data('%06d' % (i))
    qr.make()
    img = qr.make_image()
    X.append(np.asarray(img))
    Y.append([int(d) for d in format(i, '06d')])

X = np.reshape(np.asarray(X),(-1,21,21,1))/1.0
Y = np.reshape(np_utils.to_categorical(np.asarray(Y)), (-1,1,6,10))
print(X.shape)
print(Y.shape)


inputs = Input((21,21,1))
x = Conv2D(256, (3,3), padding='same', activation='relu')(inputs)
x = BatchNormalization()(x)
x = Conv2D(256, (3,3), padding='same', activation='relu')(x)
x = BatchNormalization()(x)
x = Conv2D(256, (3,3), padding='same', activation='relu')(x)
x = BatchNormalization()(x)
x = Conv2D(256, (3,3), padding='same', activation='relu')(x)
x = BatchNormalization()(x)
x = Conv2D(256, (3,3), padding='same', activation='relu')(x)
x = BatchNormalization()(x)
x = Conv2D(512, (3,3), padding='same', activation='relu')(x)
x = BatchNormalization()(x)
x = Conv2D(512, (3,3), padding='same', activation='relu')(x)
x = MaxPooling2D(pool_size=(21, 21))(x)
y = [Conv2D(10, (1,1), activation='softmax')(x) for i in range(6)]
y = Concatenate(axis=-2)(y)

model = Model(inputs=inputs, outputs=y)
model.summary()
model.compile(loss='categorical_crossentropy',
              optimizer='Adam',
              metrics=['accuracy'])
history = model.fit(X[:30000], Y[:30000], batch_size=batch_size, epochs=epochs, verbose=1, validation_data=(X[30000:], Y[30000:]))

model.save('qr_model.h5', include_optimizer=False)

ici

qr.py


y = [Conv2D(10, (1,1), activation='softmax')(x) for i in range(6)]
y = Concatenate(axis=-2)(y)

Vous pouvez écrire la partie comme suit.

qr.py


y1 = Conv2D(10, (1,1), activation='softmax')(x)
y2 = Conv2D(10, (1,1), activation='softmax')(x)
y3 = Conv2D(10, (1,1), activation='softmax')(x)
y4 = Conv2D(10, (1,1), activation='softmax')(x)
y5 = Conv2D(10, (1,1), activation='softmax')(x)
y6 = Conv2D(10, (1,1), activation='softmax')(x)
y = Concatenate(axis=-2)([y1,y2,y3,y4,y5,y6])

Le résultat de l'exécution du code à ce moment est le suivant.

(40000, 21, 21, 1)
(40000, 1, 6, 10)
...
__________________________________________________________________________________________________
Layer (type)                    Output Shape         Param #     Connected to
==================================================================================================
input_1 (InputLayer)            (None, 21, 21, 1)    0
__________________________________________________________________________________________________
conv2d_1 (Conv2D)               (None, 21, 21, 256)  2560        input_1[0][0]
__________________________________________________________________________________________________
batch_normalization_1 (BatchNor (None, 21, 21, 256)  1024        conv2d_1[0][0]
__________________________________________________________________________________________________
conv2d_2 (Conv2D)               (None, 21, 21, 256)  590080      batch_normalization_1[0][0]
__________________________________________________________________________________________________
batch_normalization_2 (BatchNor (None, 21, 21, 256)  1024        conv2d_2[0][0]
__________________________________________________________________________________________________
conv2d_3 (Conv2D)               (None, 21, 21, 256)  590080      batch_normalization_2[0][0]
__________________________________________________________________________________________________
batch_normalization_3 (BatchNor (None, 21, 21, 256)  1024        conv2d_3[0][0]
__________________________________________________________________________________________________
conv2d_4 (Conv2D)               (None, 21, 21, 256)  590080      batch_normalization_3[0][0]
__________________________________________________________________________________________________
batch_normalization_4 (BatchNor (None, 21, 21, 256)  1024        conv2d_4[0][0]
__________________________________________________________________________________________________
conv2d_5 (Conv2D)               (None, 21, 21, 256)  590080      batch_normalization_4[0][0]
__________________________________________________________________________________________________
batch_normalization_5 (BatchNor (None, 21, 21, 256)  1024        conv2d_5[0][0]
__________________________________________________________________________________________________
conv2d_6 (Conv2D)               (None, 21, 21, 512)  1180160     batch_normalization_5[0][0]
__________________________________________________________________________________________________
batch_normalization_6 (BatchNor (None, 21, 21, 512)  2048        conv2d_6[0][0]
__________________________________________________________________________________________________
conv2d_7 (Conv2D)               (None, 21, 21, 512)  2359808     batch_normalization_6[0][0]
__________________________________________________________________________________________________
max_pooling2d_1 (MaxPooling2D)  (None, 1, 1, 512)    0           conv2d_7[0][0]
__________________________________________________________________________________________________
conv2d_8 (Conv2D)               (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_9 (Conv2D)               (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_10 (Conv2D)              (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_11 (Conv2D)              (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_12 (Conv2D)              (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
conv2d_13 (Conv2D)              (None, 1, 1, 10)     5130        max_pooling2d_1[0][0]
__________________________________________________________________________________________________
concatenate_1 (Concatenate)     (None, 1, 6, 10)     0           conv2d_8[0][0]
                                                                 conv2d_9[0][0]
                                                                 conv2d_10[0][0]
                                                                 conv2d_11[0][0]
                                                                 conv2d_12[0][0]
                                                                 conv2d_13[0][0]
==================================================================================================
Total params: 5,940,796
Trainable params: 5,937,212
Non-trainable params: 3,584
__________________________________________________________________________________________________
Train on 30000 samples, validate on 10000 samples
Epoch 1/30
30000/30000 [==============================] - 66s 2ms/step - loss: 2.7801 - acc: 0.1714 - val_loss: 2.3467 - val_acc: 0.2484
Epoch 2/30
30000/30000 [==============================] - 62s 2ms/step - loss: 1.8426 - acc: 0.3493 - val_loss: 1.6885 - val_acc: 0.3941
Epoch 3/30
30000/30000 [==============================] - 64s 2ms/step - loss: 1.4841 - acc: 0.4555 - val_loss: 1.4549 - val_acc: 0.4547
...
Epoch 28/30
30000/30000 [==============================] - 64s 2ms/step - loss: 0.0401 - acc: 0.9868 - val_loss: 0.3695 - val_acc: 0.9110
Epoch 29/30
30000/30000 [==============================] - 64s 2ms/step - loss: 0.0435 - acc: 0.9853 - val_loss: 0.3403 - val_acc: 0.9184
Epoch 30/30
30000/30000 [==============================] - 63s 2ms/step - loss: 0.0339 - acc: 0.9889 - val_loss: 0.3164 - val_acc: 0.9231

La précision finale est ** acc: 0.9889, val_acc: 0.9231 **. L'époque et le modèle conviennent, donc les ajuster améliorera un peu plus la précision.

tester

Écrivez ce qui suit comme code de vérification. Le résultat est une condition limitée assez petite de 21x21 avec version = 1 du code QR, mais j'ai pu prédire un nombre à 6 chiffres dans une certaine mesure.

qr2.py


import qrcode
import numpy as np
import random
from keras.models import load_model

X, Y = [], []
sample_list = random.sample(range(10**6), k=10)
for i in sample_list:
    qr = qrcode.QRCode(
        version=1,
        error_correction=qrcode.constants.ERROR_CORRECT_H,
        box_size=1, border=0 )

    qr.add_data('%06d' % (i))
    qr.make()
    img = qr.make_image()
    X.append(np.asarray(img))
    Y.append(i)

X = np.reshape(np.asarray(X),(-1,21,21,1))/1.0
model = load_model('qr_model.h5')

Y_pred = model.predict(X)

Y_pred_list = []
for i in range(10):
    Y_pred_value = 0
    for j in range(6):
        Y_pred_value += np.argmax(Y_pred[i,0,j])
        Y_pred_value *= 10
    Y_pred_list.append(Y_pred_value//10)
print(Y)
print(Y_pred_list)
[89127, 306184, 427806, 501649, 727976, 232504, 427216, 893062, 127368, 100207]
[89127, 306184, 427806, 501649, 727976, 234506, 431222, 893062, 127378, 100207]

Caractéristiques de localisation

Généralement, MaxPooling2D sait s'il y a une fonction dans l'image, mais il n'atteint pas cet emplacement dans les couches suivantes. En parlant de CNN, il est souvent utilisé pour des problèmes de classification tels que les chiens et les chats étant inclus quelque part dans l'image, mais d'un autre côté, j'ai pensé qu'il était possible d'extraire des caractéristiques (sans utiliser d'aplatissement) pour spécifier l'emplacement, mais c'est possible. Et il semble. Cela peut être dû au fait que la quantité de caractéristiques de l'emplacement des données est extraite par la valeur de données dans la convolution à courte distance et la distance du motif carré fixe dans le coin supérieur gauche, supérieur droit et inférieur gauche dans la convolution longue distance. Si vous venez de lire la valeur des données (8 bits de 2,4 ou 4,2), Conv2d avec 2 couches (équivalent à 5,5) devrait suffire, mais en réalité, la précision n'est pas si élevée avec le modèle avec Conv2d à 2 couches. C'était (val_acc: environ 0,5). Par conséquent, si vous lisez le code QR avec CNN, il peut être nécessaire d'extraire la quantité de caractéristiques du lieu par un pliage longue distance. (Ou peut-être qu'il vaut mieux utiliser aplatir rapidement comme modèle ...)

Recommended Posts

Décrypter le code QR avec CNN
Vérifiez le code avec flake8
Affichage du code QR
Afficher rapidement le code QR sur la ligne de commande
Convertir le code de caractère du fichier avec Python3
Renforcez avec le test de code ⑦
Renforcez avec le test de code ⑨
Renforcez avec le test de code ③
Excel a essayé d'invoquer le code QR avec la magie noire
Créez un code QR pour l'URL sous Linux
Renforcez avec le test de code ⑤
Renforcez avec le test de code ④
Lire le code QR à partir du fichier image avec Python (Mac)
Renforcez avec le test de code ②
Aperçu de la caméra QR code
Code de bourdonnement avec numpy
Renforcez avec le test de code ①
Afficher le coupon de Matsuya (code QR) avec Pythonista pour iOS
Renforcez avec le test de code ⑧
Renforcez avec le test de code ⑨
CNN avec keras Essayez avec l'image que vous avez prise
J'ai écrit le code pour la génération de phrases japonaises avec DeZero
Profitez du modèle Gray-Scott avec un code court utilisant le calcul matriciel
Paramètres pour entrer et déboguer le contenu de la bibliothèque avec VS Code
Histoire que Python a cessé de travailler avec VS Code (Windows 10)
Recharger le serveur configuré avec gunicorn lors du changement de code
Commerce du système à partir de Python3: obtenez le dernier code de programme
Essayez d'extraire les caractéristiques des données de capteur avec CNN
Obtenez le code du pays avec python
Implémentation CNN avec juste numpy
Insérez le débogueur avec le nez
Tuez le processus avec sudo kill -9
Commande pour générer un code QR
Essayez d'exécuter CNN avec ChainerRL
Expliquez le code de Tensorflow_in_ROS
Déboguer Python avec VS Code
Devinez le mot de passe avec klee
gethostbyaddr () communique avec l'extérieur
Créez facilement des CNN avec Keras
Utilisez Maxout + CNN avec Pylearn2
Générer du code QR en Python
Gratter la moyenne du Nikkei avec le dramaturge-python
Calibrer le modèle avec PyCaret
Survivez à Noël avec CNN au niveau du personnage
Appelez l'API avec python3.
Documenter le code Python avec Doxygen
Bénéficiez de l'environnement le plus puissant avec VS Code, Remote-Containers et Remote Docker-Daemon
Vérifiez la réponse du code d'état HTTP avec la commande curl (#Linux #Shell)
Vérifiez la protection de la mémoire de Linux Kerne avec le code pour ARM
Résumons le degré de couplage entre les modules avec du code Python