[PYTHON] Ein Zahnarzt (!?) Erstellt eine App zur Beurteilung der Zungenmoosmenge mit Flasche + Keras

Einführung

Mit keras + flask habe ich eine Webanwendung (App-Name: Tanpic) erstellt, die den Schmutzgrad anhand des Zungenbildes beurteilt.

Es wird gesagt, dass der Grund für die Entwicklung darin besteht, dass Schmutz auf der Oberfläche der Zunge, genannt Zungenmoos, mit schlechtem Geruch zusammenhängt (* 1), und ich dachte, es wäre interessant, eine App zu haben, die schlechten Geruch mit einem Smartphone visualisieren kann. ist.

<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 "> [AI-App-Entwicklung zur Bildbeurteilung / Teil 1] Einführung in die AI-App-Entwicklung zur Bildbeurteilung mit TensorFlow / Python / Flask <img border =" 0 "width =" 1 "height = "1" src = "https://www13.a8.net/0.gif?a8mat=35RZ3H+G23XY2+3L4M+BW8O2" alt = ""> war sehr hilfreich. Die Erklärungen sind leicht zu verstehen und Sie können Fragen stellen. Ich denke, es ist ein empfohlenes Lehrmaterial für diejenigen, die zum ersten Mal einen Antrag auf Bildklassifizierung stellen.

Übrigens bin ich derzeit in der 5. Klasse der Fakultät für Zahnmedizin und noch kein wirklicher Zahnarzt. .. ..

Ergebnisse

ファイル名

Wenn ich ein Bild meiner Zunge hochlade ...

ファイル名

Der Schmutzgrad auf der Zunge wird in 3 Stufen beurteilt. Übrigens wird es ein wenig Wissen über schlechten Geruch zurückgeben. Ich hoffe, Sie können das schlechte Verhalten und den mangelnden Sinn für Design übersehen. .. ..

Tanpic:https://tanpic-b86b4.firebaseapp.com/

Datensammlung

In dieser Phase haben wir Folgendes getan:

  1. Sammeln Sie Bilder mit icrawler
  2. Beseitigung unnötiger Bilder
  3. Trimmen
  4. In 3 Stufen entsprechend dem Schmutzgrad auf der Zunge beschriften

Bilddaten wurden mit icrowler gesammelt. Weitere Informationen finden Sie im Dokument.

Referenz: icrawler-Dokumentation

Nachdem unnötige Bilder entfernt wurden, wird nur die Zunge einzeln manuell zugeschnitten. Danach wurde der Schmutzgrad auf der Zunge in drei eingeteilt.

Schmutzgrad 1 (Markenname: Zunge0) スクリーンショット 2019-11-01 19.11.49.png

Schmutzgrad 2 (Markenname: Zunge1) スクリーンショット 2019-11-01 19.14.19.png

Schmutzgrad 3 (Markenname: Zunge2) ファイル名

Die Verarbeitung der Daten war zeitaufwändig und mühsam und ziemlich schwierig

Lernen

Ich habe Google Cola Bratoly GPU zum Lernen verwendet.

Speichern Sie das Modell nach dem Aufblasen der gesammelten Bilder und dem Training als Zunge_cnn_aug.h5. Ich werde die Details weglassen.

Test Accuracy

image.png

Es war 66,66%.

Zusammenarbeit mit der Flasche

Hier ist eine kurze Zusammenfassung unserer Aktivitäten.

  1. Modell laden
  2. Konvertieren Sie das Bild mit RGB in 3 Farben
  3. Ändern Sie die Bildgröße auf 50 * 50
  4. Konvertieren Sie das Bild in ein Numpy Array
  5. Übergeben Sie das Bild an das Modell und sagen Sie es voraus
  6. Geben Sie den vorhergesagten Beschriftungswert mit der Funktion argmax zurück
  7. Übergeben Sie den Beschriftungswert mit der Funktion render_template an die HTML-Datei

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 = "Es ist 1."
class_content_1 = "Es ist fast kein Zungenmoos darauf und es scheint in einem ziemlich schönen Zustand zu sein."
classes_solution_1 = "Lassen Sie uns nach wie vor unser Bestes in der Mundpflege geben. Als Vorsichtsmaßnahme wird eine übermäßige Reinigung der Zunge nicht nur die Zunge verletzen, sondern auch die Menge des anhaftenden Zungenmoos erhöhen. Tun Sie dies daher einmal am Tag vorsichtig."

class_2 = "Es ist 2."
class_content_2 = "Sie müssen sich keine Sorgen um Schmutz auf Ihrer Zunge machen."
classes_solution_2 = "Schmutzige Zunge(Zungenmoos)Kann schlechten Geruch verursachen. Wenn Sie sich darüber Sorgen machen, ist es eine gute Idee, Ihre Zunge einmal täglich sanft zu reinigen. Darüber hinaus ist der Mundgeruch in den Abendstunden bei geringer Speichelproduktion tendenziell stärker. Achten Sie darauf, zu gurgeln und zu rehydrieren, um Maßnahmen zu ergreifen."

