Lier PHP et Python à partir de zéro sur Laravel

introduction

Implémentons un logiciel basé sur Laravel qui exécute Python à partir de PHP et affiche le résultat de la reconnaissance d'image.

La mise en œuvre de la reconnaissance d'image est Essayez d'apprendre MNIST avec TensorFlow, qui est basée sur la formation et le test séparés. À

[2020/4/15] Présentation de Bootstrap

environnement

--OS: Ubuntu 18.04.4 LTS (sur Virtual BOX)

Python3, qui est inclus dans Ubuntu 18.04.4 LTS par défaut, était 3.6.9, donc je l'ai mis à jour. En même temps, incluez la bibliothèque utilisée dans Python.

$sudo apt install python3.8
$sudo apt-get install python3-pip python3-dev
$pip3 install tensorflow
$pip3 install numpy
$pip3 install opencv-python

Notez que la bibliothèque Python2 sera incluse si vous installez avec les commandes $ sudo apt-get install python-pip python-dev et pip.

Réécrivez "~ / .bashrc" pour utiliser python3.8.

..bashrc


alias python3='/usr/bin/python3.8'

Créer un projet

Créez un projet nommé laravelAI.

$ composer create-project laravel/laravel laravelAI --prefer-dist

Structure des répertoires / fichiers

Seuls les éléments à ajouter / corriger cette fois sont répertoriés. Le déficit s'ajoute. laravelAI  ┗ app   ┗ Http    ┗ MnistController.php Python </ font>: stocke les fichiers liés à Python    ┗ mnist_test.py    ┗ DeepConvNet.py ckpt </ font>: stocker les résultats d'apprentissage  ┗ resources   ┗ views    ┗ mnist     ┗ index.blade.php  ┗ routes   ┗ wab.php

PHP (contrôleur)

Créez un contrôleur.

$ php artisan make:controller MnistController

MnistController.php


<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class MnistController extends Controller
{
    public function index(Request $request)
    {
        $data = [
            'msg' => "Veuillez saisir une image",
        ];
        return view('mnist.index', $data);
    }

    public function test(Request $request)
    {
        if(!empty($request->test_image))
        {
            //Obtenez l'image envoyée par POST
            $image = $request->file('test_image');
            //La destination de sauvegarde est"storage/app/public/image"Sera
            //Le nom du fichier sera attribué automatiquement
            $up_pass = $image->store('public/image');
            $image_pass = "./storage/image/".basename($up_pass);
            //Définissez le chemin où se trouve le fichier Python
            $pythonPath =  "../app/Python/";
            $command = "/usr/bin/python3 " . $pythonPath . "mnist_test.py " . $pythonPath . " " .$image_pass;
            exec($command , $outputs);

            //Extraction de lignes de résultats avec des expressions régulières
            $results = preg_grep('/result:.*/' , $outputs);
            if(count($results) == 1){
                //Obtenez le début d'un tableau associatif
                $result = reset($results);
                $result = substr($result , strlen('result:') , 1 );
            } 
            else {
                $result = "L'analyse a échoué.";
            }
            $data = [
                'msg' => "As tu un?",
                'image_pass' => $image_pass,
                'result'  => $result,
                'lines'   => count($outputs),
                'outputs' => $outputs,
            ];
        }
        else {
            $data = [
                'msg' => "il n'y a pas d'image",
            ];
        }
        return view('mnist.index', $data);
    }
}

La description

Exécuter des commandes Python

//Définissez le chemin où se trouve le fichier Python
$pythonPath =  "../app/Python/";
$command = "/usr/bin/python3 " . $pythonPath . "mnist_test.py " . $pythonPath . " " .$image_pass;
exec($command , $outputs);

L'exécution de commandes depuis PHP utilise la fonction ʻexec () `. Spécifiez la commande à exécuter dans le premier argument et spécifiez la variable qui stocke le résultat de sortie de la commande dans le deuxième argument. Voir ici pour plus de détails.

Exécutez Python sur le / usr / bin / python3 Python file. La chaîne $ command ci-dessus ressemble à ceci: /usr/bin/python3 ../app/Python/mnist_test.py ../app/Python/ ./storage/image/FxY92Ji6j04cyozrx62yGHu9NQzLgsIqQq23YIcH.png

Si vous modifiez la commande comme $ command =" pwd "; et que vous l'exécutez, vous pouvez voir que le chemin d'exécution de Laravel est "/ home / hogehoge / laravelAI / public". En supposant que, spécifiez l'emplacement où se trouve le fichier Python.

Le premier argument de mnist_test.py est le" chemin des données de formation "et le deuxième argument est le" chemin de l'image ".

Concernant l'emplacement de stockage de l'image reçue

//Obtenez l'image envoyée par POST
$image = $request->file('test_image');
$up_pass = $image->store('public/image');
$image_pass = "./storage/image/".basename($up_pass);

La destination de sauvegarde de l'image est "stockage / application / public / image". Créez un lien symbolique de «public / stockage» vers «stockage / app / public» avec la [commande] suivante (https://laravel.com/docs/7.x/filesystem). Pour le deuxième argument de mnist_test.py et l'image affichée dans la vue, spécifiez le chemin sous" public / storage ".

$ php artisan storage:link
$ cd public
$ ls -la
=> storage -> /home/hogehoge/laravelAI/storage/app/public

PHP (routage)

Ajoutez ce qui suit à routes / web.php.

routes/web.php


Route::get ('mnist', 'MnistController@index');
Route::post('mnist', 'MnistController@test');

Pyhton Le résultat d'apprentissage peut être utilisé tel quel depuis Essayez d'apprendre MNIST avec TensorFlow. Stockez-le dans le dossier "Python / ckpt".

