Il n'est pas exagéré de dire que la qualité du riz d'amour est déterminée par la fin. Et il y a beaucoup de fins différentes pour le riz d'amour. Harlem fin qui ne choisit pas une personne en particulier. Multi-end qui prépare la fin de chaque héroïne. Une fin individuelle qui ne se réalise qu'avec une personne spécifique. C'est une comédie d'amour où les fans se disputent toujours avec chaque fin, mais je pense que c'est la fin individuelle qui est la plus déroutante.
Parmi eux, le riz d'amour récent le plus confus à propos de la fin est, oui, "Bride of Five Equals" </ b>.
On dit que la fin de ce travail est la fin Yotsuba. Cependant, l'illusion de se terminer avec d'autres héroïnes doit être une sorte de plaisir du riz d'amour.
Dans cet article, après avoir appris les images de la première période d'animation, l'IA est faite pour juger la bonne épouse, et je réfléchis un peu à la possibilité de se terminer qui aurait pu être avec d'autres héroïnes.
La femme qui est apparue à la cérémonie de mariage de la première période de l'animation était considérée comme une épouse régulière et la femme régulière était jugée par la classification multi-classes des quintuplés et autres images. Keras est utilisé comme cadre d'apprentissage automatique. De plus, toutes les images d'apprentissage seront celles de la première période d'animation et les images à juger seront les suivantes.
Au fait, je pousse Sanku, alors j'espère que je vais faire de mon mieux et choisir Sanku.
Python : 3.9.0 conda version : 4.9.1 CPU : Intel(R) Core(TM)i5-6500 GPU : Intel(R) HD Graphics 530 keras : 2.3.1
Le premier est la collection d'images. Il semble que vous puissiez utiliser opencv pour capturer automatiquement une image en spécifiant une image d'une vidéo, mais comme il n'y avait pas de vidéo enregistrée, j'ai décidé de capturer l'animation cette fois. En guise de méthode, j'ai créé un programme qui capture toutes les 5 secondes tout en dégoulinant d'une période d'animation. Sélectionnez pyautogui comme module. Ce module est très utile car il automatise diverses autres opérations de l'interface graphique.
capture.py
import os
import pyautogui
import time
start = time.time()
for l in range(1,13):
for i in range(275):
im = pyautogui.screenshot('./capture_data/' + str(l) +'_'+ str(i) + '.png', region=(1050,50,800,450))
time.sleep(5)
end = time.time()
print('result time is :', end - start)
Dans mon cas, l'animation coulait sur l'écran supérieur droit du bureau divisé en quatre, il s'agit donc d'un programme qui capture region = (1050,50,800,450) et le coin supérieur droit du bureau. Un total de 3300 </ b> images ont été capturées sur une période d'environ 5 heures. L'image capturée ressemble à ceci.
Je ne peux toujours pas oublier l'ordre des plats de viande grillée sans viande grillée. À propos, lors de la capture à partir d'une vidéo en spécifiant une image, ce qui suit sera utile.
Lors de la capture à partir d'une vidéo
Ensuite, l'image du visage est extraite de l'image capturée par opencv. En tant que classificateur en cascade pour les images de visage, nous avons utilisé ici, qui est célèbre pour les images d'anime. Copiez ce fichier xml dans votre répertoire de travail, détectez le visage de l'image capturée précédente, puis extrayez-le. De plus, pour faciliter l'utilisation de VGG16 comme modèle d'apprentissage en profondeur, le nombre de pixels est défini sur 64 x 64 pixels.
face_cut.py
import cv2
def face_cut(img_path, save_path):
img = cv2.imread(img_path)
cascade = cv2.CascadeClassifier('lbpcascade_animeface.xml')![face_cut01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/208060/e1ce4d3c-113c-f329-ee3a-71a47e7a462c.png)
facerect = cascade.detectMultiScale(img)
for i, (x,y,w,h) in enumerate(facerect):
face_img = img[y:y+h, x:x+w]
face_img = cv2.resize(face_img, (64, 64))
cv2.imwrite(save_path, face_img)
for l in range(1,13):
for i in range(275):
face_cut('capture_data/'+str(l)+'_'+str(i)+'.png', 'cut_data/'+str(l)+'_'+str(i)+'.png')
Les images extraites sont les suivantes. Il semble que même la tante du repas scolaire soit extraite pour le moment. Sur les 3300 images capturées, 1365 </ b> étaient des visages détectés. En d'autres termes, il était possible d'extraire le visage avec un peu plus de 1/3 du total.
Ici, 1365 feuilles sont triées manuellement dans les répertoires de chaque héroïne. Cela n'a pas pris beaucoup de temps s'il s'agissait d'environ 1365, mais lorsque le nombre d'images est de l'ordre de 10 000, cela semble peu probable.
tesagyou.py
#Fais de ton mieux! !! !!
Les résultats du tri sont présentés dans le tableau ci-dessous.
Classification | Nombre de feuilles |
---|---|
Ichihana | 206 |
Nino | 168 |
Sanku | 152 |
Yotsuba | 172 |
Mai | 204 |
Autre | 463 |
Ichihana a pris la tête avec 206 feuilles et May courait après une marge serrée. Il y a une différence de 54 entre le nombre maximum d'Ichihana et le nombre minimum de Sanku, et il peut être nécessaire de rendre le nombre de feuilles d'apprentissage le même si l'on doit s'attendre à la rigueur, mais cette fois cela n'a pas d'importance aussi rigueur, alors continuez comme il est Je le ferai.
Ici, l'image du visage précédente est convertie en pandas et étiquetée de 0 à 5. Le rapport entre le nombre de trains et les essais était de 8: 2.
split.py
# split.py
import numpy as np
import glob
import cv2
from keras.utils.np_utils import to_categorical
import pandas as pd
import matplotlib.pyplot as plt
names = ['other', 'ichika', 'nino', 'miku', 'yotsuba', 'itsuki']
img_list = []
label_list = []
# append index
for index, name in enumerate(names):
face_img = glob.glob('data/'+name+'/*.png')
for face in face_img:
# imread RGB
a = cv2.imread(face, 1)
b = np.expand_dims(a, axis=0)
img_list.append(b)
label_list.append(index)
# convert pandas
X_pd = pd.Series(img_list)
y_pd = pd.Series(label_list)
# merge
Xy_pd = pd.concat([X_pd, y_pd], axis=1)
# shuffle
sf_Xy = Xy_pd.sample(frac=1)
#Réacquérir en tant que liste après la lecture aléatoire
img_list = sf_Xy[0].values
label_list = sf_Xy[1].values
#Tuple et combiner
X = np.r_[tuple(img_list)]
# convert binary
Y = to_categorical(label_list)
train_rate = 0.8
train_n = int(len(X) * train_rate)
train_X = X[:train_n]
test_X = X[train_n:]
train_y = Y[:train_n][:]
test_y = Y[train_n:][:]
Ensuite, je n'avais pas envie d'apprendre plus de 1000 feuilles, alors je n'ai rembourré que les images du train. En tant qu'éléments gonflés, une inversion gauche-droite, un flou et une conversion y ont été effectués, et l'image du train a été gonflée 2 ** 3 fois. Avec cela, le nombre total est d'environ 10 000.
split.py
## define scratch_functions
#Retourner horizontalement
def flip(img):
flip_img = cv2.flip(img, 1)
return flip_img
#Brouiller
def blur(img):
blur_img = cv2.GaussianBlur(img, (5,5), 0)
return blur_img
#conversion γ
def gamma(img):
gamma = 0.75
LUT_G = np.arange(256, dtype = 'uint8')
for i in range(256):
LUT_G[i] = 255 * pow(float(i) / 255, 1.0 / gamma)
gamma_img = cv2.LUT(img, LUT_G)
return gamma_img
total_img = []
for x in train_X:
imgs = [x]
# concat list
imgs.extend(list(map(flip, imgs)))
imgs.extend(list(map(blur, imgs)))
imgs.extend(list(map(gamma, imgs)))
total_img.extend(imgs)
# add dims to total_img
img_expand = list(map(lambda x:np.expand_dims(x, axis=0), total_img))
#Tuple et combiner
train_X_scratch = np.r_[tuple(img_expand)]
labels = []
for label in range(len(train_y)):
lbl = []
for i in range(2**3):
lbl.append(train_y[label, :])
labels.extend(lbl)
label_expand = list(map(lambda x:np.expand_dims(x, axis=0), labels))
train_y_scratch = np.r_[tuple(label_expand)]
Enfin, le modèle est entraîné à l'aide de l'image préparée. VGG16 a été choisi comme modèle pour l'apprentissage en profondeur, bien qu'il n'ait pas de signification particulière. Pour être honnête, il était surprenant qu'il ait fallu environ une demi-journée pour apprendre car le nombre d'époques était fixé à 100 et le GPU était tellement confus.
model.py
from keras.applications import VGG16
from keras.models import Model, Sequential
from keras.layers import Dense, Activation, Flatten, Input, Dropout
from keras import optimizers
import matplotlib.pyplot as plt
from split import *
# define input_tensor
input_tensor = Input(shape=(64,64,3))
vgg16 = VGG16(include_top=False, weights='imagenet', input_tensor=input_tensor)
top_model = Sequential()
top_model.add(Flatten(input_shape=vgg16.output_shape[1:]))
top_model.add(Dense(64, activation='sigmoid'))
top_model.add(Dropout(0.5))
top_model.add(Dense(32, activation='sigmoid'))
top_model.add(Dropout(0.5))
top_model.add(Dense(6, activation='softmax'))
model = Model(inputs=vgg16.input, outputs=top_model(vgg16.output))
# vgg_model apply to 15layers
for layer in model.layers[:15]:
layer.trainable = False
# compile
model.compile(loss='categorical_crossentropy', optimizer=optimizers.SGD(lr=1e-4, momentum=0.9), metrics=['accuracy'])
history = model.fit(train_X_scratch, train_y_scratch, epochs=100, batch_size=32, validation_data=(test_X, test_y))
score = model.evaluate(test_X, test_y, verbose=0)
print(score)
# save model
model.save('my_model.h5')
# plot acc, val_acc
plt.plot(history.history['acc'], label='acc', ls='-')
plt.plot(history.history['val_acc'], label='val_acc', ls='-')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(loc='best')
plt.show()
La précision n'est pas très bonne, mais un modèle de classification des cinq héroïnes a été élaboré.
Maintenant, c'est enfin le jugement tant attendu de la bonne épouse! (Il a fallu environ un jour pour arriver ici)
Quelle était la femme positive jugée par AI? !! !!
«Celui qui a été choisi était Ichihana </ b>.
Non, n'était-ce pas la longueur des cheveux? En termes de couleur, je pensais qu'il y aurait aussi un chan en mai. Pour Sanku, j'aurais dû synthétiser Sanku Hana ~, même des écouteurs qui ressemblent à Audio Tenika.
Eh bien, dans la première période d'animation, il n'y avait presque pas de scènes où des héroïnes autres qu'Ichihana levaient les cheveux, il peut donc être raisonnable qu'Ichihana ait été choisie. Les yeux sont plus importants que les cheveux en tant que caractéristique qui détermine le visage humain, mais dans le cas des quintuplés, ce sont toutes des couleurs bleuâtres, donc elles étaient indiscernables. En conséquence, je sens qu'Ichihana a été choisie à cause de ses cheveux courts. La couleur des cheveux est comme celle de mai.
Comme c'est un gros problème, j'ai également essayé de classer d'autres images.
C'est une scène du serment de la scène précédente. Cela a également été classé comme une fleur. Après tout, cela ressemble à un raccourci.
Eh bien, c'est aussi une fleur ~~
Et enfin, la dernière scène de 8 épisodes. C'est une photo d'une fille dont Kazetaro est tombé amoureux il y a longtemps.
e! C'est aussi une fleur! ?? ?? Je pense que ma couleur de cheveux était comme une fleur cette fois, mais je pense qu'Ichihana est un peu trop forte ...
Donc, en termes d'IA, l'héroïne qui est sortie en tant que mariée au mariage et la fille qui l'aimait généralement sont généralement Ichihana-san </ b>.
C'est ça. Quelque chose de désagréable sœur aînée attribut l'héroïne </ del> Une personne qui pousse Ichihana dit: "Non, vous voyez, c'est parce qu'Ichihana est une épouse positive en termes d'IA ..."
Vous pourriez dire ça. Peut être.
J'ai essayé de reconnaître l'animation "Keion!" Avec Keras Collectons des images de personnages d'anime à partir de vidéos avec opencv! Lbpcascade_animeface.xml pour la détection de visage d'anime par OpenCV
Recommended Posts