class_3 = "Es ist 3."
class_content_3 = "Möglicherweise befindet sich etwas Schmutz auf Ihrer Zunge. Zungenmoos (Schmutz auf der Zunge) kann auch schlechte Gerüche verursachen. Daher ist es ratsam, die Zunge zusätzlich zum üblichen Bürsten zu reinigen."
classes_solution_3 = "Verwenden Sie zum Reinigen des Zungenmoos Gaze oder eine Zungenbürste und reiben Sie die Oberfläche der Zunge vorsichtig von hinten nach vorne. Mach es nur einmal am Tag."

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):
    #wenn.が含まれたる かつ wenn拡張子前の.Getrennt durch, true, wenn die Erweiterung niedriger oder niedriger ist
    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']  #hinzufügen
            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="Analyseergebnis",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">

        <!--Bootstrap CSS wird geladen-->
        <link rel="stylesheet" href="/static/css/bootstrap.min.css">

        <!--manifest.Json wird geladen-->
        <!--<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>Setzen Sie ein Bild von Ihrer Zunge</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 %}
Es gibt 3 Schmutzstufen auf Ihrer Zunge{{ 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="/">Rückkehr</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>

        <!--Bootstrap JS wird geladen-->
        <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>

Funktioniert mit Firebase Cloud Storage

Ich habe mich für Firebase Cloud Storage entschieden, um die hochgeladenen Bilder zu sammeln.

Referenzartikel: [Eine Anwendung zum Hochladen von Bildern in Firebase Cloud Storage implementiert](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){

    //Verarbeitung, wenn ein Bild gesendet wird, ohne hochgeladen zu werden
    if($('#myfile').val()===""){
      $('#error').text("Bitte wählen Sie die Datei");
      e.preventDefault();
    }

    //Prozess des Hochladens in den Cloud-Speicher
    var uploadRef = storage.ref().child(file_name);
    uploadRef.put(blob).then(snapshot => {
      console.log(snapshot.state);
    });
    //Wert zurückgesetzt
    file_name = '';
    blob = '';

  });

Als ich den Konsolenbildschirm überprüfte, wurde das Bild fest gespeichert. Es war praktisch, weil es sehr einfach zu implementieren war.

In Heroku bereitstellen

Ich habe es unter Bezugnahme auf den folgenden Artikel für Heroku bereitgestellt.

Referenz: Qiita Flask Tutorial + Bereitstellen auf Heroku

Führen Sie nach dem Anmelden bei Heroku die folgenden Schritte aus, um ein Commit durchzuführen.

$ git add .
$ git commit
$ git push heroku master

Ich bin auf einen R14-Fehler gestoßen, weil der Speicher während des Git Push Heroku Masters nicht ausreicht. Beim Free-Plan liegt die obere Speichergrenze bei 512 MB, und es scheint, dass ein R14-Fehler aufgetreten ist, weil er diesen überschritten hat. Die Lösung bestand darin, ein kleineres Modell zu verwenden und die Speichernutzung unter der Obergrenze zu halten.

Referenz: Was tun, wenn in Qiita Heroku ein R14 / R15-Fehler auftritt?

Quellcode

github:https://github.com/salmon0511/TongueCoatingClassificationApp

Impressionen

Es hat Spaß gemacht, es unter Bezugnahme auf verschiedene Artikel umzusetzen, um die Idee zu verwirklichen. Ich war auch beeindruckt, als ich viele Fehler überwinden und bereitstellen konnte.

Die Lesbarkeit war mir jedoch egal (um genau zu sein, ich weiß immer noch nicht, welcher Code gut lesbar ist), daher möchte ich versuchen, Code zu schreiben, der von nun an leicht zu lesen ist.

Referenz

Erstellen Sie eine handschriftliche Zeichenerkennungsanwendung mit Flask + Keras

Recommended Posts

Ein Zahnarzt (!?) Erstellt eine App zur Beurteilung der Zungenmoosmenge mit Flasche + Keras
Erstellen Sie eine einfache Web-App mit Flasche
Stellen Sie eine mit Streamlit erstellte Web-App für Heroku bereit
So stellen Sie eine mit Flask erstellte Web-App für Heroku bereit
Erstellt ein Lesebuch mit PostgreSQL mit Flask
(Fehler) Stellen Sie eine mit Flask mit Heroku erstellte Web-App bereit
Erstellen eines Flask-Servers mit Docker
Führen Sie die App mit Flask + Heroku aus
Erstellt eine neue Corona-App in Kyoto mit Pythons Webframework Dash