Le code de test sera légèrement modifié. Vous permet de spécifier le «chemin des données d'entraînement» et le «chemin de l'image» avec des arguments de ligne de commande.

mnist_test.py


# -*- coding: utf-8 -*-
print('mnist_test.py START')
import sys
import tensorflow as tf
import cv2
import numpy as np
import DeepConvNet as CNN
#Obtenir des arguments de ligne de commande
args = sys.argv

IMAGE_SIZE  = 28    #Taille de l'image
NUM_CLASSES = 10    #Nombre d'identifications

if __name__ == "__main__":
    tf.reset_default_graph()
    
    print('Réglage START')
    #Paramètres variables utilisés dans les expressions
    x_image = tf.placeholder("float", shape=[None, IMAGE_SIZE * IMAGE_SIZE])    #contribution
    y_label = tf.placeholder("float", shape=[None, NUM_CLASSES]) #production
    keep_prob = tf.placeholder("float")

    #Créer un modèle
    logits = CNN.CNN.makeMnistCNN(x_image, keep_prob , IMAGE_SIZE , NUM_CLASSES)
    sess = tf.InteractiveSession()

    saver = tf.train.Saver()
    #Initialiser et exécuter des variables
    sess.run(tf.global_variables_initializer())
    print('Réglage FIN')
    
    print('Restore Param Start')
    ckpt = tf.train.get_checkpoint_state(args[1] + 'ckpt')
    #print(os.path.exists(args[1] + 'ckpt'))
    if ckpt: #S'il y a un point de contrôle
        last_model = ckpt.model_checkpoint_path #Chemin vers le dernier modèle enregistré
        print ("Restore load:" + last_model)
        saver.restore(sess, last_model) #Lecture de données variables
    else:
        print('Restore Failed')
    print('Restore Param End')
    
    
    #Chargement d'image
    inputNum = 1
    for count in range(int(inputNum)):
        fileName =  args[2]
        print('fileName:' + fileName)

        #Initialisation
        ximage = []
        
        #Chargement d'image
        image = cv2.imread(fileName, cv2.IMREAD_GRAYSCALE)
        if not image is None:
            image = cv2.resize(image, (IMAGE_SIZE, IMAGE_SIZE))
            ximage = image.flatten().astype(np.float32)/255.0
        else:
            print('Error:File Read Failed !!')

        if len(ximage)!=0:
            pred = np.argmax(logits.eval(feed_dict={x_image: [ximage], keep_prob: 1.0})[0])
            
            print("result:" + str(pred))
    sess.close()
    print('mnist_test.py END')

PHP (voir)

Créez une vue. La disposition est adaptée.

index.blade.php  //.html


<html>
<head>
    <title>Mnist</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" >
    <style>
        body{
            background-color: #EEFFEE;
        }
    </style>
</head>

<body>
<div class="container">
        <div class="row">
            <div class="col-sm-10">
                <h2>1-Reconnaissez le chiffre 9</h2>
                <p>{{$msg}}</p>

                <form method = "POST" action="/mnist" enctype="multipart/form-data">
                    @csrf
                    <input type="file" name="test_image"><BR>
                    <input type="submit" id="submit" value="Envoyer">
                </form>
            </div>
        </div>

        <div class="row">
            @isset($image_pass)
                <div class="col-sm-5">
                    <h3>résultat</h3>
                    <img src="{{ asset($image_pass)}}" width="112" height="112"> <BR>
                    @isset($result)
                        <p>Cette image est "{{$result}}"est</p>
                    @endempty
                </div>
            @endempty

            @isset($outputs)
                <div class="col-sm-5">
                    <h3>Sortie Python( {{$lines}}ligne)</h3>
                    @foreach ($outputs as $output)
                        {{$output}}<BR>
                    @endforeach
                </div>
            @endempty
        </div>
    </div>
</body>
</html>

Contrôle de fonctionnement

Démarrez le serveur avec la commande suivante.

$ php artisan serve 

Accédez à "http: // localhost: 8000 / mnist" dans votre navigateur. WS000226.JPG

Sélectionnez un fichier et envoyez-le. WS000225.JPG

J'ai pu le reconnaître!

À la fin

L'introduction de Vue et TypeScript est décrite dans Lien entre PHP et Python à partir de zéro sur Laravel + Vue + TypeScript.

Supplément

Exception lors de l'enregistrement du fichier: le fichier "" n'existe pas ou n'est pas lisible.

Quand je jouais avec le code dans un autre cas, je suis tombé sur l'exception ci-dessus avec $ image-> store () de sauvegarde de fichier, donc je l'ai attrapée.

Symfony\Component\Mime\Exception\InvalidArgumentException
The "" file does not exist or is not readable. 

C'est difficile à dire à partir du message d'exception ou de la pile d'appels, mais c'est parce que vous êtes bloqué avec une limite de taille de fichier téléchargé.

Contre-mesures

La taille du fichier est définie dans le fichier php.ini, donc modifiez-le. (J'ai cherché en ligne et j'ai trouvé comment réparer .htaccess, mais la correction de public / .htaccess n'a pas aidé.)

# php.Vérifiez l'emplacement de ini
$ php -i | grep php.ini
Configuration File (php.ini) Path => /etc/php/7.2/cli
Loaded Configuration File => /etc/php/7.2/cli/php.ini

$ sudo vi  /etc/php/7.2/cli/php.ini

Modifiez les deux lignes suivantes selon vos besoins. En PHP7.2, la valeur par défaut est 2 Mo et 8 Mo.

php.ini


;Taille totale maximale de tous les fichiers téléchargés par POST
post_max_size=2M
;Taille maximale par fichier
upload_max_filesize=8M

Veuillez redémarrer le serveur après avoir effectué la modification.

$ php artisan  serve

Recommended Posts