[PYTHON] Extrahieren Sie nur den Katzenteil aus dem Katzenbild (Mattierung / Semantig-Segmentierung).

Überblick

Aus dem von PIXTA gesammelten Katzenbild habe ich versucht, mit möglichst geringem Aufwand nur den Katzenteil zu extrahieren.

Vordergrundextraktion

Das Trennen von Vordergrund und Hintergrund vom Bild wird als Mattierung bezeichnet. Es scheint eine Hauptfunktion in Photoshop zu sein, und im Fall von Gimp entspricht die Funktion "Vordergrundextraktion" dieser Funktion. Es scheint, dass das allgemeine Verhalten darin besteht, das Bild in drei Typen zu unterteilen, "Vordergrund", "Hintergrund" und "entweder", und die Grenze durch Betrachten der Bildmerkmale in jedem Bereich zu bestimmen.

Es scheint schwierig zu sein, diesen Prozess zu automatisieren, und im Rahmen meiner Forschung konnte ich nur eine Methode namens Deep Automatic Portrait Matting finden, die nur Personen aus Porträtfotos extrahiert.

Abgesehen davon gab es ein Papier über eine Methode zum automatischen Generieren von Informationen (Trimap), die zum Mattieren verwendet wurden.

Eine automatische Mattierung ist jedoch nicht immer möglich, solange eine entsprechende Trimap generiert werden kann. Tatsächlich gibt es bei der Verarbeitung mit Gimp usw. viele Situationen, in denen die Vordergrund- / Hintergrundbeurteilung nicht als erwartet eingestuft wird und eine Feineinstellung erforderlich ist.

Semantische Segmentierung

Als weiteren Ansatz habe ich die Verwendung der semantischen Segmentierung in Betracht gezogen. Die semantische Segmentierung unterscheidet verschiedene Objekte pixelweise für ein einzelnes Eingabebild.

In dem zuvor geschriebenen Artikel habe ich geschrieben, dass ChainerCV auch die semantische Segmentierung unterstützt, aber das als Vorlernmodell erstellte Modell ist CamVid. Es basiert auf Trainingsdaten, die als Datensatz bezeichnet werden, und unterstützt 11 Klassen wie Himmel, Straße, Auto und Fußgänger. Es gibt keine Informationen über die Katze, mit der ich diesmal umgehen möchte.

