keras画像の意味分割を実現するサブ関数
13236 ワード
ウェイトダウンロードアドレス
レイヤ0のウェイト値を表示するには:
リファレンス
画像augmentationおよび事前訓練の参考
損失関数の定義、dice_loss
パレット
トレーニング、テスト、検証セットを含む画像フォルダCamVidを現在のディレクトリの下に配置し、画像データコードを以下のようにインポートします.
ここで、トレーニングサンプルはフォルダtrainに保存され、ground truthはtrainannotフォルダに保存され、ground truthはチャネル画像であり、各画素はカテゴリインデックス(0~11)である.訓練画像とground truthパスと名前を保存するテキストはtrain.txt、コンテンツフォーマット:
トレーニングセットがインポートされている場合は、
utilは次のとおりです.
そのうちone_hot_it利用可能keras持参to_Categorical実装:
RGBのground truthをマルチチャネル2値インデックスマップに変換します.
1枚の画像でテスト:
VGGプリトレーニングモデルを使用して画像の特徴を抽出し、表示します.
ヒストグラム等化(画像処理ではrとbチャネルを頻繁に交換する):
呼び出し時:
トレーニング:
accとlossを表示します.
Data augmentation:イメージジェネレータImageDataGeneratorを使用して、トレーニング時にこの関数は指定したepochに達するまで無限にデータを生成します.
augmentation後の画像を表示します.
プリトレーニングウェイトを使用して新しいネットワークを訓練するには、2つの方法があります.1つは、ネットワークを2つのサブモデルに分割し、前のサブモデルにトレーニングされた重みをインポートし、出力結果を後のサブモデルの入力とし、トレーニング後のサブモデル(addのみが適用されるネットワーク)、前のサブモデルの出力の保存とロードコードは以下の通りである.
モデルを画像として保存するには、次の手順に従います.
分割結果を原図に表示します.
レイヤ0のウェイト値を表示するには:
weights = model.get_weights()[0]
リファレンス
画像augmentationおよび事前訓練の参考
損失関数の定義、dice_loss
パレット
トレーニング、テスト、検証セットを含む画像フォルダCamVidを現在のディレクトリの下に配置し、画像データコードを以下のようにインポートします.
import util
import numpy as np
import os
DataPath='/CamVid/'
def load_data(mode):
data=[]
label=[]
with open(os.getcwd()+DataPath+mode+'.txt') as f:
txt=f.readlines()
txt=[line.split(' ') for line in txt]
for i in range(len(txt)):
img_data,img_h,img_w=util.get_preprocessed_image(os.getcwd()+txt[i][0])
data.append(img_data)
img_label,y_h,y_w=util.get_preprocessed_label(os.getcwd()+txt[i][1][:-1])
label.append(img_label)
return np.array(data),np.array(label)
ここで、トレーニングサンプルはフォルダtrainに保存され、ground truthはtrainannotフォルダに保存され、ground truthはチャネル画像であり、各画素はカテゴリインデックス(0~11)である.訓練画像とground truthパスと名前を保存するテキストはtrain.txt、コンテンツフォーマット:
/CamVid/train/0001TP_006690.png /CamVid/trainannot/0001TP_006690.png
トレーニングセットがインポートされている場合は、
train_data, train_label = load_data("train")
np.save("data/train_data.npy", train_data)
utilは次のとおりです.
import numpy as np
from PIL import Image
from keras.applications.vgg16 import preprocess_input
def one_hot_it(labels,h,w):
x=np.zeros([h,w,12])
for i in range(h):
for j in range(w):
x[i,j,int(labels[i][j])]=1
return x
def get_preprocessed_label(file_name): #from 1-channel index map to 1-channel binary index map
im=np.array(Image.open(file_name))
img_h,img_w=im.shape
im=one_hot_it(im,img_h,img_w)
if img_h>500 or img_w>500:
raise ValueError("Please resize your images to be not bigger than 500 x 500")
pad_h=500-img_h
pad_w=500-img_w
im=np.pad(im,pad_width=((0,pad_h),(0,pad_w),(0,0)),mode='constant',constant_values=0)
return im.reshape(500,500,12),img_h,img_w
def get_preprocessed_image(file_name):
#Note: channels last
im=np.array(Image.open(file_name)).astype(np.float32)
assert im.ndim==3,"Only RGB images are supported"
img_h,img_w,img_c=im.shape
assert img_c==3,"Only RGB images are supported"
if img_h>500 or img_w>500:
raise ValueError("Please resize your images to be not bigger than 500 x 500")
im=preprocess_input(im)
pad_h=500-img_h
pad_w=500-img_w
im=np.pad(im,pad_width=((0,pad_h),(0,pad_w),(0,0)),mode='constant',constant_values=0)
return im.astype(np.float32).reshape(500,500,3),img_h,img_w
def get_label_image(probs, img_h, img_w):
""" Returns the label image (PNG with Pascal VOC colormap) given the probabilities.Channels_last.
"""
labels = probs.argmax(axis=2).astype("uint8")[:img_h, :img_w]
label_im = Image.fromarray(labels, "P")
label_im.putpalette(_PALETTE)
return label_im
そのうちone_hot_it利用可能keras持参to_Categorical実装:
from keras.utils.np_utils import to_categorical
categorical_labels = to_categorical(imgs, num_classes)
label=categorical_labels.reshape(imgs_num,img_rows,img_cols,num_classes)
ground truthをカラーとして表示するコードは以下の通りです.import numpy as np
import os
from PIL import Image
import util
_PALETTE = [0, 0, 0,
128, 0, 0,
0, 128, 0,
128, 128, 0,
0, 0, 128,
128, 0, 128,
0, 128, 128,
128, 128, 128,
64, 0, 0,
192, 0, 0,
64, 128, 0,
192, 128, 0,
64, 0, 128,
192, 0, 128,
64, 128, 128,
192, 128, 128,
0, 64, 0,
128, 64, 0,
0, 192, 0,
128, 192, 0,
0, 64, 128,
128, 64, 128,
0, 192, 128,
128, 192, 128,
64, 64, 0,
192, 64, 0,
64, 192, 0,
192, 192, 0]
_COLOR_LIST=np.array(_PALETTE).reshape(28,3).tolist()
def get_rgb(single,h,w): #from index map to rgb
x=np.zeros([h,w,3])
for i in range(h):
for j in range (w):
r,g,b=_COLOR_LIST[int(single[i][j])]
x[i,j,0]=r
x[i,j,1]=g
x[i,j,2]=b
r = Image.fromarray(x[:,:,0]).convert('L')
g = Image.fromarray(x[:,:,1]).convert('L')
b = Image.fromarray(x[:,:,2]).convert('L')
image = Image.merge("RGB", (r,g,b))
return image
DataPath = '/CamVid/'
mode='test'
output_file='/colorlabel/'
with open(os.getcwd() + DataPath + mode +'.txt') as f:
txt = f.readlines()
txt = [line.split(' ') for line in txt]
for i in range(len(txt)):
im = np.array(Image.open(os.getcwd() +txt[i][1][:-1]))
y=im.astype(np.float32)
####################### 3 RGB###############################################
y= get_rgb(y,y.shape[0],y.shape[1])
y.save(os.getcwd() +output_file+txt[i][1][-18:-1])
######################### , ##########################################
y = one_hot_it(y,y.shape[0],y.shape[1])
segmentation = get_label_image(y)
segmentation.save(os.getcwd() +output_file+txt[i][1][-18:-1])
RGBのground truthをマルチチャネル2値インデックスマップに変換します.
def label_colormap(label_rgb):
h=label_rgb.shape[0]
w=label_rgb.shape[1]
cmap=np.zeros([h,w])
for i in range(h):
for j in range(w):
r,g,b=label_rgb[i][j]
cmap[i][j]=_COLOR_LIST.index([r,g,b])
return cmap
def get_preprocessed_label_MSRC(file_name):
#Note: channels_last
im =label_colormap(np.array(Image.open(file_name)))
img_h, img_w = im.shape
im=one_hot_it(im,img_h,img_w)
if img_h > 500 or img_w > 500:
raise ValueError("Please resize your images to be not bigger than 500 x 500.")
pad_h = 500 - img_h
pad_w = 500 - img_w
im = np.pad(im, pad_width=((0, pad_h), (0, pad_w),(0,0)), mode='constant', constant_values=0)
return im.reshape(500, 500,12), img_h, img_w
1枚の画像でテスト:
input_file = "image.jpg"
output_file = "out.png"
saved_model_path="my_weights.h5"
model = get_model()
model.load_weights(saved_model_path)
img_data, img_h, img_w = util.get_preprocessed_image(input_file)
temp=np.expand_dims(img_data,axis=0)
probs = model.predict(temp, verbose=False)[0, :, :, :]
segmentation = util.get_label_image(probs, img_h, img_w)
segmentation.save(output_file)
VGGプリトレーニングモデルを使用して画像の特徴を抽出し、表示します.
from keras.applications.vgg16 import VGG16
from keras.preprocessing import image
from keras.applications.vgg16 import preprocess_input
from keras.models import Model
import numpy as np
import matplotlib.pyplot as plt
import os
import util
img_path='image.jpg'
img=image.load_img(img_path,target_size=(224,224))
x=image.img_to_array(img)
x=np.expand_dims(x,axis=0)
x=preprocess_input(x)
base_model=VGG16(weights='imagenet',include_top=False)
model=Model(inputs=base_model.input,outputs=base_model.get_layer('block3_pool').output)
block3_pool_features=model.predict(x)[0,:,:,:]
for i,layer in enumerate(model.layers):
print(i,layer.name)
plt.imshow(block3_pool_features[:,:,2]) #show single feature map
plt.axis('off')
plt.show()
for i in range(20): #show more feature maps
plt.figure()
plt.imshow(block3_pool_features[:,:,i])
ヒストグラム等化(画像処理ではrとbチャネルを頻繁に交換する):
from skimage import exposure
def normalized(rgb):
norm=np.zeros((rgb.shape[0], rgb.shape[1], 3),np.float32)
b=rgb[:,:,0]
g=rgb[:,:,1]
r=rgb[:,:,2]
norm[:,:,0]=exposure.equalize_hist(b)
norm[:,:,1]=exposure.equalize_hist(g)
norm[:,:,2]=exposure.equalize_hist(r)
return norm
呼び出し時:
from keras.preprocessing import image
x=normalized(image.img_to_array(x))
トレーニング:
import keras.callbacks import ModelCheckpoint,Callback,EarlyStopping
class LossHistory(Callback):
def on_train_begin(self,logs={}):
self.losses=[]
def on_batch_end(self,batch,logs={}):
self.losses.append(logs.get('loss'))
model.compile(optimizer=SGD(lr=1e-13,momentum=0.99,nesterov=True),loss='binary_crossentropy',metrics=['accuracy'])
checkpointer=ModelCheckpoint(filepath='my.h5',monitor='val_acc',verbose=1,save_best_only=True,
save_weights_only=True,mode='auto')
history=LossHistory()
earlystop=EarlyStopping(monitor='val_acc',patience=10,verbose=1,mode='auto')
memory=model.fit(train_data,train_label,batch_size=1,epochs=100,verbose=1,
callbacks=[checkpointer,earlystop,history],validation_split=0.1,shuffle=True) #validation_split first, then shuffle (validation no shuffle)
scores=model.evaluate(val_data,val_label,batch_size=1,verbose=1)
print("%s:%.2f%%" % (model.metrics_names[1],scores[1]*100))
accとlossを表示します.
import matplotlib.pyplot as plt
print(memory.history.keys()) #list all data in memory
#summaryize memory for accuracy
plt.plot(memory.history['acc'])
plt.plot(memory.history['val_acc'])
plt.title('model accuracy')
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train','val'],loc='upper left')
plt.show()
#summarize memory for loss
plt.plot(memory.history['loss'])
plt.plot(memory.history['val_loss'])
plt.title('model loss')
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train','val'],loc='upper right')
plt.show()
Data augmentation:イメージジェネレータImageDataGeneratorを使用して、トレーニング時にこの関数は指定したepochに達するまで無限にデータを生成します.
from keras.preprocessing.image import ImageDataGenerator
train_datagen=ImageDataGenerator(featurewise_center=False,# set input mean to 0 over the dataset
samplewise_center=False, #set each sample mean to 0
featurewise_std_normalization=False, #divide inputs by std of the dataset
samplewise_std_normalization=False, #divide each input by its std
zca_whitening=False, #apply ZCA whitening
rotation_range=10, #randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.1, #randomly shift iamges horizontally (fraction of total width)
height_shift_range=0.1, #randomly shift images vertically (fraction of total height)
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True)
test_datagen=ImageDataGenerator(rescale=1./255)
train_generator=train_datagen.flow_from_directory(
train_data_dir,
target_size=(img_width,img_height),
batch_size=32,
class_mode='binary') #train , 。
validation_generator=test_datagen.flow_from_directory(
validation_data_dir,
target_size=(img_width,img_height),
batch_size=32,
class_mode='binary')
model.fit_generator(train_generator,
samples_per_epoch=nb_train_samples,
nb_epoch=nb_epoch,
validation_data=validation_generator,
nb_val_samples=nb_validation_samples)
またはmodel.fit_generator(datagen.flow(x_train,y_train,batch_size=batch_size),
steps_per_epoch=batch_size,
epochs=epochs,
validation_data=(x_test,y_test))
augmentation後の画像を表示します.
from keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array, load_img
datagen=ImageDataGenerator(
rotation_range=40,
width_shift_range=0.2,
height_shift_range=0.2,
rescale=1./255,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest')
img=load_img('image.jpg')
x=img_to_array(img)
x=x.reshape((1,)+x.shape)
i=0
for batch in datagen.flow(x,batch_size=1,save_to_dir='preview',save_prefix='augmentation',save_format='jpg'):
i+=1
if i>50:
break
プリトレーニングウェイトを使用して新しいネットワークを訓練するには、2つの方法があります.1つは、ネットワークを2つのサブモデルに分割し、前のサブモデルにトレーニングされた重みをインポートし、出力結果を後のサブモデルの入力とし、トレーニング後のサブモデル(addのみが適用されるネットワーク)、前のサブモデルの出力の保存とロードコードは以下の通りである.
np.save(open('features_train.npy','w'),features_train)
train_data=np.load(open('features_train.npy'))
二は、既存の重みのあるネットワーク層を固定し、訓練しないことであり、コードは以下の通りである.for layer in model.layers[:25]:
layer.trainable=False
モデルを画像として保存するには、次の手順に従います.
from keras.utils import plot_model
plot_model(model,'model1.png')
分割結果を原図に表示します.
from PIL import Image
import matplotlib.pyplot as plt
mask = Image.open("mask.png")#voc , , mode P
image = Image.open("image.jpg")#mode RGB
outputImage = Image.new("RGB",(image.size[0],image.size[1]),(0,0,0))# mode
outputImage.paste(mask)
FullHdOutImage = Image.blend(outputImage, image, 0.5)#0.9 ,image ;0.1 ,outputImage
plt.imshow(FullHdOutImage)
その他の読図ツール:from skimage import io
img=io.imread("mask.png", as_grey=False)
io.imshow(img)