|
import sys |
|
import cv2 |
|
import keras.backend as K |
|
from keras.models import load_model |
|
from keras.preprocessing.image import load_img, img_to_array |
|
import numpy as np |
|
|
|
|
|
K.set_learning_phase(0) |
|
|
|
def Grad_Cam_plus_plus(input_model, layer_name, img_array): |
|
|
|
model = input_model |
|
(row, col, _) = img_array.shape |
|
|
|
# 前処理 |
|
X = np.expand_dims(img_array, axis=0) |
|
X = X.astype('float32') |
|
preprocessed_input = X / 255.0 |
|
|
|
|
|
# 予測クラスの算出 |
|
predictions = model.predict(preprocessed_input) |
|
class_idx = np.argmax(predictions[0]) |
|
|
|
# 使用する重みの抽出、高階微分の計算 |
|
class_output = model.output[:, class_idx] |
|
class_output = model.layers[-1].output |
|
conv_output = model.get_layer(layer_name).output |
|
grads = K.gradients(class_output, conv_output)[0] |
|
#first_derivative:1階微分 |
|
first_derivative = K.exp(class_output)[0][class_idx] * grads |
|
#second_derivative:2階微分 |
|
second_derivative = K.exp(class_output)[0][class_idx] * grads * grads |
|
#third_derivative:3階微分 |
|
third_derivative = K.exp(class_output)[0][class_idx] * grads * grads * grads |
|
|
|
#関数の定義 |
|
gradient_function = K.function([model.input], [conv_output, first_derivative, second_derivative, third_derivative]) # model.inputを入力すると、conv_outputとgradsを出力する関数 |
|
|
|
|
|
conv_output, conv_first_grad, conv_second_grad, conv_third_grad = gradient_function([preprocessed_input]) |
|
conv_output, conv_first_grad, conv_second_grad, conv_third_grad = conv_output[0], conv_first_grad[0], conv_second_grad[0], conv_third_grad[0] |
|
|
|
#alphaを求める |
|
global_sum = np.sum(conv_output.reshape((-1, conv_first_grad.shape[2])), axis=0) |
|
alpha_num = conv_second_grad |
|
alpha_denom = conv_second_grad*2.0 + conv_third_grad*global_sum.reshape((1,1,conv_first_grad.shape[2])) |
|
alpha_denom = np.where(alpha_denom!=0.0, alpha_denom, np.ones(alpha_denom.shape)) |
|
alphas = alpha_num / alpha_denom |
|
|
|
#alphaの正規化 |
|
alpha_normalization_constant = np.sum(np.sum(alphas, axis = 0), axis = 0) |
|
alpha_normalization_constant_processed = np.where(alpha_normalization_constant != 0.0, alpha_normalization_constant, np.ones(alpha_normalization_constant.shape)) |
|
alphas /= alpha_normalization_constant_processed.reshape((1,1,conv_first_grad.shape[2])) |
|
|
|
#wの計算 |
|
weights = np.maximum(conv_first_grad, 0.0) |
|
deep_linearization_weights = np.sum((weights * alphas).reshape((-1, conv_first_grad.shape[2]))) |
|
|
|
#Lの計算 |
|
grad_CAM_map = np.sum(deep_linearization_weights * conv_output, axis=2) |
|
grad_CAM_map = np.maximum(grad_CAM_map, 0) |
|
grad_CAM_map = grad_CAM_map / np.max(grad_CAM_map) |
|
|
|
#ヒートマップを描く |
|
grad_CAM_map = cv2.resize(grad_CAM_map, (row, col), cv2.INTER_LINEAR) |
|
jetcam = cv2.applyColorMap(np.uint8(255 * grad_CAM_map), cv2.COLORMAP_JET) # モノクロ画像に疑似的に色をつける |
|
jetcam = (np.float32(jetcam) + img_array / 2) # もとの画像に合成 |
|
|
|
return jetcam |
|
|
|
|
|
row = 512 |
|
col = 512 |
|
img_shape = (row, col, 3) |
|
model = load_model('model.h5') |
|
target_layer = 'block5_conv3' |
|
image_path = sys.argv[1] or 'dagm2007andothers/validation/NG/class1_1.png' |
|
|
|
img = img_to_array(load_img(image_path, target_size=(row, col))) |
|
img_GCAMplusplus = Grad_Cam_plus_plus(model, target_layer, img) |
|
img_Gplusplusname = image_path + "_GCAM++_VGG16.jpg" |
|
cv2.imwrite(img_Gplusplusname, img_GCAMplusplus) |