Bei der Suche nach anderen Implementierungen und Datensätzen für die semantische Segmentierung wurde Keras-Implementierung von DilatedNet in [PASCAL VOC2011 challange](http: //host.robots.ox) gefunden. Ich verteilte es einschließlich eines trainierten Modells unter Verwendung eines Datensatzes, der auf dem Datensatz .ac.uk / pascal / VOC / voc2012 /) basiert, und entschied mich daher, es dieses Mal zu verwenden.

installieren

Sie können es verwenden, indem Sie den Code klonen, alle Python-Module installieren, die die Abhängigkeiten von require.txt erfüllen, und das Pre-Learning-Modell herunterladen. Da wir das alte Keras- und TensorFlow-Backend (0.12.1) verwenden werden, ist es eine gute Idee, eine dedizierte virtuelle Umgebung zu haben.

$ pip install -r requirements.txt
$ curl -L https://github.com/nicolov/segmentation_keras/releases/download/model/nicolov_segmentation_model.tar.gz \
 | tar xvf -
$ python predict.py --weights_path \ 
 conversion/converted/dilation8_pascal_voc.npy \
 images/cat.jpg

dilation8_pascal_voc.npy ist die Modelldatei vor dem Training. Durch die Verarbeitung der enthaltenen Bilder / cat.jpg wird eine Datei mit dem Namen images / cat_seg.png generiert.

Gilt für unbekannte Bilder

Verwenden wir dieses Modell, um ein unbekanntes Bild zu verarbeiten. Leider ist bei dieser Implementierung die Größe des Eingabebilds begrenzt, und es scheint, dass es nur verarbeitet werden kann, wenn die Breite und Höhe weniger als ungefähr 500 betragen. Nachdem ich das Bild im Voraus auf eine Größe geändert hatte, die diese Grenze erreicht, habe ich versucht, es zu verarbeiten.

Zu verarbeitendes Bild: サイズ修正猫画像

Segmentierungsausgabe セグメンテーション

Der als Katzenbild identifizierte Bereich wird durch die Farbe # 400000 (R: 0x40, G: 0x00, B: 0x00) identifiziert. Auf den ersten Blick scheint es zu funktionieren. Wenn Sie sich danach auf jedes Pixel dieses Bildes beziehen, können Sie das gewünschte Ergebnis erzielen, indem Sie den anderen bewerteten Teil als das Katzenbild aus dem Originalbild ausfüllen.

Wenn Sie sich die Grenzen genau ansehen, werden sie jedoch nicht genau nach den numerischen Werten unterteilt.

セグメンテーション拡大

Zum absoluten Wertvergleich

Wie Sie sehen können, sind die Werte an den Rändern leicht unscharf. Wenn Sie also einfach die absoluten Werte der Segmentierungspixel vergleichen, um festzustellen, ob es sich um ein Vordergrundbild handelt, fehlt dieser Teil des Bildes.

絶対値比較の結果

Siehe die Normen zwischen Farbräumen

Als Ergebnis verschiedener Gedanken und Versuche habe ich numpys linalg.norm verwendet, um den Abstand zwischen der Farbe des Segmentierungspixels und # 400000 zu berechnen. Wenn es innerhalb einer bestimmten Zahl liegt, wird festgestellt, dass es sich um ein Katzenbildpixel handelt. Ich tat. Das Ergebnis der Betrachtung des Bereichs entsprechend 32, der die Hälfte von 64 ist, als gültig ist wie folgt.

ノルムによる処理結果

Es fühlt sich gut an. Der Code zur Ausgabe dieses Ergebnisses ist unten dargestellt.

# -*- coding: utf-8 -*-

import argparse
import os, sys
from PIL import Image
import numpy as np

def get_args():
    p = argparse.ArgumentParser()
    p.add_argument("--contents-dir", '-c', default=None)
    p.add_argument("--segments-dir", '-s', default=None)
    p.add_argument("--output-dir", '-o', default=None)
    p.add_argument("--cat-label-vals", '-v', default="64,0,0")
    args = p.parse_args()
    if args.contents_dir is None or args.segments_dir is None or args.output_dir is None:
        p.print_help()
        sys.exit(1)
    
    return args

def cat_col_array(val_str):
    vals = val_str.split(',')
    vals = [int(i) for i in vals]
    return vals

def cmpary(a1, a2):
    v1 = np.asarray(a1)
    v2 = np.asarray(a2)
    norm = np.linalg.norm(v1-v2)
    if norm <= 32:
        return True
    return False

def make_images(cont_dir, seg_dir, out_dir, cat_vals):
    files = []
    for fname in os.listdir(cont_dir): # make target file list
        seg_fname = os.path.join(seg_dir, fname)
        if os.path.exists(seg_fname):
            files.append(fname)
    for fname in files:
        print("processing: %s" % fname)
        c_fname = os.path.join(cont_dir, fname)
        cont = np.asarray(Image.open(c_fname)).copy()
        s_fname = os.path.join(seg_dir, fname)
        seg = np.asarray(Image.open(s_fname))
        width, height, _ = seg.shape
        for y in range(height):
            for x in range(width):
                vals = seg[x, y]
                if not cmpary(vals, cat_vals):
                    cont[x, y] = [255, 255, 255]
        out = Image.fromarray(cont)
        o_fname = os.path.join(out_dir, fname)
        out.save(o_fname)

def main():
    args = get_args()
    cat_vals = cat_col_array(args.cat_label_vals)
    make_images(args.contents_dir, args.segments_dir, args.output_dir,
                cat_vals)
    
if __name__ == '__main__':
    main()

Aufgabe

Wenn das diesmal verwendete Modell auf alle von Pixabay gesammelten und ausgewählten Bilder angewendet wurde, wurden nicht immer 100% erwartete Ergebnisse angezeigt. Es gibt Fälle, in denen beurteilt wird, dass es Merkmale für einen der verbleibenden 19 Typen außer Katzen gibt.

Ein Teil des Körpers wird als Hund beurteilt

Bei der Verarbeitung des folgenden Bildes wurde ein Teil des Körperteils als Hund identifiziert.

処理対象

セグメンテーション結果

Violett-ähnlicher Farbton (# 400080) ist der Bereich, der als Hund identifiziert wird. Natürlich finde ich, dass Hunde mit dieser Farbe relativ teuer sind. Wenn Sie dieses Ergebnis dem vorherigen Skript geben, sieht es folgendermaßen aus:

マッティング結果

Da das diesmal erstellte Bild fast keine Hunde enthält, kann es möglich sein, den als Hund eingestuften Bereich zu verlassen.

Behandlung von schwarzen Katzen

Schwarze Katzen sind auf dem Bild nur schwer sauber zu erfassen, daher scheint es wahrscheinlich, dass Probleme in Bezug auf Diskriminierung auftreten.

黒猫画像

セグメンテーション結果

Der Schattenteil ist ein Teil der Katze geworden, und der Körperteil, der nur schwarz aussieht, ist verschwunden.

マッティング結果

Datensatz

Dieses Mal werden die URLs zu den Daten, die für die Segmentierung / Mattierung bestimmt sind, aufgelistet und auf github veröffentlicht.

1100 Es wird ein kleines Bild sein.

von jetzt an

Ich denke, dass die edge2cats von pix2pix auch mit dieser Datenmenge bis zu einem gewissen Grad reproduziert werden können, also werde ich es tatsächlich lernen.

Außerdem möchte ich das Papier lesen, um mein Verständnis der Struktur von SegNet zu vertiefen, die diesmal mit DilatedNet und ChainerCV verwendet werden kann. Außerdem möchte ich versuchen, die in der DilatedNet Keras-Implementierung verwendeten Trainingsdaten mit SegNet von ChainerCV zu lernen.

Recommended Posts

Extrahieren Sie nur den Katzenteil aus dem Katzenbild (Mattierung / Semantig-Segmentierung).
Auszug nur vollständig aus dem Ergebnis von Trinity
Entfernen Sie den Rahmen aus dem Bild
Computer Vision: Semantische Segmentierung Teil2 - Semantische Echtzeitsegmentierung
Schneiden wir das Gesicht aus dem Bild
Holen Sie sich nur den Text aus dem Django-Formular.
Verwenden Sie Pillow, um das Bild transparent zu machen und nur einen Teil davon zu überlagern
Verwenden Sie PIL in Python, um nur die gewünschten Daten aus Exif zu extrahieren