Einführung
- Möglicherweise müssen Bilder für maschinelles Lernen gesammelt und visuell sortiert werden.
――Auf dem Mac löschen Sie wiederholt, während Sie das Bild im Finder betrachten. Dies ist eine entmutigende Aufgabe.
――Dieses Mal habe ich eine einfache Verwaltungsanwendung erstellt, die auf einem Webbrowser basiert.
- Die vollständige Quelle ist hier.
Überblick
- Auf der "oberen Seite" wird jedes Menü basierend auf "KLASSEN" in "config.py" angezeigt.
――Sie können sowohl mit "Bild herunterladen als auch mit Gesichtsbild" vergleichen.
—— Sie können auch auf das Gesichtsbild klicken, um alles auf einmal zu löschen.
- Das "Vorhersageergebnis des Trainingsbildes" und das "Vorhersageergebnis des Testbildes" werden getrennt angegeben.
oberste Seite
Bild und Gesichtsbild herunterladen
Bibliothek
- Ich benutze "Flask".
- "Kissen" wird verwendet, um das Bild zu skalieren.
- Ich benutze
Bootstrap
.
- Ein spezielles Symbol wird mit "Font Awesome" angezeigt. Dieses Mal verwende ich es mit dem Papierkorbsymbol oben rechts im Gesichtsbild.
oberste Seite
- Auf der oberen Seite wird der Inhalt von
index.html
fast so angezeigt, wie er ist.
--CLASSES
in config.py
wird als items
in index.html
übergeben.
- Die Farbe wird mit "Bootstrap" geändert, um jedes Menü zu identifizieren.
image_viewer.py
@app.route('/')
def index():
"""Top Page."""
return render_template('index.html', items=CLASSES)
templates/index.html
<div class="container-fluid">
{% for item in items %}
<div class="row">
<div class="col">
{{ loop.index }} {{ item }}
</div>
<div class="col-11">
<a class="btn btn-primary" href="/download_and_face/{{ item }}" role="button">Bild herunterladen, Gesichtsbild</a>
<a class="btn btn-secondary" href="/predict/train/{{ item }}" role="button">Vorhersageergebnis des Trainingsbildes</a>
<a class="btn btn-success" href="/predict/test/{{ item }}" role="button">Vorhersageergebnis des Testbildes</a>
</div>
</div>
<br />
{% endfor %}
</div>
Bild und Gesichtsbild herunterladen
- Unter "DOWNLOAD_PATH" werden Bilder gespeichert, die von der benutzerdefinierten Google-Suche usw. heruntergeladen wurden.
--Beispiel: data / download / Abe Otsu / 0001.jpeg
- Unter "FACE_PATH" wird das mit "Haar Cascade" von "OpenCV" erkannte Bild gespeichert.
- Außerdem wird der Dateiname basierend auf dem Dateinamen des heruntergeladenen Bildes generiert.
- Beispiel: data / face / Abe Otsu / 0001-0001.jpeg
GET-Verarbeitung
- Erhalten Sie "Abe Otsu" usw. mit "Gegenstand".
--Erstellen Sie eine Liste der heruntergeladenen Bilder mit
DOWNLOAD_PATH`` item`` * .jpeg
als Schlüssel.
--Erstellen Sie eine Liste mit Gesichtsbildern mit FACE_PATH`` item`` * .jpeg
als Schlüssel.
image_viewer.py
@app.route('/download_and_face/<item>', methods=['GET', 'POST'])
def download_and_face(item):
"""Bild herunterladen, Gesichtsbild."""
download_list = glob.glob(os.path.join(DOWNLOAD_PATH, item, '*.jpeg'))
download_list = sorted([os.path.basename(filename) for filename in download_list])
face_list = glob.glob(os.path.join(FACE_PATH, item, '*.jpeg'))
face_list = sorted([os.path.basename(filename) for filename in face_list])
- Aus dem heruntergeladenen Bild wird ein Suchschlüssel für ein Gesichtsbild erstellt und eine Array-Zeile erstellt.
- Die Kombination aus jedem heruntergeladenen Bild und Gesichtsbild wird in "Zeilen" gespeichert.
--Pass
item
und rows
an die Template Engine.
image_viewer.py
rows = []
for download in download_list:
row = [download]
key = download.split('.')[0] + '-'
for face in face_list:
if face.startswith(key):
row.append(face)
rows.append(row)
return render_template('download_and_face.html', item=item, rows=rows)
- Die Vorlage zeigt die Kombination aus dem heruntergeladenen Bild und dem Gesichtsbild in einer Zeile an.
--Erstellen Sie eine Verknüpfung zwischen dem heruntergeladenen Bild und dem Gesichtsbild.
- Die Größe des Bildes wird durch "Größe = 200" angegeben. Diese Größe ist die vertikale Größe des Bildes.
――Durch die Größenanpassung ist es einfacher, das heruntergeladene Bild und das Gesichtsbild zu vergleichen.
- Im Gesichtsbild werden "CSS" und "JS" verwendet, damit es einfach durch Klicken angegeben werden kann.
»Hier habe ich mich auf Folgendes bezogen.
templates/download_and_face.html
<tbody>
{% for row in rows %}
<tr>
<td>
{{ loop.index }}
</td>
<td>
<figure class="figure">
<img src="/data/download/{{ item }}/{{ row[0] }}?size=200" />
<figcaption class="figure-caption">{{ row[0] }}</figcaption>
</figure>
</td>
<td>
{% for filename in row[1:] %}
<figure class="figure">
<label class="image-checkbox">
<img src="/data/face/{{ item }}/{{ filename }}?size=200" />
<input type="checkbox" name="filename" value="{{ filename }}" />
<i class="fa fa-trash-o d-none"></i>
</label>
<figcaption class="figure-caption">{{ filename }}</figcaption>
</figure>
{% endfor %}
</td>
</tr>
{% endfor %}
</tbody>
- Die Anzeige des Gesichtsbildes wird angepasst, wenn das Kontrollkästchen aktiviert ist und wenn es nicht angegeben ist.
static/download_and_face.css
.image-checkbox {
cursor: pointer;
border: 2px solid transparent;
box-sizing: border-box;
-moz-box-sizing: border-box;
-webkit-box-sizing: border-box;
position: relative;
}
.image-checkbox input[type="checkbox"] {
display: none;
}
.image-checkbox-checked {
border-color: #d9534f;
}
.image-checkbox .fa {
color: #ffffff;
background-color: #d9534f;
font-size: 20px;
padding: 4px;
position: absolute;
right: 0;
top: 0;
}
.image-checkbox-checked .fa {
display: block !important;
}
- Zum Zeitpunkt der ersten Anzeige wird der Status des Kontrollkästchens auf die Klasse gesetzt.
--Auch die Klasse wird beim Klicken geändert.
static/download_and_face.js
// image gallery
// init the state from the input
$(".image-checkbox").each(function () {
if ($(this).find('input[type="checkbox"]').first().attr("checked")) {
$(this).addClass('image-checkbox-checked');
}
else {
$(this).removeClass('image-checkbox-checked');
}
});
// sync the state to the input
$(".image-checkbox").on("click", function (e) {
$(this).toggleClass('image-checkbox-checked');
var $checkbox = $(this).find('input[type="checkbox"]');
$checkbox.prop("checked",!$checkbox.prop("checked"))
e.preventDefault();
});
Bildgröße anpassen
- Generieren Sie den Pfad des heruntergeladenen Bildes und des Gesichtsbilds.
image_viewer.py
@app.route('/data/<folder>/<item>/<filename>')
def get_image(folder, item, filename):
"""Skalieren Sie mit der Bildantwortgröße."""
if folder not in ['download', 'face']:
abort(404)
filename = os.path.join(DATA_PATH, folder, item, filename)
- Verwenden Sie
Pillow
, um das Bild zu laden.
image_viewer.py
try:
image = Image.open(filename)
except Exception as err:
pprint.pprint(err)
abort(404)
- Wenn die URL-Option eine "Größe" enthält, ändern Sie die Größe des Bildes.
――In diesem Fall wird das Bild basierend auf der vertikalen Größe skaliert.
――Durch Ausrichten der vertikalen Größe mit dem heruntergeladenen Bild und dem Gesichtsbild ist ein visueller Vergleich einfacher.
- Sie können die Größe von "Kissen" auch mit "Miniaturbild" ändern.
――Das Seitenverhältnis ändert sich hier jedoch.
image_viewer.py
if 'size' in request.args:
height = int(request.args.get('size'))
width = int(image.size[0] * height / image.size[1])
image = image.resize((width, height), Image.LANCZOS)
- Konvertieren Sie schließlich die "Pillow" -Daten in Byte-Daten und erstellen Sie eine Antwort mit "image / jpeg".
image_viewer.py
data = io.BytesIO()
image.save(data, 'jpeg', optimize=True, quality=95)
response = make_response()
response.data = data.getvalue()
response.mimetype = 'image/jpeg'
return response
Nachbearbeitung
- Der Dateiname des Gesichtsbildes, das im Formular gelöscht werden soll, ist POST.
--Überprüfen Sie das Zielgesichtsbild und löschen Sie es mit
os.remove
.
――Ich denke, dass hier ein vorsichtigerer Mechanismus erforderlich ist, aber es ist eine einfache Form unter der Annahme, dass er von Einzelpersonen verwendet wird.
image_viewer.py
@app.route('/download_and_face/<item>', methods=['GET', 'POST'])
def download_and_face(item):
"""Bild herunterladen, Gesichtsbild."""
if request.method == 'POST' and request.form.get('action') == 'delete':
for filename in request.form.getlist('filename'):
filename = os.path.join(FACE_PATH, item, filename)
if os.path.isfile(filename):
os.remove(filename)
print('delete face image: {}'.format(filename))
abschließend
- Ich habe eine Webanwendung erstellt, die unnötige Gesichtsbilder löscht, während das heruntergeladene Bild mit dem Gesichtsbild verglichen wird.
――Ich denke, es ist viel bequemer, als das Gesichtsbild mit dem Mac Finder zu löschen.
――Das Erstellen einer Webanwendung dauert einige Zeit und ist gewöhnungsbedürftig.
――Nächstes Mal planen wir, das Gesichtsbild aufzublasen.