Dieser Artikel ist Teil des Beispielcodes für Kaggle: The Nature Conservancy Fisheries Monitoring. Das auf CNN bezogene Programm ist hier nicht aufgeführt. Details werden zu einem späteren Zeitpunkt zusammengefasst.
Hier werden wir zwei Analysen anhand der Fotos des Angelplatzes durchführen.
Hier stellen wir vor Wie man automatisch die Arten von Booten gruppiert, die Bilder aufgenommen haben. Beispielsweise kann es verwendet werden, um für jedes Boot ein anderes Modell zu erstellen oder Bereiche zu maskieren, in denen sich keine Fische auf dem Brett befinden.
Erstellen Sie eine Funktion zum Anzeigen von Bildern nebeneinander. Es gibt zwei Arten, vier und acht. Danach werden 500 Proben aus dem Zug gelesen.
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)))
Die Größe der Zugbilder ist nicht einheitlich. Gibt es eine Fotogröße, die nur bestimmte Boote enthält? Lassen Sie uns die Boots-ID als Bildgröße überprüfen.
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
Die Größe geteilt. Lassen Sie uns vier aktuelle Bilder gleichzeitig anzeigen.
for uniq in pd.Series(shapes).unique():
show_four(train[shapes == uniq], 'Images with shape: {}'.format(uniq))
plt.show()
Mit Ausnahme der Bildgröße von (854, 1518, 3) enthalten die anderen Bilder ein oder mehrere Boote. Ein anderer Ansatz ist wahrscheinlich erforderlich, um die Boots-ID zu berücksichtigen.
Der Einfachheit halber werden wir diese 500 Daten analysieren. Natürlich kann dieselbe Verarbeitung mit allen Bilddaten durchgeführt werden. Analysieren Sie in den folgenden drei Schritten.
# 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
Erstellen Sie eine NxN-Matrix. N ist die Anzahl der Bilder, und diese Matrix zeigt den Abstand zwischen den Bildern. SKLearn verfügt über viele Clustering-Methoden, die vorberechnete Distanzmatrizen verwenden können. Hier wird die Distanzmatrix DBSCAN zum Clustering übergeben.
print(distances)
plt.hist(distances.flatten(), bins=50)
plt.title('Histogram of distance matrix')
print('')
Sie können sehen, dass es eine Fläche von 0,8 oder weniger gibt. Wahrscheinlich bei der Berechnung des Abstands zwischen Bildern desselben Bootes. DBSCAN betrachtet Entfernungen bis zu 0,5 als ähnliche Cluster. Wenn wir uns das Histogramm ansehen, beurteilen wir, dass 0,6 ein geeigneter Schwellenwert ist.
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()
Es hat ziemlich gut funktioniert. Es gab jedoch eine Gruppe, die keinem Bootsausweis angehörte. Es gibt zwei mögliche Gründe.
size = len(np.array(train)[y == -1])
show_eight(np.array(train)[y == -1], 'BoatID: {} (Unclassified images) - Image count {}'.format(-1, size))
Einige können visuell Cluster erstellen. Mit anderen Worten, der Algorithmus kann verbessert werden. Die Tatsache, dass mehr als 75% der Boote durch unbeaufsichtigtes Lernen klassifiziert werden konnten, bedeutet jedoch, dass die Klassifizierung ziemlich genau war.
Segmentieren Sie das Fischbild. Als Arbeitsablauf
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')
Verwenden Sie andere Daten als das zuvor als Vorlage verwendete Foto. Mithilfe der matchTemplate von opencv können Sie einen Teil finden, der der vorbereiteten Vorlage ähnelt. Es gibt verschiedene Arten von optionalen Methoden, daher werden wir mit jeder der sechs Methoden experimentieren. Der angegebene Ort soll von einem Quadrat umgeben sein.
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()
Wenn ich es ausführe, kann ich den Fisch gut mit anderen Methoden als TM_SQDIFF und TM_SQDIFF_NORMED segmentieren. Daher wird dieses Mal TM_CCOEFF als Erkennungsmethode verwendet.
Die Fotos in diesem Wettbewerb sind auf 8 Fischarten beschränkt. Wählen Sie daher 4 Fotos von jeder Fischart aus und führen Sie die Segmentierung mit TM_CCOEFF durch.
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()
Wenn Sie es ausführen, können Sie sehen, dass nur die in der Vorlage verwendeten Fischdaten "LAG" mit relativ hoher Genauigkeit segmentiert werden können. Möglicherweise möchten Sie eine andere Vorlage für andere Fische vorbereiten.
Recommended Posts