Avec keras + flask, j'ai créé une application Web (nom de l'application: Tanpic) qui juge le degré de saleté de l'image de la langue.
On dit que la raison de son développement est que la saleté à la surface de la langue appelée mousse de langue est liée à une mauvaise odeur (* 1), et j'ai pensé que ce serait intéressant s'il y avait une application qui pourrait visualiser les mauvaises odeurs avec un smartphone. est.
<a href = "https://px.a8.net/svt/ejp?a8mat=35RZ3H+G23XY2+3L4M+BW8O2&a8ejpredirect=https%3A%2F%2Fwww.udemy.com%2Fcourse%2Ftensorflow-advanced % 2F "rel =" nofollow "> [Développement d'application Image Judgment AI / Partie 1] Introduction au développement d'application Image Judgment AI avec TensorFlow / Python / Flask <img border =" 0 "width =" 1 "height = "1" src = "https://www13.a8.net/0.gif?a8mat=35RZ3H+G23XY2+3L4M+BW8O2" alt = ""> a été très utile. Les explications sont faciles à comprendre et vous pouvez poser des questions, donc je pense que c'est un matériel pédagogique recommandé pour ceux qui font une demande de classification d'images pour la première fois.
Au fait, je suis actuellement en 5e année à la Faculté de médecine dentaire et je ne suis pas encore vraiment dentiste. .. ..
Lorsque je télécharge une image de ma langue ...
Le degré de saleté sur la langue est évalué en 3 étapes. En passant, cela vous rendra un peu de connaissance sur les mauvaises odeurs. J'espère que vous pouvez ignorer le mauvais comportement et le manque de sens du design. .. ..
Tanpic:https://tanpic-b86b4.firebaseapp.com/
Dans cette phase, nous avons effectué les opérations suivantes:
Les données d'image ont été collectées à l'aide d'icrowler. Veuillez vous référer au document pour plus de détails.
Référence: documentation icrawler
Après avoir éliminé les images inutiles, seule la langue est coupée manuellement une par une. Après cela, le degré de saleté sur la langue a été classé en trois.
Degré de saleté 1 (nom de l'étiquette: tongue0)
Degré de saleté 2 (nom de l'étiquette: tongue1)
Degré de saleté 3 (nom de l'étiquette: tongue2)
Le traitement des données était long et laborieux et assez difficile
J'ai utilisé le GPU google colabratoly pour apprendre.
Après avoir gonflé et entraîné les images collectées, enregistrez le modèle sous le nom tongue_cnn_aug.h5. J'omettrai les détails.
Test Accuracy
C'était 66,66%.
Voici un bref résumé de ce que nous faisons.
predict_web.py
import os
from flask import Flask, flash, request, redirect, url_for, render_template
from werkzeug.utils import secure_filename
from keras.models import load_model
import numpy as np
from PIL import Image
import tensorflow as tf
class_1 = "C'est 1."
class_content_1 = "Il n'y a presque pas de mousse de langue dessus, et il semble être dans un assez bel état."
classes_solution_1 = "Faisons de notre mieux en matière de soins bucco-dentaires comme avant. En guise de mise en garde, un nettoyage excessif de la langue endommage non seulement la langue, mais augmente également la quantité de mousse de langue attachée, alors assurez-vous de le faire doucement une fois par jour."
class_2 = "C'est 2."
class_content_2 = "Vous n'avez pas à vous soucier de la saleté sur votre langue."
classes_solution_2 = "Langue sale(Mousse de langue)Peut causer de mauvaises odeurs, donc si cela vous inquiète, c'est une bonne idée de nettoyer doucement votre langue une fois par jour. De plus, l'odeur buccale a tendance à être plus forte le soir lorsque la production de salive est faible. Assurez-vous de vous gargariser et de vous réhydrater pour prendre des mesures."
class_3 = "C'est 3."
class_content_3 = "Il peut y avoir de la saleté sur votre langue. La mousse de langue (saleté sur la langue) peut également provoquer de mauvaises odeurs, il est donc conseillé de nettoyer votre langue en plus de votre brossage habituel."
classes_solution_3 = "Pour nettoyer la mousse de la langue, utilisez de la gaze ou une brosse à langue et frottez doucement la surface de la langue de l'arrière vers l'avant. Ne le faites qu'une fois par jour."
classes = [class_1,class_2,class_3]
classes_content = [class_content_1, class_content_2, class_content_3]
classes_solution = [classes_solution_1, classes_solution_2, classes_solution_3]
num_classes = len(classes)
image_size = 50
UPLOAD_FOLDER = './uploads'
ALLOWED_EXTENSIOS = set(['png', 'jpg', 'gif','heic'])
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
model = load_model('./tongue_cnn_aug.h5')
graph = tf.get_default_graph()
def allowed_file(filename):
#si.が含まれたる かつ si拡張子前の.Séparé par, vrai si l'extension est inférieure ou inférieure
return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIOS
# @app.route('/', methods=['GET', 'POST'])
@app.route('/')
def upload_file():
return render_template('test.html')
@app.route('/predict',methods=['GET', 'POST'])
def predict_file():
global graph
with graph.as_default():
if request.method == 'POST':
file = request.files['file'] #ajouter à
if file and allowed_file(file.filename):
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
filepath = os.path.join(app.config['UPLOAD_FOLDER'], filename)
image = Image.open(filepath)
image = image.convert('RGB')
image = image.resize((image_size, image_size))
data = np.asarray(image)
X = []
X.append(data)
X = np.array(X)
result = model.predict([X])[0]
predicted = result.argmax()
return render_template('predict.html', result = classes[predicted], result_content = classes_content[predicted], result_solution = classes_solution[predicted], result_title="Résultats d'analyse",img_name=file.filename)
from flask import send_from_directory
@app.route('/uploads/<filename>')
def uploaded_file(filename):
return send_from_directory(app.config['UPLOAD_FOLDER'], filename)
predict.html
<!DOCTYPE! html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>Tanpic</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/css/style.css">
<link rel="shortcut icon" href="/static/favicon.ico">
<!--Chargement CSS Bootstrap-->
<link rel="stylesheet" href="/static/css/bootstrap.min.css">
<!--manifest.Chargement de json-->
<!--<link rel="manifest" href="./manifest.json">-->
</head>
<body>
<!--navi bar-->
<nav class="navbar navbar-expand-lg navbar-light bg-light fixed-top">
<a class="navbar-brand" href="#">Tanpic</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarTogglerDemo03" aria-controls="navbarTogglerDemo03" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarTogglerDemo03">
<ul class="navbar-nav mr-auto mt-2 mt-lg-0">
<li class="nav-item active">
<a class="nav-link" href="#">Home <span class="sr-only">(current)</span></a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Disabled</a>
</li>
</ul>
</div>
</nav>
<!--header area-->
<header class = "bg-primary text-center">
<div class = "bg-mask">
<div class="container">
<h1>Tanpic</h1>
<h2>Mettez une photo de votre langue</h2>
<ul>
{% for entry in entries %}
<li>{{entry.title}} / {{entry.text}}</li>
{% endfor %}
</ul>
</div>
</div>
</header>
<!--sorting Grid section-->
<section class = "sorting">
<div class = "container text-center">
{%if img_name%}
<img src="uploads/{{img_name}}" style="width:300px;height:300px;">
{%endif%}
</div>
</section>
<!-- prediction session-->
<div class = "container">
<p>
{%if result_title%}
{{result_title}}
{%else%}
{%endif%}
</p>
<p class="lead">
<span>
{% if result %}
Il y a 3 niveaux de saleté sur votre langue{{ result }}
{% else %}
{% endif %}
</span>
<br>
<br>
<span>
{%if result_content%}
{{result_content}}
{%else%}
{%endif%}
</span>
<br>
<br>
<span>
{%if result_solution%}
{{result_solution}}
{%else%}
{%endif%}
</span>
</p>
<a href="/">Revenir</a>
</div>
<!-- Footer -->
<footer class="page-footer font-small cyan darken-3">
<!-- Footer Elements -->
<div class="container">
<!-- Grid row-->
<div class="row">
<!-- Grid column -->
<div class="col-md-12 py-5">
<div class="mb-5 flex-center">
<!-- Facebook -->
<a class="fb-ic">
<i class="fab fa-facebook-f fa-lg white-text mr-md-5 mr-3 fa-2x"> </i>
</a>
<!-- Twitter -->
<a class="tw-ic">
<i class="fab fa-twitter fa-lg white-text mr-md-5 mr-3 fa-2x"> </i>
</a>
<!-- Google +-->
<a class="gplus-ic">
<i class="fab fa-google-plus-g fa-lg white-text mr-md-5 mr-3 fa-2x"> </i>
</a>
<!--Linkedin -->
<a class="li-ic">
<i class="fab fa-linkedin-in fa-lg white-text mr-md-5 mr-3 fa-2x"> </i>
</a>
<!--Instagram-->
<a class="ins-ic">
<i class="fab fa-instagram fa-lg white-text mr-md-5 mr-3 fa-2x"> </i>
</a>
<!--Pinterest-->
<a class="pin-ic">
<i class="fab fa-pinterest fa-lg white-text fa-2x"> </i>
</a>
</div>
</div>
<!-- Grid column -->
</div>
<!-- Grid row-->
</div>
<!-- Footer Elements -->
<!-- Copyright -->
<div class="footer-copyright text-center py-3">© 2018 Copyright:
<a href="https://mdbootstrap.com/education/bootstrap/"> MDBootstrap.com</a>
</div>
<!-- Copyright -->
</footer>
<script type="text/javascript" src="/static/js/jquery-3.3.1.min.js"></script>
<!--js script-->
<script type="text/javascript" src="/static/js/text.js"></script>
<!--Chargement Bootstrap JS-->
<script type="text/javascript" src="/static/js/bootstrap.min.js"></script>
<!-- Firebase App (the core Firebase SDK) is always required and must be listed first -->
<script src="https://www.gstatic.com/firebasejs/6.2.0/firebase-app.js"></script>
<!-- Add Firebase products that you want to use -->
<script src="https://www.gstatic.com/firebasejs/6.2.0/firebase-firestore.js"></script>
<script src="https://www.gstatic.com/firebasejs/6.2.0/firebase-storage.js"></script>
</body>
</html>
J'ai décidé d'utiliser Firebase Cloud Storage pour collecter les images téléchargées.
Article de référence: [Implémentation d'une application de téléchargement d'images sur Firebase Cloud Storage](https://kapi-travel.com/programing/firebase-cloud-storage%E3%81%B8%E3%81%AE%E7%94% BB% E5% 83% 8F% E3% 82% A2% E3% 83% 83% E3% 83% 97% E3% 83% AD% E3% 83% BC% E3% 83% 89% E3% 82% A2% E3% 83% 97% E3% 83% AA% E3% 82% 92% E5% AE% 9F% E8% A3% 85 /)
text.js
// Your web app's Firebase configuration
var firebaseConfig = {
apiKey: "",
authDomain: "",
databaseURL: "",
projectId: "",
storageBucket: "",
messagingSenderId: "",
appId: "",
measurementId: ""
};
// Initialize Firebase
firebase.initializeApp(firebaseConfig);
const storage = firebase.storage();
var file_name;
var blob;
$('#f1').on('submit',function(e){
//Traitement lorsqu'une image est soumise sans être téléchargée
if($('#myfile').val()===""){
$('#error').text("Veuillez sélectionner un fichier");
e.preventDefault();
}
//Processus de téléchargement sur Cloud Storage
var uploadRef = storage.ref().child(file_name);
uploadRef.put(blob).then(snapshot => {
console.log(snapshot.state);
});
//réinitialisation de la valeur
file_name = '';
blob = '';
});
Lorsque j'ai vérifié l'écran de la console, l'image a été enregistrée fermement. C'était pratique car très simple à mettre en œuvre.
Je l'ai déployé sur heroku en me référant à l'article suivant.
Référence: Qiita Flask Tutorial + Deploy to heroku
Après vous être connecté à heroku, suivez les étapes ci-dessous pour vous engager.
$ git add .
$ git commit
$ git push heroku master
Je suis tombé sur une erreur R14 en raison d'une mémoire insuffisante lors de git push heroku master. Avec le plan gratuit, la limite supérieure de mémoire est de 512 Mo, et il semble qu'une erreur R14 s'est produite car elle a dépassé cette valeur. La solution était d'utiliser un modèle plus petit et de maintenir l'utilisation de la mémoire en dessous de la limite supérieure.
Référence: Que faire lorsqu'une erreur R14 / R15 se produit dans Qiita Heroku
github:https://github.com/salmon0511/TongueCoatingClassificationApp
C'était amusant de le mettre en œuvre en se référant à divers articles afin de concrétiser l'idée. De plus, j'ai été impressionné quand j'ai pu surmonter de nombreuses erreurs et déployer.
Cependant, je ne me souciais pas de la lisibilité (pour être exact, je ne sais toujours pas quel code est hautement lisible), alors j'aimerais essayer d'écrire du code facile à lire à partir de maintenant.
Service de classification d'images de prototype avec Qiita Flask & Keras
Créer une application de reconnaissance de caractères manuscrits avec Flask + Keras
Recommended Posts