Cet article fait partie de l'exemple de code pour Kaggle: The Nature Conservancy Fisheries Monitoring. Le programme lié à CNN n'est pas répertorié ici. Les détails seront résumés à une date ultérieure.
Ici, nous effectuerons deux analyses à partir des photographies du site de pêche.
Ici, nous allons présenter Comment regrouper automatiquement les types de bateaux qui ont pris des photos. Par exemple, il peut être utilisé pour créer un modèle différent pour chaque bateau, ou pour masquer des zones où il n'y a pas de poisson sur le plateau.
Créez une fonction pour afficher les images côte à côte. Il existe deux types, quatre et huit. Après cela, 500 échantillons sont lus à partir du train.
import pandas as pd
import numpy as np
import glob
from sklearn import cluster
from scipy.misc import imread
import cv2
import skimage.measure as sm
# import progressbar
import multiprocessing
import random
import matplotlib.pyplot as plt
import seaborn as sns
%matplotlib inline
new_style = {'grid': False}
plt.rc('axes', **new_style)
# Function to show 4 images
def show_four(imgs, title):
#select_imgs = [np.random.choice(imgs) for _ in range(4)]
select_imgs = [imgs[np.random.choice(len(imgs))] for _ in range(4)]
_, ax = plt.subplots(1, 4, sharex='col', sharey='row', figsize=(20, 3))
plt.suptitle(title, size=20)
for i, img in enumerate(select_imgs):
ax[i].imshow(img)
# Function to show 8 images
def show_eight(imgs, title):
select_imgs = [imgs[np.random.choice(len(imgs))] for _ in range(8)]
_, ax = plt.subplots(2, 4, sharex='col', sharey='row', figsize=(20, 6))
plt.suptitle(title, size=20)
for i, img in enumerate(select_imgs):
ax[i // 4, i % 4].imshow(img)
select = 500 # Only load 500 images for speed
# Data loading
train_files = sorted(glob.glob('../input/train/*/*.jpg'), key=lambda x: random.random())[:select]
train = np.array([imread(img) for img in train_files])
print('Length of train {}'.format(len(train)))
La taille des images de train n'est pas unifiée. Existe-t-il une taille de photo qui ne comprend que certains bateaux? Vérifions l'ID du bateau comme taille d'image.
print('Sizes in train:')
shapes = np.array([str(img.shape) for img in train])
pd.Series(shapes).value_counts()
(720, 1280, 3) 287
(750, 1280, 3) 81
(974, 1280, 3) 50
(670, 1192, 3) 29
(718, 1276, 3) 28
(924, 1280, 3) 9
(974, 1732, 3) 7
(700, 1244, 3) 5
(854, 1518, 3) 3
(750, 1334, 3) 1
dtype: int64
Divisé la taille. Affiche quatre images réelles à la fois.
for uniq in pd.Series(shapes).unique():
show_four(train[shapes == uniq], 'Images with shape: {}'.format(uniq))
plt.show()
À l'exception de la taille d'image (854, 1518, 3), les autres images contiennent un ou plusieurs bateaux. Une autre approche sera probablement nécessaire pour considérer l'ID du bateau.
Par souci de simplicité, nous analyserons ces 500 données. Bien entendu, le même traitement peut être effectué en utilisant toutes les données d'image. Analysez dans les trois étapes suivantes.
# Function for computing distance between images
def compare(args):
img, img2 = args
img = (img - img.mean()) / img.std()
img2 = (img2 - img2.mean()) / img2.std()
return np.mean(np.abs(img - img2))
# Resize the images to speed it up.
train = [cv2.resize(img, (224, 224), cv2.INTER_LINEAR) for img in train]
# Create the distance matrix in a multithreaded fashion
pool = multiprocessing.Pool(8)
#bar = progressbar.ProgressBar(max=len(train))
distances = np.zeros((len(train), len(train)))
for i, img in enumerate(train): #enumerate(bar(train)):
all_imgs = [(img, f) for f in train]
dists = pool.map(compare, all_imgs)
distances[i, :] = dists
Créez une matrice NxN. N est le nombre d'images, et cette matrice montre la distance entre les images. SKLearn a de nombreuses méthodes de clustering qui peuvent utiliser des matrices de distance pré-calculées. Ici, la matrice de distance est donnée à DBSCAN pour le clustering.
print(distances)
plt.hist(distances.flatten(), bins=50)
plt.title('Histogram of distance matrix')
print('')
Vous pouvez voir qu'il y a une aire de 0,8 ou moins. Probablement lors du calcul de la distance entre les images du même bateau. DBSCAN considère les distances jusqu'à 0,5 comme des clusters similaires. En regardant l'histogramme, nous jugeons que 0,6 est un seuil approprié.
cls = cluster.DBSCAN(metric='precomputed', min_samples=5, eps=0.6)
y = cls.fit_predict(distances)
print(y)
print('Cluster sizes:')
print(pd.Series(y).value_counts())
for uniq in pd.Series(y).value_counts().index:
if uniq != -1:
size = len(np.array(train)[y == uniq])
if size > 10:
show_eight(np.array(train)[y == uniq], 'BoatID: {} - Image count {}'.format(uniq, size))
plt.show()
else:
show_four(np.array(train)[y == uniq], 'BoatID: {} - Image count {}'.format(uniq, size))
plt.show()
Cela a plutôt bien fonctionné. Cependant, il y avait un groupe qui n'appartenait à aucune carte d'identité de bateau. Il y a deux raisons possibles.
size = len(np.array(train)[y == -1])
show_eight(np.array(train)[y == -1], 'BoatID: {} (Unclassified images) - Image count {}'.format(-1, size))
Certains peuvent créer visuellement des clusters. En d'autres termes, il y a place à l'amélioration de l'algorithme. Cependant, le fait que plus de 75% des bateaux puissent être classés par apprentissage non supervisé signifie que le classement était assez précis.
Segmentez l'image du poisson. Comme procédure de travail
import os
from scipy import ndimage
from subprocess import check_output
import cv2
import numpy as np
from matplotlib import pyplot as plt
%matplotlib inline
img_rows, img_cols= 350, 425
im_array = cv2.imread('../input/train/LAG/img_00091.jpg',0)
template = np.zeros([ img_rows, img_cols], dtype='uint8') # initialisation of the template
template[:, :] = im_array[100:450,525:950] # I try multiple times to find the correct rectangle.
#template /= 255.
plt.subplots(figsize=(10, 7))
plt.subplot(121),plt.imshow(template, cmap='gray')
plt.subplot(122), plt.imshow(im_array, cmap='gray')
Utilisez des données différentes de la photo utilisée précédemment comme modèle. En utilisant matchTemplate d'opencv, vous pouvez trouver une partie similaire au modèle préparé. Il existe plusieurs types de méthodes optionnelles, nous allons donc expérimenter chacune des six méthodes. L'emplacement spécifié est défini pour être entouré d'un carré.
file_name = '../input/train/LAG/img_01512.jpg' # img_00176,img_02758, img_01512
img = cv2.imread(file_name,0)
img2 = img
w, h = template.shape[::-1]
# All the 6 methods for comparison in a list
methods = ['cv2.TM_CCOEFF', 'cv2.TM_CCOEFF_NORMED', 'cv2.TM_CCORR',
'cv2.TM_CCORR_NORMED', 'cv2.TM_SQDIFF', 'cv2.TM_SQDIFF_NORMED']
for meth in methods:
img = img2
method = eval(meth)
# Apply template Matching
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
# If the method is TM_SQDIFF or TM_SQDIFF_NORMED, take minimum
if method in [cv2.TM_SQDIFF, cv2.TM_SQDIFF_NORMED]:
top_left = min_loc
else:
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img,top_left, bottom_right, 255, 2)
fig, ax = plt.subplots(figsize=(12, 7))
plt.subplot(121),plt.imshow(res,cmap = 'gray')
plt.title('Matching Result'), plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(img,cmap = 'gray') #,aspect='auto'
plt.title('Detected Point'), plt.xticks([]), plt.yticks([])
plt.suptitle(meth)
plt.show()
Lorsque je l'exécute, je peux bien segmenter le poisson par des méthodes autres que TM_SQDIFF et TM_SQDIFF_NORMED. Par conséquent, cette fois, TM_CCOEFF est utilisé comme méthode de découverte.
Les photos de ce concours sont limitées à 8 types de poissons. Par conséquent, sélectionnez 4 photos de chaque espèce de poisson et exécutez la segmentation avec TM_CCOEFF.
method = eval('cv2.TM_CCOEFF')
indexes=[1,30,40,5]
train_path = "../input/train/"
sub_folders = check_output(["ls", train_path]).decode("utf8").strip().split('\n')
for sub_folder in sub_folders:
file_names = check_output(["ls", train_path+sub_folder]).decode("utf8").strip().split('\n')
k=0
_, ax = plt.subplots(2,2,figsize=(10, 7))
for file_name in [file_names[x] for x in indexes]: # I take only 4 images of each group.
img = cv2.imread(train_path+sub_folder+"/"+file_name,0)
img2 = img
w, h = template.shape[::-1]
# Apply template Matching
res = cv2.matchTemplate(img,template,method)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res)
top_left = max_loc
bottom_right = (top_left[0] + w, top_left[1] + h)
cv2.rectangle(img,top_left, bottom_right, 255, 2)
if k==0 :
ax[0,0].imshow(img,cmap = 'gray')
plt.xticks([]), plt.yticks([])
if k==1 :
ax[0,1].imshow(img,cmap = 'gray')
plt.xticks([]), plt.yticks([])
if k==2 :
ax[1,0].imshow(img,cmap = 'gray')
plt.xticks([]), plt.yticks([])
if k==3 :
ax[1,1].imshow(img,cmap = 'gray')
plt.xticks([]), plt.yticks([])
k=k+1
plt.suptitle(sub_folder)
plt.show()
Lorsque vous l'exécutez, vous pouvez voir que seules les données de poissons "LAG" utilisées dans le modèle peuvent être segmentées avec une précision relativement élevée. Vous voudrez peut-être préparer un autre modèle pour d'autres poissons.
Recommended Posts