À partir de l'image du chat collectée sur PIXTA, j'ai essayé d'extraire uniquement la partie du chat avec le moins d'effort possible.
Le processus de séparation du premier plan et de l'arrière-plan de l'image est appelé matage. Cela semble être une fonction majeure dans Photoshop, et dans le cas de gimp, la fonction nommée "Foreground Extraction" lui correspond. Il semble que le comportement général consiste à diviser l'image en trois types, "premier plan", "arrière-plan" et "l'un ou l'autre", et à déterminer la limite en regardant les caractéristiques de l'image dans chaque zone.
Il semble difficile d'automatiser ce processus, et dans le cadre de mes recherches, je n'ai pu trouver qu'une méthode appelée Deep Automatic Portrait Matting, qui extrait uniquement des personnes à partir de photographies de portrait.
En dehors de cela, il y avait un article sur une méthode de génération automatique d'informations (trimap) utilisée pour le matage.
Cependant, le matage automatique n'est pas toujours possible si un trimap approprié peut être généré. En fait, lors du traitement avec gimp, etc., il existe de nombreuses situations dans lesquelles le jugement de premier plan / arrière-plan n'est pas classé comme prévu et un ajustement fin est nécessaire.
Comme autre approche, j'ai envisagé d'utiliser la segmentation sémantique. La segmentation sémantique discrimine divers objets pixel par pixel pour une seule image d'entrée.
Dans l'article précédemment écrit, j'ai écrit que ChainerCV supporte également la segmentation sémantique, mais celui préparé comme modèle de pré-apprentissage est CamVid. Il est basé sur des données d'entraînement appelées ensemble de données et prend en charge 11 classes telles que le ciel, la route, la voiture et les piétons. Il n'y a aucune information sur le chat que je souhaite gérer cette fois.
Lorsque j'ai recherché d'autres implémentations et ensembles de données de segmentation sémantique, l'implémentation Keras de DilatedNet a été trouvée dans [PASCAL VOC2011 challange](http: //host.robots.ox). Je l'ai distribué avec un modèle entraîné en utilisant un jeu de données basé sur le jeu de données .ac.uk / pascal / VOC / voc2012 /), j'ai donc décidé de l'utiliser cette fois.
Vous pouvez l'utiliser en clonant le code, en installant tous les modules python qui satisfont aux dépendances requirements.txt et en téléchargeant le modèle de pré-apprentissage. Puisque nous allons utiliser l'ancien backend Keras et TensorFlow (0.12.1), il est judicieux d'avoir un environnement virtualenv dédié.
$ 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 sera le fichier de modèle de pré-entraînement. Le traitement des images / cat.jpg incluses générera un fichier appelé images / cat_seg.png.
En fait, utilisons ce modèle pour traiter une image inconnue. Malheureusement, cette implémentation a une limite sur la taille de l'image d'entrée, et il semble qu'elle ne peut être traitée que si la largeur et la hauteur sont inférieures à environ 500. Après avoir redimensionné l'image à une taille qui respecte cette limite à l'avance, j'ai essayé le traitement.
Image à traiter:
Sortie de segmentation
La zone identifiée comme une image de chat est identifiée par la couleur # 400000 (R: 0x40, G: 0x00, B: 0x00). À première vue, cela semble fonctionner. Après cela, tout en se référant à chaque pixel de cette image, il semble que vous puissiez obtenir le résultat souhaité en remplissant la partie jugée autre que l'image du chat à partir de l'image originale.
Cependant, si vous regardez de près les limites, elles ne sont pas exactement divisées en fonction des valeurs numériques.
Comme vous pouvez le voir, les valeurs autour des bords sont légèrement floues, donc si vous comparez simplement les valeurs absolues des pixels de segmentation pour déterminer s'il s'agit d'une image de premier plan, cette partie de l'image sera manquante.
À la suite de diverses réflexions et essais, j'ai utilisé linalg.norm de numpy pour calculer la distance entre la couleur du pixel de segmentation et # 400000, et si elle se situe dans un certain nombre, il est déterminé qu'il s'agit d'un pixel d'image de chat. J'ai fait. Le résultat de considérer la plage correspondant à 32, qui est la moitié de 64, comme valide est le suivant.
Ça fait du bien. Le code pour afficher ce résultat est indiqué ci-dessous.
# -*- 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()
Lorsque le modèle utilisé cette fois-ci a été appliqué à toutes les images collectées sur Pixabay et sélectionnées, il n'a pas toujours montré les résultats attendus à 100%. Il y a des cas où il est jugé qu'il existe des caractéristiques de l'un des 19 types restants autres que les chats.
Lorsque l'image suivante a été traitée, une partie de la partie du corps a été identifiée comme un chien.
La teinte violette (# 400080) est la zone identifiée comme un chien. Certes, je pense que les chiens avec ce genre de couleur sont relativement chers. Si vous donnez ce résultat au script précédent, il ressemblera à ceci:
Étant donné que l'image préparée cette fois-ci ne contient presque pas de chiens, il est possible de quitter la zone considérée comme un chien.
Les chats noirs sont difficiles à capturer proprement dans l'image, il semble donc que des problèmes soient susceptibles de se produire en termes de discrimination.
La partie ombre est devenue une partie du chat, et la partie du corps qui n'a l'air que noire a disparu.
Cette fois, les URL vers les données ciblées pour la segmentation / mise en correspondance sont répertoriées et publiées sur github.
1100 Ce sera une petite image.
Je pense que les bords2cats de pix2pix peuvent être reproduits dans une certaine mesure même avec ce niveau de données, donc je vais vraiment l'apprendre.
En outre, j'aimerais lire l'article pour approfondir ma compréhension de la structure de SegNet qui peut être utilisée avec DilatedNet et ChainerCV utilisé cette fois. Je voudrais également essayer de former les données de formation utilisées dans l'implémentation DilatedNet Keras avec SegNet de ChainerCV.
Recommended Posts