Im vorherigen Artikel (https://qiita.com/IchiLab/items/fd99bcd92670607f8f9b) haben wir die Verwendung der von TensorFlow bereitgestellten Objekterkennungs-API zusammengefasst. Um diese API zu verwenden, um "dieses Objekt ist XX" aus Bildern und Videos zu lehren, Kommentieren und in das TFRecord-Format konvertieren, Es wird als Lehrerdaten und Verifizierungsdaten verwendet. Ich bin der Meinung, dass es noch wenige Artikel gibt, in denen der spezifische Inhalt dieses TFRecord-Formats erwähnt wird.
In diesem Artikel beginnen wir mit einer Methode, die ohne Programmierung erstellt werden kann. Wir werden aus verschiedenen Blickwinkeln zusammenfassen, einschließlich des Schreibens und Erstellens von Python-Code. Natürlich fasse ich nur die Ergebnisse zusammen, die ich durch Versuch und Irrtum gefunden habe. Bitte beachten Sie, dass einige Teile möglicherweise nicht erreichbar sind.
--Verfahren zum Erstellen einer TFRecord-Datei auf Microsoft VoTT ――Welche Art von Datei ist TFRecord?
Lassen Sie uns von der folgenden Seite herunterladen. Wählen Sie ".exe", wenn das Betriebssystem Windows ist, oder ".dmg", wenn das Betriebssystem Mac ist. VoTT
Erstellen Sie zunächst ein neues Projekt mit "Neues Projekt".
Stellen Sie das Projekt ein.
Anzeigename
: Bitte verwenden Sie einen beliebigen Namen.Sicherheitstoken
: Standardmäßig OK.Quellverbindung
: Legt den Namen des Ortes fest, an dem das Bild gelesen werden sollZielverbindung
: Der Einstellungsname des Speicherorts, an dem das Projekt gespeichert wird. .vott
, .json
und TFRecord werden in dem hier angegebenen Verzeichnis gespeichert.Wenn VoTT jedes Verzeichnis angibt, werden die Einstellungsinformationen wie der Speicherort des Ordners mit "Verbindung hinzufügen" gespeichert. Im Element "~ Verbindung" wird der Einstellungsname angegeben. Wenn Sie es zum ersten Mal verwenden, erstellen Sie daher zunächst die Einstellung mit "Verbindung hinzufügen" auf der rechten Seite.
Stellen Sie das Verzeichnis ein.
Wählen Sie abschließend "Verbindung speichern".
Nach dem Einstellen von "Quellverbindung" bzw. "Zielverbindung" ist der nächste Schritt die Anmerkungsarbeit.
Die Annotation kann in der Sekunde von oben links (unterhalb der Hausmarke) erfolgen. (Das Foto zeigt meine Katzen Mimi und Kitty)
Setzen Sie zuerst das Tag. Auf der rechten Seite steht TAGS, daneben befindet sich ein + -Symbol. Wenn Sie dies auswählen, können Sie ein neues Tag festlegen. Dieses Mal habe ich den Namen meiner Katze als "Mimmy" und "Kitty" festgelegt.
Wählen Sie dann das zweite quadratische Symbol links oben aus. Ziehen Sie dann den Ort, den Sie mit Anmerkungen versehen möchten, und legen Sie ihn bei.
Es kann sich zum Zeitpunkt des Einschließens um ein graues Quadrat handeln. Wenn Sie zum Zeitpunkt des Einfügens einen beliebigen Tag-Namen angeben möchten, nachdem Sie den Tag-Namen auf der rechten Seite ausgewählt haben, Wenn Sie ein Symbol wie eine Sperrmarke auswählen und "Ich werde es mit diesem festen Tag anhängen" einstellen, Der Tag-Name wird automatisch angegeben, wenn Sie ihn mit Anmerkungen versehen. (Auf einem Mac können Sie den gleichen Vorgang ausführen, indem Sie die Befehlstaste gedrückt halten und auf den Tag-Namen klicken. Strg-Taste in Windows ...? Unbestätigt)
Sie können es auch an einem Quadrat befestigen, indem Sie beim Kommentieren die Umschalttaste drücken. Es ist eine gute Idee, sich durch Berühren an diesen Bereich zu gewöhnen.
Um einen TFRecord zu generieren, muss dieser in den Exporteinstellungen im Voraus festgelegt werden. Wählen Sie das vierte Pfeilsymbol oben im Menüsymbol links aus.
Wählen Sie nach Abschluss der Einstellungen "Exporteinstellungen speichern", um die Einstellungen zu speichern.
Kehren Sie danach zum Anmerkungsbildschirm zurück, speichern Sie das Projekt mit dem Diskettensymbol oben rechts und exportieren Sie das Format (diesmal TFRecord), das mit dem Symbol des Pfeils oben rechts festgelegt wurde. Übrigens wird die JSON-Datei beim Speichern ohne Erlaubnis erstellt, auch wenn Sie nichts festlegen.
Das obige Verfahren wird zum Erstellen einer TFRecord-Datei mit VoTT erstellt.
Das nächste ist das Hauptthema dieses Artikels.
Was ist TFRecord überhaupt?
Ein Auszug aus dem offiziellen TensorFlow-Tutorial sagt:
Das TFRecord-Format ist ein einfaches Format zum Speichern einer Reihe von Binärdatensätzen. Protokollpuffer sind plattform- und sprachunabhängige Bibliotheken, die strukturierte Daten effizient serialisieren.
Referenz) Verwendung von TFRecords und tf.Beispiel
Nur das zu lesen, fällt mir nicht ein. Schauen wir uns nun den Inhalt des TFRecord an, der zuvor mit VoTT exportiert wurde.
Der Inhalt von TFRecord kann mit den folgenden Quellen visualisiert werden.
from __future__ import absolute_import, division, print_function, unicode_literals
import tensorflow as tf
import numpy as np
import IPython.display as display
#Geben Sie den Pfad von TFRecord an
filenames = 'VoTT/Cat/Cat-TFRecords-export/Mimmy_and_Kitty.tfrecord'
raw_dataset = tf.data.TFRecordDataset(filenames)
#Exportieren Sie den gelesenen Inhalt in ein anderes Format
# (.Es kann txt sein. Bei json hängt es vom Editor ab, aber es ist farbig und leichter zu sehen, daher wird es über txt empfohlen.
tfr_data = 'tfr.json'
for raw_record in raw_dataset.take(1):
example = tf.train.Example()
example.ParseFromString(raw_record.numpy())
print(example)
#In eine Datei schreiben. Dies ist nicht unbedingt erforderlich, da Sie es auf der Konsole sehen können, ohne es zu exportieren.
with open(tfr_data, 'w') as f:
print(example, file=f)
Werfen wir einen Blick auf die aus der obigen Quelle exportierte Datei.
features {
feature {
key: "image/encoded"
value {
bytes_list {
value: "\377\330\377...
.....(Da es sich um eine große Menge handelt, wird sie weggelassen.)..."
}
}
}
feature {
key: "image/filename"
value {
bytes_list {
value: "Mimmy_and_Kitty.jpg "
}
}
}
feature {
key: "image/format"
value {
bytes_list {
value: "jpg"
}
}
}
feature {
key: "image/height"
value {
int64_list {
value: 1440
}
}
}
feature {
key: "image/key/sha256"
value {
bytes_list {
value: "TqXFCKZWbnYkBUP4/rBv1Fd3e+OVScQBZDav2mXSMw4="
}
}
}
feature {
key: "image/object/bbox/xmax"
value {
float_list {
value: 0.48301976919174194
value: 0.7260425686836243
}
}
}
feature {
key: "image/object/bbox/xmin"
value {
float_list {
value: 0.3009025752544403
value: 0.5285395383834839
}
}
}
feature {
key: "image/object/bbox/ymax"
value {
float_list {
value: 0.6981713175773621
value: 0.8886410593986511
}
}
}
feature {
key: "image/object/bbox/ymin"
value {
float_list {
value: 0.3555919826030731
value: 0.5664308667182922
}
}
}
feature {
key: "image/object/class/label"
value {
int64_list {
value: 0
value: 1
}
}
}
feature {
key: "image/object/class/text"
value {
bytes_list {
value: "Mimmy"
value: "Kitty"
}
}
}
feature {
key: "image/width"
value {
int64_list {
value: 2560
}
}
}
}
Andere Schlüssel wie "schwierig", "abgeschnitten", "Ansicht", "Quell-ID" sind enthalten, Hier habe ich nur die Inhalte extrahiert, die ich für notwendig halte. Wenn Sie den Inhalt überprüfen, können Sie sehen, dass er die folgende Struktur hat.
image / encoded
: Binärdaten des BildesBild / Breite
, Bild / Höhe
: Bildgrößexmin
, xmax
, ymin
, ymax
: Kommentierte Koordinateninformationen. Es wird nur die Anzahl der mit Anmerkungen versehenen Werte berücksichtigt.class / text
, class / label
: Tag-Informationen. Text ist der Name des Tags, und die Nummer auf dem Etikett kann als die Nummer angesehen werden, die dem Tag-Namen zugewiesen ist. In diesem Fall ist "Mimmy" 0 und "Kitty" 1.An diesem Punkt haben Sie wahrscheinlich verstanden, aus welcher Struktur TFRecord besteht.
Das Folgende ist eine Methode zum programmgesteuerten Ausschneiden des von VoTT kommentierten Teils. Wenn Sie dies tun können, wenn Sie Ihr eigenes Programm schreiben und eine TFRecord-Datei erstellen, Möglicherweise benötigen Sie eine Idee, um ** das zu erkennende Objekt mit dem Hintergrund zu kombinieren **, wie unten beschrieben. Oder es ist nützlich für das maschinelle Lernen der Bildklassifizierung.
Auch das ist mir aufgefallen, nachdem ich es versucht habe: ** Die Ausrichtung des von VoTT gesehenen Bildes und die Ausrichtung des Bildes beim tatsächlichen Zuschneiden können unterschiedlich sein ** Ich habe herausgefunden, dass.
Mit anderen Worten, das Bild, das Sie auf dem Bildschirm sehen, wenn Sie in VoTT Anmerkungen machen, Dies bedeutet, dass die Ausrichtung des Bildes der Originaldaten beim Ausschneiden mit JSON-Informationen manchmal um 180 Grad unterschiedlich war.
Dank dessen wurde nur ein Bild eines unbeabsichtigten Ortes ausgeschnitten. Ich bin mir nicht sicher, ob dies in TFRecord in der richtigen Ausrichtung kommentiert ist Es kann sicher sein, es einmal anzusehen.
Nun, die Einführung ist lang geworden, aber lassen Sie uns json sofort auf das Zuschneiden von Bildern überprüfen. Sie haben bereits erwähnt, dass json auch automatisch exportiert wird, wenn Sie die Anmerkungsarbeit mit VoTT beenden und exportieren.
Die im Beispiel angegebenen Katzendaten wurden wie folgt geschrieben.
{
"asset": {
"format": "jpg",
"id": "1da8e6914e4ec2e2c2e82694f19d03d5",
"name": "Mimmy_and_Kitty.jpg ",
"path": "【Ordnernamen】/VoTT/Cat/IMAGES/Mimmy_and_Kitty.jpg ",
"size": {
"width": 2560,
"height": 1440
},
"state": 2,
"type": 1
},
"regions": [
{
"id": "kFskTbQ6Z",
"type": "RECTANGLE",
"tags": [
"Mimmy"
],
"boundingBox": {
"height": 493.3142744479496,
"width": 466.2200532386868,
"left": 770.3105590062112,
"top": 512.0524447949527
},
"points": [
{
"x": 770.3105590062112,
"y": 512.0524447949527
},
{
"x": 1236.5306122448978,
"y": 512.0524447949527
},
{
"x": 1236.5306122448978,
"y": 1005.3667192429023
},
{
"x": 770.3105590062112,
"y": 1005.3667192429023
}
]
},
],
"version": "2.1.0"
}
(Die Informationen auf dem anderen Kitty-Tag werden weggelassen, da sie lang sind, wenn sie platziert werden.)
Wie Sie sehen können, enthält es den Dateinamen, die Bildgröße und sogar die mit Anmerkungen versehenen Koordinateninformationen. Es ist durchaus möglich, ein Bild nur mit diesen Informationen auszuschneiden.
Die mit Anmerkungen versehenen Koordinateninformationen sind sorgfältig in zwei Typen enthalten: "BoundingBox" und "Punkte". Es scheint verschiedene Möglichkeiten zu geben, aber diesmal habe ich mir die "BoundingBox" angesehen und versucht, sie auszuschneiden. Unten ist der Quellcode.
import json
import os
import fnmatch
import cv2 as cv
JSON_DIR = 'VoTT/Cat/'
IMG_DIR = 'VoTT/Cat/'
CUT_IMAGE = 'cut_images/'
CUT_IMAGE_NAME = 'cat'
IMAGE_FORMAT = '.jpg'
class Check():
def filepath_checker(self, dir):
if not (os.path.exists(dir)):
print('No such directory > ' + dir)
exit()
def directory_init(self, dir):
if not(os.path.exists(dir)) :
os.makedirs(dir, exist_ok=True)
def main():
check = Check()
#Überprüfen Sie, ob das Verzeichnis mit der JSON-Datei vorhanden ist
check.filepath_checker(JSON_DIR)
#'Bereiten Sie einen Speicherort für das CUT-Image vor'
check.directory_init(CUT_IMAGE)
#Analysieren Sie json und schneiden Sie es aus Bild- und Anmerkungskoordinaten aus
count = 0
for jsonName in fnmatch.filter(os.listdir(JSON_DIR), '*.json'):
#Öffnen Sie json
with open(JSON_DIR + jsonName) as f :
result = json.load(f)
#Bilddateinamen abrufen
imgName = result['asset']['name']
print('jsonName = {}, imgName = {} '.format(jsonName, imgName))
img = cv.imread(IMG_DIR + imgName)
if img is None:
print('cv.imread Error')
exit()
#Schleife so viele wie kommentiert
for region in result['regions'] :
height = int(region['boundingBox']['height'])
width = int(region['boundingBox']['width'])
left = int(region['boundingBox']['left'])
top = int(region['boundingBox']['top'])
cutImage = img[top: top + height, left: left + width]
#Vermeiden Sie Informationen, die Sie während der Anmerkung versehentlich auf einen Punkt geklickt haben
if height == 0 or width == 0:
print('<height or width is 0> imgName = ', imgName)
continue
#Wenn Sie vor dem Export die Größe ändern möchten, kommentieren Sie
#cutImage = cv.resize(cutImage, (300,300))
#「cut_images/cat0000.Exportieren Sie Dateien mit Seriennummern wie "jpg".
cv.imwrite(CUT_IMAGE + CUT_IMAGE_NAME + "{0:04d}".format(count + 1) + IMAGE_FORMAT, cutImage)
print("{0:04d}".format(count+1))
count += 1
if __name__ == "__main__":
main()
Der Grund, warum es im Quellcode eine bedingte Verzweigung von "wenn Höhe == 0 oder Breite == 0" gibt, ist Der Teil, auf den während der Annotation mit VoTT versehentlich geklickt wurde, bleibt als Daten erhalten. Weil ein Fehler aufgetreten ist, weil kein Bereich zum Ausschneiden vorhanden war Ich habe versucht, es aufzunehmen, um das menschliche Versagen zu vermeiden.
In meinem Fall musste also viel auf einem Blatt kommentiert werden Es wurde immer schwieriger, dies zu bemerken. Dies gilt umso mehr, wenn eine große Menge an Bilddaten vorhanden ist.
Nun, es ist lange her, aber lassen Sie uns von nun an ein Programm schreiben, um TFRecord zu erstellen.
Jetzt haben Sie eine ungefähre Vorstellung von der Zusammensetzung des Inhalts von TFRecord Zum Schluss schreiben wir den Quellcode und generieren TFRecord.
Was wir mit der diesmal veröffentlichten Quelle machen, ist wie folgt.
Zunächst wurde das Hintergrundbild von der Materialseite ausgeliehen. es ist hier.
Und hier ist das zu kombinierende Objektbild.
Unten ist der Quellcode.
import tensorflow as tf
import cv2 as cv
import utils.dataset_util as dataset_util
def img_composition(bg, obj, left, top):
"""
Funktion, die Hintergrund und Objekt synthetisiert
----------
bg : numpy.ndarray ~ Hintergrundbild
obj : numpy.ndarray ~ Objektbild
left :int ~ Zu kombinierende Koordinaten (links)
top :int ~ Zu kombinierende Koordinaten (oben)
"""
bg_img = bg.copy()
obj_img = obj.copy()
bg_h, bg_w = bg_img.shape[:2]
obj_h, obj_w = obj_img.shape[:2]
roi = bg_img[top:top + obj_h, left:left + obj_w]
mask = obj_img[:, :, 3]
ret, mask_inv = cv.threshold(cv.bitwise_not(mask), 200, 255, cv.THRESH_BINARY)
img1_bg = cv.bitwise_and(roi, roi, mask=mask_inv)
img2_obj = cv.bitwise_and(obj_img, obj_img, mask=mask)
dst = cv.add(img1_bg, img2_obj)
bg_img[top: obj_h + top, left: obj_w + left] = dst
return bg_img
def set_feature(image_string, label, label_txt, xmins, xmaxs, ymins, ymaxs):
"""
Funktion zum Einstellen der Informationen, die in TFRecord geschrieben werden sollen
Um diese Funktion zu verwenden, befindet sie sich im Verzeichnis "Objekterkennung" der TensorFlow-Objekterkennungs-API.
Sie müssen die "util" -Bibliothek einbringen
----------
image_string :Bytes ~ Kombinierte Bildinformationen
label :Liste ~ Kommentierte Tag-Nummer
label_txt :list ~ Kommentierter Tag-Name
xmins, xmaxs, ymins, ymaxs :liste ~ 0 kommentierte Koordinaten auf.0~1.Wert dargestellt durch 0
"""
image_shape = tf.io.decode_jpeg(image_string).shape
feature = {
'image/encoded': dataset_util.bytes_feature(image_string),
'image/format': dataset_util.bytes_feature('jpg'.encode('utf8')),
'image/height': dataset_util.int64_feature(image_shape[0]),
'image/width': dataset_util.int64_feature(image_shape[1]),
'image/object/bbox/xmin': dataset_util.float_list_feature(xmins),
'image/object/bbox/xmax': dataset_util.float_list_feature(xmaxs),
'image/object/bbox/ymin': dataset_util.float_list_feature(ymins),
'image/object/bbox/ymax': dataset_util.float_list_feature(ymaxs),
#Wenn Sie nur eine Information geben möchten, können Sie diese auskommentierte Funktion verwenden (Typen stimmen überein)
# 'image/object/class/label': dataset_util.int64_feature(label),
# 'image/object/class/text': dataset_util.bytes_feature(LABEL.encode('utf8')),
#Wenn Sie zwei oder mehr auf einem Blatt markieren möchten, klicken Sie auf "_list_Verwenden Sie eine Funktion, die "" enthält
#Natürlich können Sie nur eine verwenden, daher wird empfohlen, diese zu verwenden
'image/object/class/label': dataset_util.int64_list_feature(label),
'image/object/class/text': dataset_util.bytes_list_feature(label_txt),
}
return tf.train.Example(features=tf.train.Features(feature=feature))
def main():
#Jeder Dateipfadname
bg_image_path = './comp/bg.jpg'
obj_img_path = './comp/Mimmy_image.png'
comp_img_path = './comp/img_comp.jpg'
tfr_filename = './mimmy.tfrecord'
#Für TF Record
tag = {'Mimmy': 0, 'Kitty': 1, 'Mimelo': 2}
xmins = []
xmaxs = []
ymins = []
ymaxs = []
class_label_list = []
class_text_list = []
datas = {}
#Einstellung des Beschriftungsnamens
class_label = tag['Mimmy']
#Hintergrund laden
bg_img = cv.imread(bg_image_path, -1)
bg_img = cv.cvtColor(bg_img, cv.COLOR_RGB2RGBA)
bg_h, bg_w = bg_img.shape[:2]
#Laden eines Objekts
obj_img = cv.imread(obj_img_path, -1)
obj_img = cv.cvtColor(obj_img, cv.COLOR_RGB2RGBA)
scale = 250 / obj_img.shape[1]
obj_img = cv.resize(obj_img, dsize=None, fx=scale, fy=scale)
obj_h, obj_w = obj_img.shape[:2]
#Kombinieren Sie Hintergrund und Objekt
x = int(bg_w * 0.45) - int(obj_w / 2)
y = int(bg_h * 0.89) - int(obj_h / 2)
comp_img = img_composition(bg_img, obj_img, x, y)
#Verbundbild exportieren
cv.imwrite(comp_img_path, comp_img)
#Zur TFRecord-Koordinateninformationsliste hinzugefügt
xmins.append(x / bg_w)
xmaxs.append((x + obj_w) / bg_w)
ymins.append(y / bg_h)
ymaxs.append((y + obj_h) / bg_h)
#Etiketteninformationen für TFRecord hinzugefügt
class_label_list.append(class_label)
class_text_list.append('Mimmy'.encode('utf8'))
datas[comp_img_path] = class_label
#Prozess zum Erstellen von TFRecord
with tf.io.TFRecordWriter(tfr_filename) as writer:
for data in datas.keys():
image_string = open(data, 'rb').read()
tf_example = set_feature(image_string, class_label_list, class_text_list, xmins, xmaxs, ymins, ymaxs)
writer.write(tf_example.SerializeToString())
if __name__ == "__main__":
main()
Hier ist das Bild, das nach dem Ausführen des Programms erstellt wurde.
Wie in den Kommentaren im Quellcode erwähnt, beachten Sie bitte, dass die in der TensorFlow-Objekterkennungs-API enthaltene Bibliothek erforderlich ist.
Zur Erklärung habe ich dieses Mal ein Bild zum Zusammensetzen und den Quellcode zum Generieren einer TFRecord-Datei eingeführt. In Wirklichkeit denke ich jedoch, dass es notwendig ist, eine große Anzahl von TFRecord-Dateien aus viel mehr Bildern zu generieren.
In meinem Fall, wie man Bilder aus dem angegebenen Ordner zufällig auswählt und kombiniert, Ich habe eine Methode der Massenproduktion ausprobiert, indem ich die Koordinaten ein wenig zufällig kombiniert habe.
Wenn Sie in diesem Artikel verschiedene Tipps für die Massenproduktion von Lehrerdaten finden, würde ich gerne von Ihnen hören.
Nur für den Fall, dass der Inhalt der TFRecord-Datei, die ich gerade erstellt habe, Lassen Sie uns mit der in der ersten Hälfte eingeführten Methode überprüfen.
features {
feature {
key: "image/encoded"
value {
bytes_list {
value: "\377\330\377...
.....(Da es sich um eine große Menge handelt, wird sie weggelassen.)..."
}
}
}
feature {
key: "image/format"
value {
bytes_list {
value: "jpg"
}
}
}
feature {
key: "image/height"
value {
int64_list {
value: 1397
}
}
}
feature {
key: "image/object/bbox/xmax"
value {
float_list {
value: 0.5151041746139526
}
}
}
feature {
key: "image/object/bbox/xmin"
value {
float_list {
value: 0.38489583134651184
}
}
}
feature {
key: "image/object/bbox/ymax"
value {
float_list {
value: 0.9878310561180115
}
}
}
feature {
key: "image/object/bbox/ymin"
value {
float_list {
value: 0.7916964888572693
}
}
}
feature {
key: "image/object/class/label"
value {
int64_list {
value: 0
}
}
}
feature {
key: "image/object/class/text"
value {
bytes_list {
value: "Mimmy"
}
}
}
feature {
key: "image/width"
value {
int64_list {
value: 1920
}
}
}
}
Wie oben erwähnt, müssen Sie es nur einmal tun, also überprüfen Sie den Inhalt richtig und Wenn es der beabsichtigte Wert ist, gibt es kein Problem!
Für Daten im TFRecord-Format, die für die Objekterkennung in TensorFlow nützlich sind Es war ein langer Artikel, aber ich habe ihn zusammengefasst, soweit ich verstehen kann.
Wir hoffen, dass dieser Artikel den Bereich der Lehrerdatenerstellung erweitert. Vielen Dank für das Lesen bis zum Ende.
Recommended Posts