<reponame>manohar8642/object_detection_keras
import os
import cv2
import numpy as np
import sys
import pickle
from optparse import OptionParser
import time
from keras_frcnn import config
import keras_frcnn.resnet as nn
from keras import backend as K
from keras.layers import Input
from keras.models import Model
from keras_frcnn import roi_helpers
from keras_frcnn import data_generators
from sklearn.metrics import average_precision_score


def get_map(pred, gt, f):
	T = {}
	P = {}
	fx, fy = f

	for bbox in gt:
		bbox['bbox_matched'] = False

	pred_probs = np.array([s['prob'] for s in pred])
	box_idx_sorted_by_prob = np.argsort(pred_probs)[::-1]

	for box_idx in box_idx_sorted_by_prob:
		pred_box = pred[box_idx]
		pred_class = pred_box['class']
		pred_x1 = pred_box['x1']
		pred_x2 = pred_box['x2']
		pred_y1 = pred_box['y1']
		pred_y2 = pred_box['y2']
		pred_prob = pred_box['prob']
		if pred_class not in P:
			P[pred_class] = []
			T[pred_class] = []
		P[pred_class].append(pred_prob)
		found_match = False

		for gt_box in gt:
			gt_class = gt_box['class']
			gt_x1 = gt_box['x1']/fx
			gt_x2 = gt_box['x2']/fx
			gt_y1 = gt_box['y1']/fy
			gt_y2 = gt_box['y2']/fy
			gt_seen = gt_box['bbox_matched']
			if gt_class != pred_class:
				continue
			if gt_seen:
				continue
			iou = data_generators.iou((pred_x1, pred_y1, pred_x2, pred_y2), (gt_x1, gt_y1, gt_x2, gt_y2))
			if iou >= 0.5:
				found_match = True
				gt_box['bbox_matched'] = True
				break
			else:
				continue

		T[pred_class].append(int(found_match))

	for gt_box in gt:
		if not gt_box['bbox_matched']: #and not gt_box['difficult']:
			if gt_box['class'] not in P:
				P[gt_box['class']] = []
				T[gt_box['class']] = []

			T[gt_box['class']].append(1)
			P[gt_box['class']].append(0)

	#import pdb
	#pdb.set_trace()
	return T, P

sys.setrecursionlimit(40000)

parser = OptionParser()

parser.add_option("-p", "--path", dest="test_path", help="Path to test data.")
parser.add_option("-n", "--num_rois", dest="num_rois",
				help="Number of ROIs per iteration. Higher means more memory use.", default=32)
parser.add_option("--config_filename", dest="config_filename", help=
				"Location to read the metadata related to the training (generated when training).",
				default="config.pickle")
parser.add_option("-o", "--parser", dest="parser", help="Parser to use. One of simple or pascal_voc",
				default="pascal_voc"),

(options, args) = parser.parse_args()

if not options.test_path:   # if filename is not given
	parser.error('Error: path to test data must be specified. Pass --path to command line')


if options.parser == 'pascal_voc':
	from keras_frcnn.pascal_voc_parser import get_data
elif options.parser == 'simple':
	from keras_frcnn.simple_parser import get_data
else:
	raise ValueError("Command line option parser must be one of 'pascal_voc' or 'simple'")

config_output_filename = options.config_filename

with open(config_output_filename, 'rb') as f_in:
	C = pickle.load(f_in)

# turn off any data augmentation at test time
C.use_horizontal_flips = False
C.use_vertical_flips = False
C.rot_90 = False

img_path = options.test_path


def format_img(img, C):
	img_min_side = float(C.im_size)
	(height,width,_) = img.shape
	
	if width <= height:
		f = img_min_side/width
		new_height = int(f * height)
		new_width = int(img_min_side)
	else:
		f = img_min_side/height
		new_width = int(f * width)
		new_height = int(img_min_side)
	fx = width/float(new_width)
	fy = height/float(new_height)
	img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_CUBIC)
	img = img[:, :, (2, 1, 0)]
	img = img.astype(np.float32)
	img[:, :, 0] -= C.img_channel_mean[0]
	img[:, :, 1] -= C.img_channel_mean[1]
	img[:, :, 2] -= C.img_channel_mean[2]
	img /= C.img_scaling_factor
	img = np.transpose(img, (2, 0, 1))
	img = np.expand_dims(img, axis=0)
	return img, fx, fy


class_mapping = C.class_mapping

if 'bg' not in class_mapping:
	class_mapping['bg'] = len(class_mapping)

class_mapping = {v: k for k, v in class_mapping.items()}
print(class_mapping)
class_to_color = {class_mapping[v]: np.random.randint(0, 255, 3) for v in class_mapping}
C.num_rois = int(options.num_rois)

if K.image_dim_ordering() == 'th':
	input_shape_img = (3, None, None)
	input_shape_features = (1024, None, None)
else:
	input_shape_img = (None, None, 3)
	input_shape_features = (None, None, 1024)


img_input = Input(shape=input_shape_img)
roi_input = Input(shape=(C.num_rois, 4))
feature_map_input = Input(shape=input_shape_features)

# define the base network (resnet here, can be VGG, Inception, etc)
shared_layers = nn.nn_base(img_input, trainable=True)

# define the RPN, built on the base layers
num_anchors = len(C.anchor_box_scales) * len(C.anchor_box_ratios)
rpn_layers = nn.rpn(shared_layers, num_anchors)

classifier = nn.classifier(feature_map_input, roi_input, C.num_rois, nb_classes=len(class_mapping), trainable=True)

model_rpn = Model(img_input, rpn_layers)
model_classifier_only = Model([feature_map_input, roi_input], classifier)

model_classifier = Model([feature_map_input, roi_input], classifier)

model_rpn.load_weights(C.model_path, by_name=True)
model_classifier.load_weights(C.model_path, by_name=True)

model_rpn.compile(optimizer='sgd', loss='mse')
model_classifier.compile(optimizer='sgd', loss='mse')

all_imgs, _, _ = get_data(options.test_path)
test_imgs = [s for s in all_imgs if s['imageset'] == 'test']


T = {}
P = {}
for idx, img_data in enumerate(test_imgs):
	print('{}/{}'.format(idx,len(test_imgs)))
	st = time.time()
	filepath = img_data['filepath']

	img = cv2.imread(filepath)

	X, fx, fy = format_img(img, C)

	if K.image_dim_ordering() == 'tf':
		X = np.transpose(X, (0, 2, 3, 1))

	# get the feature maps and output from the RPN
	[Y1, Y2, F] = model_rpn.predict(X)

	R = roi_helpers.rpn_to_roi(Y1, Y2, C, K.image_dim_ordering(), overlap_thresh=0.7)

	# convert from (x1,y1,x2,y2) to (x,y,w,h)
	R[:, 2] -= R[:, 0]
	R[:, 3] -= R[:, 1]

	# apply the spatial pyramid pooling to the proposed regions
	bboxes = {}
	probs = {}

	for jk in range(R.shape[0] // C.num_rois + 1):
		ROIs = np.expand_dims(R[C.num_rois * jk:C.num_rois * (jk + 1), :], axis=0)
		if ROIs.shape[1] == 0:
			break

		if jk == R.shape[0] // C.num_rois:
			# pad R
			curr_shape = ROIs.shape
			target_shape = (curr_shape[0], C.num_rois, curr_shape[2])
			ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype)
			ROIs_padded[:, :curr_shape[1], :] = ROIs
			ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :]
			ROIs = ROIs_padded

		[P_cls, P_regr] = model_classifier_only.predict([F, ROIs])

		for ii in range(P_cls.shape[1]):

			if np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1):
				continue

			cls_name = class_mapping[np.argmax(P_cls[0, ii, :])]

			if cls_name not in bboxes:
				bboxes[cls_name] = []
				probs[cls_name] = []

			(x, y, w, h) = ROIs[0, ii, :]

			cls_num = np.argmax(P_cls[0, ii, :])
			try:
				(tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)]
				tx /= C.classifier_regr_std[0]
				ty /= C.classifier_regr_std[1]
				tw /= C.classifier_regr_std[2]
				th /= C.classifier_regr_std[3]
				x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th)
			except:
				pass
			bboxes[cls_name].append([16 * x, 16 * y, 16 * (x + w), 16 * (y + h)])
			probs[cls_name].append(np.max(P_cls[0, ii, :]))

	all_dets = []

	for key in bboxes:
		bbox = np.array(bboxes[key])

		new_boxes, new_probs = roi_helpers.non_max_suppression_fast(bbox, np.array(probs[key]), overlap_thresh=0.5)
		for jk in range(new_boxes.shape[0]):
			(x1, y1, x2, y2) = new_boxes[jk, :]
			det = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2, 'class': key, 'prob': new_probs[jk]}
			all_dets.append(det)


	print('Elapsed time = {}'.format(time.time() - st))
	t, p = get_map(all_dets, img_data['bboxes'], (fx, fy))
	for key in t.keys():
		if key not in T:
			T[key] = []
			P[key] = []
		T[key].extend(t[key])
		P[key].extend(p[key])
	all_aps = []
	for key in T.keys():
		ap = average_precision_score(T[key], P[key])
		print('{} AP: {}'.format(key, ap))
		all_aps.append(ap)
	print('mAP = {}'.format(np.mean(np.array(all_aps))))
	#print(T)
	#print(P)
	
#	if the above code throws error, comment the code and uncomment the below code to get the mAP.
	
	
# def non_max_suppression_fast(boxes, probs, overlap_thresh=0.9, max_boxes=300):
# 	# code used from here: http://www.pyimagesearch.com/2015/02/16/faster-non-maximum-suppression-python/
# 	# if there are no boxes, return an empty list
  
#     # Process explanation:
#     #   Step 1: Sort the probs list
#     #   Step 2: Find the larget prob 'Last' in the list and save it to the pick list
#     #   Step 3: Calculate the IoU with 'Last' box and other boxes in the list. If the IoU is larger than overlap_threshold, delete the box from list
#     #   Step 4: Repeat step 2 and step 3 until there is no item in the probs list 
# 	if len(boxes) == 0:
# 		return []

# 	# grab the coordinates of the bounding boxes
# 	x1 = boxes[:, 0]
# 	y1 = boxes[:, 1]
# 	x2 = boxes[:, 2]
# 	y2 = boxes[:, 3]

# 	np.testing.assert_array_less(x1, x2)
# 	np.testing.assert_array_less(y1, y2)

# 	# if the bounding boxes integers, convert them to floats --
# 	# this is important since we'll be doing a bunch of divisions
# 	if boxes.dtype.kind == "i":
# 		boxes = boxes.astype("float")

# 	# initialize the list of picked indexes	
# 	pick = []

# 	# calculate the areas
# 	area = (x2 - x1) * (y2 - y1)

# 	# sort the bounding boxes 
# 	idxs = np.argsort(probs)

# 	# keep looping while some indexes still remain in the indexes
# 	# list
# 	while len(idxs) > 0:
# 		# grab the last index in the indexes list and add the
# 		# index value to the list of picked indexes
# 		last = len(idxs) - 1
# 		i = idxs[last]
# 		pick.append(i)

# 		# find the intersection

# 		xx1_int = np.maximum(x1[i], x1[idxs[:last]])
# 		yy1_int = np.maximum(y1[i], y1[idxs[:last]])
# 		xx2_int = np.minimum(x2[i], x2[idxs[:last]])
# 		yy2_int = np.minimum(y2[i], y2[idxs[:last]])

# 		ww_int = np.maximum(0, xx2_int - xx1_int)
# 		hh_int = np.maximum(0, yy2_int - yy1_int)

# 		area_int = ww_int * hh_int

# 		# find the union
# 		area_union = area[i] + area[idxs[:last]] - area_int

# 		# compute the ratio of overlap
# 		overlap = area_int/(area_union + 1e-6)

# 		# delete all indexes from the index list that have
# 		idxs = np.delete(idxs, np.concatenate(([last],
# 			np.where(overlap > overlap_thresh)[0])))

# 		if len(pick) >= max_boxes:
# 			break

# 	# return only the bounding boxes that were picked using the integer data type
# 	boxes = boxes[pick].astype("int")
# 	probs = probs[pick]
# 	return boxes, probs

# def apply_regr_np(X, T):
# 	"""Apply regression layer to all anchors in one feature map

# 	Args:
# 		X: shape=(4, 18, 25) the current anchor type for all points in the feature map
# 		T: regression layer shape=(4, 18, 25)

# 	Returns:
# 		X: regressed position and size for current anchor
# 	"""
# 	try:
# 		x = X[0, :, :]
# 		y = X[1, :, :]
# 		w = X[2, :, :]
# 		h = X[3, :, :]

# 		tx = T[0, :, :]
# 		ty = T[1, :, :]
# 		tw = T[2, :, :]
# 		th = T[3, :, :]

# 		cx = x + w/2.
# 		cy = y + h/2.
# 		cx1 = tx * w + cx
# 		cy1 = ty * h + cy

# 		w1 = np.exp(tw.astype(np.float64)) * w
# 		h1 = np.exp(th.astype(np.float64)) * h
# 		x1 = cx1 - w1/2.
# 		y1 = cy1 - h1/2.

# 		x1 = np.round(x1)
# 		y1 = np.round(y1)
# 		w1 = np.round(w1)
# 		h1 = np.round(h1)
# 		return np.stack([x1, y1, w1, h1])
# 	except Exception as e:
# 		print(e)
# 		return X
    
# def apply_regr(x, y, w, h, tx, ty, tw, th):
#     # Apply regression to x, y, w and h
# 	try:
# 		cx = x + w/2.
# 		cy = y + h/2.
# 		cx1 = tx * w + cx
# 		cy1 = ty * h + cy
# 		w1 = math.exp(tw) * w
# 		h1 = math.exp(th) * h
# 		x1 = cx1 - w1/2.
# 		y1 = cy1 - h1/2.
# 		x1 = int(round(x1))
# 		y1 = int(round(y1))
# 		w1 = int(round(w1))
# 		h1 = int(round(h1))

# 		return x1, y1, w1, h1

# 	except ValueError:
# 		return x, y, w, h
# 	except OverflowError:
# 		return x, y, w, h
# 	except Exception as e:
# 		print(e)
# 		return x, y, w, h


# def rpn_to_roi(rpn_layer, regr_layer, C, dim_ordering, use_regr=True, max_boxes=300,overlap_thresh=0.9):
# 	"""Convert rpn layer to roi bboxes

# 	Args: (num_anchors = 9)
# 		rpn_layer: output layer for rpn classification 
# 			shape (1, feature_map.height, feature_map.width, num_anchors)
# 			Might be (1, 18, 25, 9) if resized image is 400 width and 300
# 		regr_layer: output layer for rpn regression
# 			shape (1, feature_map.height, feature_map.width, num_anchors)
# 			Might be (1, 18, 25, 36) if resized image is 400 width and 300
# 		C: config
# 		use_regr: Wether to use bboxes regression in rpn
# 		max_boxes: max bboxes number for non-max-suppression (NMS)
# 		overlap_thresh: If iou in NMS is larger than this threshold, drop the box

# 	Returns:
# 		result: boxes from non-max-suppression (shape=(300, 4))
# 			boxes: coordinates for bboxes (on the feature map)
# 	"""
# 	regr_layer = regr_layer / C.std_scaling

# 	anchor_sizes = C.anchor_box_scales   # (3 in here)
# 	anchor_ratios = C.anchor_box_ratios  # (3 in here)

# 	assert rpn_layer.shape[0] == 1

# 	(rows, cols) = rpn_layer.shape[1:3]

# 	curr_layer = 0

# 	# A.shape = (4, feature_map.height, feature_map.width, num_anchors) 
# 	# Might be (4, 18, 25, 9) if resized image is 400 width and 300
# 	# A is the coordinates for 9 anchors for every point in the feature map 
# 	# => all 18x25x9=4050 anchors cooridnates
# 	A = np.zeros((4, rpn_layer.shape[1], rpn_layer.shape[2], rpn_layer.shape[3]))

# 	for anchor_size in anchor_sizes:
# 		for anchor_ratio in anchor_ratios:
# 			# anchor_x = (128 * 1) / 16 = 8  => width of current anchor
# 			# anchor_y = (128 * 2) / 16 = 16 => height of current anchor
# 			anchor_x = (anchor_size * anchor_ratio[0])/C.rpn_stride
# 			anchor_y = (anchor_size * anchor_ratio[1])/C.rpn_stride
			
# 			# curr_layer: 0~8 (9 anchors)
# 			# the Kth anchor of all position in the feature map (9th in total)
# 			regr = regr_layer[0, :, :, 4 * curr_layer:4 * curr_layer + 4] # shape => (18, 25, 4)
# 			regr = np.transpose(regr, (2, 0, 1)) # shape => (4, 18, 25)

# 			# Create 18x25 mesh grid
# 			# For every point in x, there are all the y points and vice versa
# 			# X.shape = (18, 25)
# 			# Y.shape = (18, 25)
# 			X, Y = np.meshgrid(np.arange(cols),np. arange(rows))

# 			# Calculate anchor position and size for each feature map point
# 			A[0, :, :, curr_layer] = X - anchor_x/2 # Top left x coordinate
# 			A[1, :, :, curr_layer] = Y - anchor_y/2 # Top left y coordinate
# 			A[2, :, :, curr_layer] = anchor_x       # width of current anchor
# 			A[3, :, :, curr_layer] = anchor_y       # height of current anchor

# 			# Apply regression to x, y, w and h if there is rpn regression layer
# 			if use_regr:
# 				A[:, :, :, curr_layer] = apply_regr_np(A[:, :, :, curr_layer], regr)

# 			# Avoid width and height exceeding 1
# 			A[2, :, :, curr_layer] = np.maximum(1, A[2, :, :, curr_layer])
# 			A[3, :, :, curr_layer] = np.maximum(1, A[3, :, :, curr_layer])

# 			# Convert (x, y , w, h) to (x1, y1, x2, y2)
# 			# x1, y1 is top left coordinate
# 			# x2, y2 is bottom right coordinate
# 			A[2, :, :, curr_layer] += A[0, :, :, curr_layer]
# 			A[3, :, :, curr_layer] += A[1, :, :, curr_layer]

# 			# Avoid bboxes drawn outside the feature map
# 			A[0, :, :, curr_layer] = np.maximum(0, A[0, :, :, curr_layer])
# 			A[1, :, :, curr_layer] = np.maximum(0, A[1, :, :, curr_layer])
# 			A[2, :, :, curr_layer] = np.minimum(cols-1, A[2, :, :, curr_layer])
# 			A[3, :, :, curr_layer] = np.minimum(rows-1, A[3, :, :, curr_layer])

# 			curr_layer += 1

# 	all_boxes = np.reshape(A.transpose((0, 3, 1, 2)), (4, -1)).transpose((1, 0))  # shape=(4050, 4)
# 	all_probs = rpn_layer.transpose((0, 3, 1, 2)).reshape((-1))                   # shape=(4050,)

# 	x1 = all_boxes[:, 0]
# 	y1 = all_boxes[:, 1]
# 	x2 = all_boxes[:, 2]
# 	y2 = all_boxes[:, 3]

# 	# Find out the bboxes which is illegal and delete them from bboxes list
# 	idxs = np.where((x1 - x2 >= 0) | (y1 - y2 >= 0))

# 	all_boxes = np.delete(all_boxes, idxs, 0)
# 	all_probs = np.delete(all_probs, idxs, 0)

# 	# Apply non_max_suppression
# 	# Only extract the bboxes. Don't need rpn probs in the later process
# 	result = non_max_suppression_fast(all_boxes, all_probs, overlap_thresh=overlap_thresh, max_boxes=max_boxes)[0]

# 	return result


# def format_img_map(img, C):
#     """Format image for mAP. Resize original image to C.im_size (300 in here)

#     Args:
#             img: cv2 image
#             C: config

#     Returns:
#             img: Scaled and normalized image with expanding dimension
#             fx: ratio for width scaling
#             fy: ratio for height scaling
#     """

#     img_min_side = float(C.im_size)
#     (height, width, _) = img.shape

#     if width <= height:
#         f = img_min_side/width
#         new_height = int(f * height)
#         new_width = int(img_min_side)
#     else:
#         f = img_min_side/height
#         new_width = int(f * width)
#         new_height = int(img_min_side)
#     fx = width/float(new_width)
#     fy = height/float(new_height)
#     img = cv2.resize(img, (new_width, new_height),
#                      interpolation=cv2.INTER_CUBIC)
#     # Change image channel from BGR to RGB
#     img = img[:, :, (2, 1, 0)]
#     img = img.astype(np.float32)
#     img[:, :, 0] -= C.img_channel_mean[0]
#     img[:, :, 1] -= C.img_channel_mean[1]
#     img[:, :, 2] -= C.img_channel_mean[2]
#     img /= C.img_scaling_factor
#     # Change img shape from (height, width, channel) to (channel, height, width)
#     img = np.transpose(img, (2, 0, 1))
#     # Expand one dimension at axis 0
#     # img shape becames (1, channel, height, width)
#     img = np.expand_dims(img, axis=0)
#     return img, fx, fy


# T = {}
# P = {}
# mAPs = []
# for idx, img_data in enumerate(test_imgs):
#     print('{}/{}'.format(idx, len(test_imgs)))
#     st = time.time()
#     filepath = img_data['filepath']

#     img = cv2.imread(filepath)

#     X, fx, fy = format_img_map(img, C)

#     # Change X (img) shape from (1, channel, height, width) to (1, height, width, channel)
#     X = np.transpose(X, (0, 2, 3, 1))

#     # get the feature maps and output from the RPN
#     [Y1, Y2, F] = model_rpn.predict(X)

#     R = rpn_to_roi(Y1, Y2, C, K.image_data_format(), overlap_thresh=0.7)

#     # convert from (x1,y1,x2,y2) to (x,y,w,h)
#     R[:, 2] -= R[:, 0]
#     R[:, 3] -= R[:, 1]

#     # apply the spatial pyramid pooling to the proposed regions
#     bboxes = {}
#     probs = {}

#     for jk in range(R.shape[0] // C.num_rois + 1):
#         ROIs = np.expand_dims(
#             R[C.num_rois * jk:C.num_rois * (jk + 1), :], axis=0)
#         if ROIs.shape[1] == 0:
#             break

#         if jk == R.shape[0] // C.num_rois:
#             # pad R
#             curr_shape = ROIs.shape
#             target_shape = (curr_shape[0], C.num_rois, curr_shape[2])
#             ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype)
#             ROIs_padded[:, :curr_shape[1], :] = ROIs
#             ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :]
#             ROIs = ROIs_padded

#         [P_cls, P_regr] = model_classifier_only.predict([F, ROIs])

#         # Calculate all classes' bboxes coordinates on resized image (300, 400)
#         # Drop 'bg' classes bboxes
#         for ii in range(P_cls.shape[1]):

#             # If class name is 'bg', continue
#             if np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1):
#                 continue

#             # Get class name
#             cls_name = class_mapping[np.argmax(P_cls[0, ii, :])]

#             if cls_name not in bboxes:
#                 bboxes[cls_name] = []
#                 probs[cls_name] = []

#             (x, y, w, h) = ROIs[0, ii, :]

#             cls_num = np.argmax(P_cls[0, ii, :])
#             try:
#                 (tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)]
#                 tx /= C.classifier_regr_std[0]
#                 ty /= C.classifier_regr_std[1]
#                 tw /= C.classifier_regr_std[2]
#                 th /= C.classifier_regr_std[3]
#                 x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th)
#             except:
#                 pass
#             bboxes[cls_name].append(
#                 [16 * x, 16 * y, 16 * (x + w), 16 * (y + h)])
#             probs[cls_name].append(np.max(P_cls[0, ii, :]))

#     all_dets = []

#     for key in bboxes:
#         bbox = np.array(bboxes[key])

#         # Apply non-max-suppression on final bboxes to get the output bounding boxe
#         new_boxes, new_probs = non_max_suppression_fast(
#             bbox, np.array(probs[key]), overlap_thresh=0.5)
#         for jk in range(new_boxes.shape[0]):
#             (x1, y1, x2, y2) = new_boxes[jk, :]
#             det = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2,
#                   'class': key, 'prob': new_probs[jk]}
#             all_dets.append(det)

#     print('Elapsed time = {}'.format(time.time() - st))
#     t, p = get_map(all_dets, img_data['bboxes'], (fx, fy))
#     for key in t.keys():
#         if key not in T:
#             T[key] = []
#             P[key] = []
#         T[key].extend(t[key])
#         P[key].extend(p[key])
#     all_aps = []
#     for key in T.keys():
#         ap = average_precision_score(T[key], P[key])
#         print('{} AP: {}'.format(key, ap))
#         all_aps.append(ap)
#     print('mAP = {}'.format(np.mean(np.array(all_aps))))
#     mAPs.append(np.mean(np.array(all_aps)))
#     print(T)
#     print(P)

# print()
# print('mean average precision:', np.nanmean(np.array(mAPs)))

import os
import cv2
import numpy as np
import sys
import pickle
from optparse import OptionParser
import time
from keras_frcnn import config
import keras_frcnn.resnet as nn
from keras import backend as K
from keras.layers import Input
from keras.models import Model
from keras_frcnn import roi_helpers
from keras_frcnn import data_generators
from sklearn.metrics import average_precision_score


def get_map(pred, gt, f):
	T = {}
	P = {}
	fx, fy = f

	for bbox in gt:
		bbox['bbox_matched'] = False

	pred_probs = np.array([s['prob'] for s in pred])
	box_idx_sorted_by_prob = np.argsort(pred_probs)[::-1]

	for box_idx in box_idx_sorted_by_prob:
		pred_box = pred[box_idx]
		pred_class = pred_box['class']
		pred_x1 = pred_box['x1']
		pred_x2 = pred_box['x2']
		pred_y1 = pred_box['y1']
		pred_y2 = pred_box['y2']
		pred_prob = pred_box['prob']
		if pred_class not in P:
			P[pred_class] = []
			T[pred_class] = []
		P[pred_class].append(pred_prob)
		found_match = False

		for gt_box in gt:
			gt_class = gt_box['class']
			gt_x1 = gt_box['x1']/fx
			gt_x2 = gt_box['x2']/fx
			gt_y1 = gt_box['y1']/fy
			gt_y2 = gt_box['y2']/fy
			gt_seen = gt_box['bbox_matched']
			if gt_class != pred_class:
				continue
			if gt_seen:
				continue
			iou = data_generators.iou((pred_x1, pred_y1, pred_x2, pred_y2), (gt_x1, gt_y1, gt_x2, gt_y2))
			if iou >= 0.5:
				found_match = True
				gt_box['bbox_matched'] = True
				break
			else:
				continue

		T[pred_class].append(int(found_match))

	for gt_box in gt:
		if not gt_box['bbox_matched']: #and not gt_box['difficult']:
			if gt_box['class'] not in P:
				P[gt_box['class']] = []
				T[gt_box['class']] = []

			T[gt_box['class']].append(1)
			P[gt_box['class']].append(0)

	#import pdb
	#pdb.set_trace()
	return T, P

sys.setrecursionlimit(40000)

parser = OptionParser()

parser.add_option("-p", "--path", dest="test_path", help="Path to test data.")
parser.add_option("-n", "--num_rois", dest="num_rois",
				help="Number of ROIs per iteration. Higher means more memory use.", default=32)
parser.add_option("--config_filename", dest="config_filename", help=
				"Location to read the metadata related to the training (generated when training).",
				default="config.pickle")
parser.add_option("-o", "--parser", dest="parser", help="Parser to use. One of simple or pascal_voc",
				default="pascal_voc"),

(options, args) = parser.parse_args()

if not options.test_path:   # if filename is not given
	parser.error('Error: path to test data must be specified. Pass --path to command line')


if options.parser == 'pascal_voc':
	from keras_frcnn.pascal_voc_parser import get_data
elif options.parser == 'simple':
	from keras_frcnn.simple_parser import get_data
else:
	raise ValueError("Command line option parser must be one of 'pascal_voc' or 'simple'")

config_output_filename = options.config_filename

with open(config_output_filename, 'rb') as f_in:
	C = pickle.load(f_in)

# turn off any data augmentation at test time
C.use_horizontal_flips = False
C.use_vertical_flips = False
C.rot_90 = False

img_path = options.test_path


def format_img(img, C):
	img_min_side = float(C.im_size)
	(height,width,_) = img.shape
	
	if width <= height:
		f = img_min_side/width
		new_height = int(f * height)
		new_width = int(img_min_side)
	else:
		f = img_min_side/height
		new_width = int(f * width)
		new_height = int(img_min_side)
	fx = width/float(new_width)
	fy = height/float(new_height)
	img = cv2.resize(img, (new_width, new_height), interpolation=cv2.INTER_CUBIC)
	img = img[:, :, (2, 1, 0)]
	img = img.astype(np.float32)
	img[:, :, 0] -= C.img_channel_mean[0]
	img[:, :, 1] -= C.img_channel_mean[1]
	img[:, :, 2] -= C.img_channel_mean[2]
	img /= C.img_scaling_factor
	img = np.transpose(img, (2, 0, 1))
	img = np.expand_dims(img, axis=0)
	return img, fx, fy


class_mapping = C.class_mapping

if 'bg' not in class_mapping:
	class_mapping['bg'] = len(class_mapping)

class_mapping = {v: k for k, v in class_mapping.items()}
print(class_mapping)
class_to_color = {class_mapping[v]: np.random.randint(0, 255, 3) for v in class_mapping}
C.num_rois = int(options.num_rois)

if K.image_dim_ordering() == 'th':
	input_shape_img = (3, None, None)
	input_shape_features = (1024, None, None)
else:
	input_shape_img = (None, None, 3)
	input_shape_features = (None, None, 1024)


img_input = Input(shape=input_shape_img)
roi_input = Input(shape=(C.num_rois, 4))
feature_map_input = Input(shape=input_shape_features)

# define the base network (resnet here, can be VGG, Inception, etc)
shared_layers = nn.nn_base(img_input, trainable=True)

# define the RPN, built on the base layers
num_anchors = len(C.anchor_box_scales) * len(C.anchor_box_ratios)
rpn_layers = nn.rpn(shared_layers, num_anchors)

classifier = nn.classifier(feature_map_input, roi_input, C.num_rois, nb_classes=len(class_mapping), trainable=True)

model_rpn = Model(img_input, rpn_layers)
model_classifier_only = Model([feature_map_input, roi_input], classifier)

model_classifier = Model([feature_map_input, roi_input], classifier)

model_rpn.load_weights(C.model_path, by_name=True)
model_classifier.load_weights(C.model_path, by_name=True)

model_rpn.compile(optimizer='sgd', loss='mse')
model_classifier.compile(optimizer='sgd', loss='mse')

all_imgs, _, _ = get_data(options.test_path)
test_imgs = [s for s in all_imgs if s['imageset'] == 'test']


T = {}
P = {}
for idx, img_data in enumerate(test_imgs):
	print('{}/{}'.format(idx,len(test_imgs)))
	st = time.time()
	filepath = img_data['filepath']

	img = cv2.imread(filepath)

	X, fx, fy = format_img(img, C)

	if K.image_dim_ordering() == 'tf':
		X = np.transpose(X, (0, 2, 3, 1))

	# get the feature maps and output from the RPN
	[Y1, Y2, F] = model_rpn.predict(X)

	R = roi_helpers.rpn_to_roi(Y1, Y2, C, K.image_dim_ordering(), overlap_thresh=0.7)

	# convert from (x1,y1,x2,y2) to (x,y,w,h)
	R[:, 2] -= R[:, 0]
	R[:, 3] -= R[:, 1]

	# apply the spatial pyramid pooling to the proposed regions
	bboxes = {}
	probs = {}

	for jk in range(R.shape[0] // C.num_rois + 1):
		ROIs = np.expand_dims(R[C.num_rois * jk:C.num_rois * (jk + 1), :], axis=0)
		if ROIs.shape[1] == 0:
			break

		if jk == R.shape[0] // C.num_rois:
			# pad R
			curr_shape = ROIs.shape
			target_shape = (curr_shape[0], C.num_rois, curr_shape[2])
			ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype)
			ROIs_padded[:, :curr_shape[1], :] = ROIs
			ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :]
			ROIs = ROIs_padded

		[P_cls, P_regr] = model_classifier_only.predict([F, ROIs])

		for ii in range(P_cls.shape[1]):

			if np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1):
				continue

			cls_name = class_mapping[np.argmax(P_cls[0, ii, :])]

			if cls_name not in bboxes:
				bboxes[cls_name] = []
				probs[cls_name] = []

			(x, y, w, h) = ROIs[0, ii, :]

			cls_num = np.argmax(P_cls[0, ii, :])
			try:
				(tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)]
				tx /= C.classifier_regr_std[0]
				ty /= C.classifier_regr_std[1]
				tw /= C.classifier_regr_std[2]
				th /= C.classifier_regr_std[3]
				x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th)
			except:
				pass
			bboxes[cls_name].append([16 * x, 16 * y, 16 * (x + w), 16 * (y + h)])
			probs[cls_name].append(np.max(P_cls[0, ii, :]))

	all_dets = []

	for key in bboxes:
		bbox = np.array(bboxes[key])

		new_boxes, new_probs = roi_helpers.non_max_suppression_fast(bbox, np.array(probs[key]), overlap_thresh=0.5)
		for jk in range(new_boxes.shape[0]):
			(x1, y1, x2, y2) = new_boxes[jk, :]
			det = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2, 'class': key, 'prob': new_probs[jk]}
			all_dets.append(det)


	print('Elapsed time = {}'.format(time.time() - st))
	t, p = get_map(all_dets, img_data['bboxes'], (fx, fy))
	for key in t.keys():
		if key not in T:
			T[key] = []
			P[key] = []
		T[key].extend(t[key])
		P[key].extend(p[key])
	all_aps = []
	for key in T.keys():
		ap = average_precision_score(T[key], P[key])
		print('{} AP: {}'.format(key, ap))
		all_aps.append(ap)
	print('mAP = {}'.format(np.mean(np.array(all_aps))))
	#print(T)
	#print(P)
	
#	if the above code throws error, comment the code and uncomment the below code to get the mAP.
	
	
# def non_max_suppression_fast(boxes, probs, overlap_thresh=0.9, max_boxes=300):
# 	# code used from here: http://www.pyimagesearch.com/2015/02/16/faster-non-maximum-suppression-python/
# 	# if there are no boxes, return an empty list
  
#     # Process explanation:
#     #   Step 1: Sort the probs list
#     #   Step 2: Find the larget prob 'Last' in the list and save it to the pick list
#     #   Step 3: Calculate the IoU with 'Last' box and other boxes in the list. If the IoU is larger than overlap_threshold, delete the box from list
#     #   Step 4: Repeat step 2 and step 3 until there is no item in the probs list 
# 	if len(boxes) == 0:
# 		return []

# 	# grab the coordinates of the bounding boxes
# 	x1 = boxes[:, 0]
# 	y1 = boxes[:, 1]
# 	x2 = boxes[:, 2]
# 	y2 = boxes[:, 3]

# 	np.testing.assert_array_less(x1, x2)
# 	np.testing.assert_array_less(y1, y2)

# 	# if the bounding boxes integers, convert them to floats --
# 	# this is important since we'll be doing a bunch of divisions
# 	if boxes.dtype.kind == "i":
# 		boxes = boxes.astype("float")

# 	# initialize the list of picked indexes	
# 	pick = []

# 	# calculate the areas
# 	area = (x2 - x1) * (y2 - y1)

# 	# sort the bounding boxes 
# 	idxs = np.argsort(probs)

# 	# keep looping while some indexes still remain in the indexes
# 	# list
# 	while len(idxs) > 0:
# 		# grab the last index in the indexes list and add the
# 		# index value to the list of picked indexes
# 		last = len(idxs) - 1
# 		i = idxs[last]
# 		pick.append(i)

# 		# find the intersection

# 		xx1_int = np.maximum(x1[i], x1[idxs[:last]])
# 		yy1_int = np.maximum(y1[i], y1[idxs[:last]])
# 		xx2_int = np.minimum(x2[i], x2[idxs[:last]])
# 		yy2_int = np.minimum(y2[i], y2[idxs[:last]])

# 		ww_int = np.maximum(0, xx2_int - xx1_int)
# 		hh_int = np.maximum(0, yy2_int - yy1_int)

# 		area_int = ww_int * hh_int

# 		# find the union
# 		area_union = area[i] + area[idxs[:last]] - area_int

# 		# compute the ratio of overlap
# 		overlap = area_int/(area_union + 1e-6)

# 		# delete all indexes from the index list that have
# 		idxs = np.delete(idxs, np.concatenate(([last],
# 			np.where(overlap > overlap_thresh)[0])))

# 		if len(pick) >= max_boxes:
# 			break

# 	# return only the bounding boxes that were picked using the integer data type
# 	boxes = boxes[pick].astype("int")
# 	probs = probs[pick]
# 	return boxes, probs

# def apply_regr_np(X, T):
# 	"""Apply regression layer to all anchors in one feature map

# 	Args:
# 		X: shape=(4, 18, 25) the current anchor type for all points in the feature map
# 		T: regression layer shape=(4, 18, 25)

# 	Returns:
# 		X: regressed position and size for current anchor
# 	"""
# 	try:
# 		x = X[0, :, :]
# 		y = X[1, :, :]
# 		w = X[2, :, :]
# 		h = X[3, :, :]

# 		tx = T[0, :, :]
# 		ty = T[1, :, :]
# 		tw = T[2, :, :]
# 		th = T[3, :, :]

# 		cx = x + w/2.
# 		cy = y + h/2.
# 		cx1 = tx * w + cx
# 		cy1 = ty * h + cy

# 		w1 = np.exp(tw.astype(np.float64)) * w
# 		h1 = np.exp(th.astype(np.float64)) * h
# 		x1 = cx1 - w1/2.
# 		y1 = cy1 - h1/2.

# 		x1 = np.round(x1)
# 		y1 = np.round(y1)
# 		w1 = np.round(w1)
# 		h1 = np.round(h1)
# 		return np.stack([x1, y1, w1, h1])
# 	except Exception as e:
# 		print(e)
# 		return X
    
# def apply_regr(x, y, w, h, tx, ty, tw, th):
#     # Apply regression to x, y, w and h
# 	try:
# 		cx = x + w/2.
# 		cy = y + h/2.
# 		cx1 = tx * w + cx
# 		cy1 = ty * h + cy
# 		w1 = math.exp(tw) * w
# 		h1 = math.exp(th) * h
# 		x1 = cx1 - w1/2.
# 		y1 = cy1 - h1/2.
# 		x1 = int(round(x1))
# 		y1 = int(round(y1))
# 		w1 = int(round(w1))
# 		h1 = int(round(h1))

# 		return x1, y1, w1, h1

# 	except ValueError:
# 		return x, y, w, h
# 	except OverflowError:
# 		return x, y, w, h
# 	except Exception as e:
# 		print(e)
# 		return x, y, w, h


# def rpn_to_roi(rpn_layer, regr_layer, C, dim_ordering, use_regr=True, max_boxes=300,overlap_thresh=0.9):
# 	"""Convert rpn layer to roi bboxes

# 	Args: (num_anchors = 9)
# 		rpn_layer: output layer for rpn classification 
# 			shape (1, feature_map.height, feature_map.width, num_anchors)
# 			Might be (1, 18, 25, 9) if resized image is 400 width and 300
# 		regr_layer: output layer for rpn regression
# 			shape (1, feature_map.height, feature_map.width, num_anchors)
# 			Might be (1, 18, 25, 36) if resized image is 400 width and 300
# 		C: config
# 		use_regr: Wether to use bboxes regression in rpn
# 		max_boxes: max bboxes number for non-max-suppression (NMS)
# 		overlap_thresh: If iou in NMS is larger than this threshold, drop the box

# 	Returns:
# 		result: boxes from non-max-suppression (shape=(300, 4))
# 			boxes: coordinates for bboxes (on the feature map)
# 	"""
# 	regr_layer = regr_layer / C.std_scaling

# 	anchor_sizes = C.anchor_box_scales   # (3 in here)
# 	anchor_ratios = C.anchor_box_ratios  # (3 in here)

# 	assert rpn_layer.shape[0] == 1

# 	(rows, cols) = rpn_layer.shape[1:3]

# 	curr_layer = 0

# 	# A.shape = (4, feature_map.height, feature_map.width, num_anchors) 
# 	# Might be (4, 18, 25, 9) if resized image is 400 width and 300
# 	# A is the coordinates for 9 anchors for every point in the feature map 
# 	# => all 18x25x9=4050 anchors cooridnates
# 	A = np.zeros((4, rpn_layer.shape[1], rpn_layer.shape[2], rpn_layer.shape[3]))

# 	for anchor_size in anchor_sizes:
# 		for anchor_ratio in anchor_ratios:
# 			# anchor_x = (128 * 1) / 16 = 8  => width of current anchor
# 			# anchor_y = (128 * 2) / 16 = 16 => height of current anchor
# 			anchor_x = (anchor_size * anchor_ratio[0])/C.rpn_stride
# 			anchor_y = (anchor_size * anchor_ratio[1])/C.rpn_stride
			
# 			# curr_layer: 0~8 (9 anchors)
# 			# the Kth anchor of all position in the feature map (9th in total)
# 			regr = regr_layer[0, :, :, 4 * curr_layer:4 * curr_layer + 4] # shape => (18, 25, 4)
# 			regr = np.transpose(regr, (2, 0, 1)) # shape => (4, 18, 25)

# 			# Create 18x25 mesh grid
# 			# For every point in x, there are all the y points and vice versa
# 			# X.shape = (18, 25)
# 			# Y.shape = (18, 25)
# 			X, Y = np.meshgrid(np.arange(cols),np. arange(rows))

# 			# Calculate anchor position and size for each feature map point
# 			A[0, :, :, curr_layer] = X - anchor_x/2 # Top left x coordinate
# 			A[1, :, :, curr_layer] = Y - anchor_y/2 # Top left y coordinate
# 			A[2, :, :, curr_layer] = anchor_x       # width of current anchor
# 			A[3, :, :, curr_layer] = anchor_y       # height of current anchor

# 			# Apply regression to x, y, w and h if there is rpn regression layer
# 			if use_regr:
# 				A[:, :, :, curr_layer] = apply_regr_np(A[:, :, :, curr_layer], regr)

# 			# Avoid width and height exceeding 1
# 			A[2, :, :, curr_layer] = np.maximum(1, A[2, :, :, curr_layer])
# 			A[3, :, :, curr_layer] = np.maximum(1, A[3, :, :, curr_layer])

# 			# Convert (x, y , w, h) to (x1, y1, x2, y2)
# 			# x1, y1 is top left coordinate
# 			# x2, y2 is bottom right coordinate
# 			A[2, :, :, curr_layer] += A[0, :, :, curr_layer]
# 			A[3, :, :, curr_layer] += A[1, :, :, curr_layer]

# 			# Avoid bboxes drawn outside the feature map
# 			A[0, :, :, curr_layer] = np.maximum(0, A[0, :, :, curr_layer])
# 			A[1, :, :, curr_layer] = np.maximum(0, A[1, :, :, curr_layer])
# 			A[2, :, :, curr_layer] = np.minimum(cols-1, A[2, :, :, curr_layer])
# 			A[3, :, :, curr_layer] = np.minimum(rows-1, A[3, :, :, curr_layer])

# 			curr_layer += 1

# 	all_boxes = np.reshape(A.transpose((0, 3, 1, 2)), (4, -1)).transpose((1, 0))  # shape=(4050, 4)
# 	all_probs = rpn_layer.transpose((0, 3, 1, 2)).reshape((-1))                   # shape=(4050,)

# 	x1 = all_boxes[:, 0]
# 	y1 = all_boxes[:, 1]
# 	x2 = all_boxes[:, 2]
# 	y2 = all_boxes[:, 3]

# 	# Find out the bboxes which is illegal and delete them from bboxes list
# 	idxs = np.where((x1 - x2 >= 0) | (y1 - y2 >= 0))

# 	all_boxes = np.delete(all_boxes, idxs, 0)
# 	all_probs = np.delete(all_probs, idxs, 0)

# 	# Apply non_max_suppression
# 	# Only extract the bboxes. Don't need rpn probs in the later process
# 	result = non_max_suppression_fast(all_boxes, all_probs, overlap_thresh=overlap_thresh, max_boxes=max_boxes)[0]

# 	return result


# def format_img_map(img, C):
#     """Format image for mAP. Resize original image to C.im_size (300 in here)

#     Args:
#             img: cv2 image
#             C: config

#     Returns:
#             img: Scaled and normalized image with expanding dimension
#             fx: ratio for width scaling
#             fy: ratio for height scaling
#     """

#     img_min_side = float(C.im_size)
#     (height, width, _) = img.shape

#     if width <= height:
#         f = img_min_side/width
#         new_height = int(f * height)
#         new_width = int(img_min_side)
#     else:
#         f = img_min_side/height
#         new_width = int(f * width)
#         new_height = int(img_min_side)
#     fx = width/float(new_width)
#     fy = height/float(new_height)
#     img = cv2.resize(img, (new_width, new_height),
#                      interpolation=cv2.INTER_CUBIC)
#     # Change image channel from BGR to RGB
#     img = img[:, :, (2, 1, 0)]
#     img = img.astype(np.float32)
#     img[:, :, 0] -= C.img_channel_mean[0]
#     img[:, :, 1] -= C.img_channel_mean[1]
#     img[:, :, 2] -= C.img_channel_mean[2]
#     img /= C.img_scaling_factor
#     # Change img shape from (height, width, channel) to (channel, height, width)
#     img = np.transpose(img, (2, 0, 1))
#     # Expand one dimension at axis 0
#     # img shape becames (1, channel, height, width)
#     img = np.expand_dims(img, axis=0)
#     return img, fx, fy


# T = {}
# P = {}
# mAPs = []
# for idx, img_data in enumerate(test_imgs):
#     print('{}/{}'.format(idx, len(test_imgs)))
#     st = time.time()
#     filepath = img_data['filepath']

#     img = cv2.imread(filepath)

#     X, fx, fy = format_img_map(img, C)

#     # Change X (img) shape from (1, channel, height, width) to (1, height, width, channel)
#     X = np.transpose(X, (0, 2, 3, 1))

#     # get the feature maps and output from the RPN
#     [Y1, Y2, F] = model_rpn.predict(X)

#     R = rpn_to_roi(Y1, Y2, C, K.image_data_format(), overlap_thresh=0.7)

#     # convert from (x1,y1,x2,y2) to (x,y,w,h)
#     R[:, 2] -= R[:, 0]
#     R[:, 3] -= R[:, 1]

#     # apply the spatial pyramid pooling to the proposed regions
#     bboxes = {}
#     probs = {}

#     for jk in range(R.shape[0] // C.num_rois + 1):
#         ROIs = np.expand_dims(
#             R[C.num_rois * jk:C.num_rois * (jk + 1), :], axis=0)
#         if ROIs.shape[1] == 0:
#             break

#         if jk == R.shape[0] // C.num_rois:
#             # pad R
#             curr_shape = ROIs.shape
#             target_shape = (curr_shape[0], C.num_rois, curr_shape[2])
#             ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype)
#             ROIs_padded[:, :curr_shape[1], :] = ROIs
#             ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :]
#             ROIs = ROIs_padded

#         [P_cls, P_regr] = model_classifier_only.predict([F, ROIs])

#         # Calculate all classes' bboxes coordinates on resized image (300, 400)
#         # Drop 'bg' classes bboxes
#         for ii in range(P_cls.shape[1]):

#             # If class name is 'bg', continue
#             if np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1):
#                 continue

#             # Get class name
#             cls_name = class_mapping[np.argmax(P_cls[0, ii, :])]

#             if cls_name not in bboxes:
#                 bboxes[cls_name] = []
#                 probs[cls_name] = []

#             (x, y, w, h) = ROIs[0, ii, :]

#             cls_num = np.argmax(P_cls[0, ii, :])
#             try:
#                 (tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)]
#                 tx /= C.classifier_regr_std[0]
#                 ty /= C.classifier_regr_std[1]
#                 tw /= C.classifier_regr_std[2]
#                 th /= C.classifier_regr_std[3]
#                 x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th)
#             except:
#                 pass
#             bboxes[cls_name].append(
#                 [16 * x, 16 * y, 16 * (x + w), 16 * (y + h)])
#             probs[cls_name].append(np.max(P_cls[0, ii, :]))

#     all_dets = []

#     for key in bboxes:
#         bbox = np.array(bboxes[key])

#         # Apply non-max-suppression on final bboxes to get the output bounding boxe
#         new_boxes, new_probs = non_max_suppression_fast(
#             bbox, np.array(probs[key]), overlap_thresh=0.5)
#         for jk in range(new_boxes.shape[0]):
#             (x1, y1, x2, y2) = new_boxes[jk, :]
#             det = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2,
#                   'class': key, 'prob': new_probs[jk]}
#             all_dets.append(det)

#     print('Elapsed time = {}'.format(time.time() - st))
#     t, p = get_map(all_dets, img_data['bboxes'], (fx, fy))
#     for key in t.keys():
#         if key not in T:
#             T[key] = []
#             P[key] = []
#         T[key].extend(t[key])
#         P[key].extend(p[key])
#     all_aps = []
#     for key in T.keys():
#         ap = average_precision_score(T[key], P[key])
#         print('{} AP: {}'.format(key, ap))
#         all_aps.append(ap)
#     print('mAP = {}'.format(np.mean(np.array(all_aps))))
#     mAPs.append(np.mean(np.array(all_aps)))
#     print(T)
#     print(P)

# print()
# print('mean average precision:', np.nanmean(np.array(mAPs)))
#and not gt_box['difficult']: #import pdb #pdb.set_trace() # if filename is not given # turn off any data augmentation at test time # define the base network (resnet here, can be VGG, Inception, etc) # define the RPN, built on the base layers # get the feature maps and output from the RPN # convert from (x1,y1,x2,y2) to (x,y,w,h) # apply the spatial pyramid pooling to the proposed regions # pad R #print(T) #print(P) #	if the above code throws error, comment the code and uncomment the below code to get the mAP. # def non_max_suppression_fast(boxes, probs, overlap_thresh=0.9, max_boxes=300): # 	# code used from here: http://www.pyimagesearch.com/2015/02/16/faster-non-maximum-suppression-python/ # 	# if there are no boxes, return an empty list #     # Process explanation: #     #   Step 1: Sort the probs list #     #   Step 2: Find the larget prob 'Last' in the list and save it to the pick list #     #   Step 3: Calculate the IoU with 'Last' box and other boxes in the list. If the IoU is larger than overlap_threshold, delete the box from list #     #   Step 4: Repeat step 2 and step 3 until there is no item in the probs list # 	if len(boxes) == 0: # 		return [] # 	# grab the coordinates of the bounding boxes # 	x1 = boxes[:, 0] # 	y1 = boxes[:, 1] # 	x2 = boxes[:, 2] # 	y2 = boxes[:, 3] # 	np.testing.assert_array_less(x1, x2) # 	np.testing.assert_array_less(y1, y2) # 	# if the bounding boxes integers, convert them to floats -- # 	# this is important since we'll be doing a bunch of divisions # 	if boxes.dtype.kind == "i": # 		boxes = boxes.astype("float") # 	# initialize the list of picked indexes # 	pick = [] # 	# calculate the areas # 	area = (x2 - x1) * (y2 - y1) # 	# sort the bounding boxes # 	idxs = np.argsort(probs) # 	# keep looping while some indexes still remain in the indexes # 	# list # 	while len(idxs) > 0: # 		# grab the last index in the indexes list and add the # 		# index value to the list of picked indexes # 		last = len(idxs) - 1 # 		i = idxs[last] # 		pick.append(i) # 		# find the intersection # 		xx1_int = np.maximum(x1[i], x1[idxs[:last]]) # 		yy1_int = np.maximum(y1[i], y1[idxs[:last]]) # 		xx2_int = np.minimum(x2[i], x2[idxs[:last]]) # 		yy2_int = np.minimum(y2[i], y2[idxs[:last]]) # 		ww_int = np.maximum(0, xx2_int - xx1_int) # 		hh_int = np.maximum(0, yy2_int - yy1_int) # 		area_int = ww_int * hh_int # 		# find the union # 		area_union = area[i] + area[idxs[:last]] - area_int # 		# compute the ratio of overlap # 		overlap = area_int/(area_union + 1e-6) # 		# delete all indexes from the index list that have # 		idxs = np.delete(idxs, np.concatenate(([last], # 			np.where(overlap > overlap_thresh)[0]))) # 		if len(pick) >= max_boxes: # 			break # 	# return only the bounding boxes that were picked using the integer data type # 	boxes = boxes[pick].astype("int") # 	probs = probs[pick] # 	return boxes, probs # def apply_regr_np(X, T): # 	"""Apply regression layer to all anchors in one feature map # 	Args: # 		X: shape=(4, 18, 25) the current anchor type for all points in the feature map # 		T: regression layer shape=(4, 18, 25) # 	Returns: # 		X: regressed position and size for current anchor # 	""" # 	try: # 		x = X[0, :, :] # 		y = X[1, :, :] # 		w = X[2, :, :] # 		h = X[3, :, :] # 		tx = T[0, :, :] # 		ty = T[1, :, :] # 		tw = T[2, :, :] # 		th = T[3, :, :] # 		cx = x + w/2. # 		cy = y + h/2. # 		cx1 = tx * w + cx # 		cy1 = ty * h + cy # 		w1 = np.exp(tw.astype(np.float64)) * w # 		h1 = np.exp(th.astype(np.float64)) * h # 		x1 = cx1 - w1/2. # 		y1 = cy1 - h1/2. # 		x1 = np.round(x1) # 		y1 = np.round(y1) # 		w1 = np.round(w1) # 		h1 = np.round(h1) # 		return np.stack([x1, y1, w1, h1]) # 	except Exception as e: # 		print(e) # 		return X # def apply_regr(x, y, w, h, tx, ty, tw, th): #     # Apply regression to x, y, w and h # 	try: # 		cx = x + w/2. # 		cy = y + h/2. # 		cx1 = tx * w + cx # 		cy1 = ty * h + cy # 		w1 = math.exp(tw) * w # 		h1 = math.exp(th) * h # 		x1 = cx1 - w1/2. # 		y1 = cy1 - h1/2. # 		x1 = int(round(x1)) # 		y1 = int(round(y1)) # 		w1 = int(round(w1)) # 		h1 = int(round(h1)) # 		return x1, y1, w1, h1 # 	except ValueError: # 		return x, y, w, h # 	except OverflowError: # 		return x, y, w, h # 	except Exception as e: # 		print(e) # 		return x, y, w, h # def rpn_to_roi(rpn_layer, regr_layer, C, dim_ordering, use_regr=True, max_boxes=300,overlap_thresh=0.9): # 	"""Convert rpn layer to roi bboxes # 	Args: (num_anchors = 9) # 		rpn_layer: output layer for rpn classification # 			shape (1, feature_map.height, feature_map.width, num_anchors) # 			Might be (1, 18, 25, 9) if resized image is 400 width and 300 # 		regr_layer: output layer for rpn regression # 			shape (1, feature_map.height, feature_map.width, num_anchors) # 			Might be (1, 18, 25, 36) if resized image is 400 width and 300 # 		C: config # 		use_regr: Wether to use bboxes regression in rpn # 		max_boxes: max bboxes number for non-max-suppression (NMS) # 		overlap_thresh: If iou in NMS is larger than this threshold, drop the box # 	Returns: # 		result: boxes from non-max-suppression (shape=(300, 4)) # 			boxes: coordinates for bboxes (on the feature map) # 	""" # 	regr_layer = regr_layer / C.std_scaling # 	anchor_sizes = C.anchor_box_scales   # (3 in here) # 	anchor_ratios = C.anchor_box_ratios  # (3 in here) # 	assert rpn_layer.shape[0] == 1 # 	(rows, cols) = rpn_layer.shape[1:3] # 	curr_layer = 0 # 	# A.shape = (4, feature_map.height, feature_map.width, num_anchors) # 	# Might be (4, 18, 25, 9) if resized image is 400 width and 300 # 	# A is the coordinates for 9 anchors for every point in the feature map # 	# => all 18x25x9=4050 anchors cooridnates # 	A = np.zeros((4, rpn_layer.shape[1], rpn_layer.shape[2], rpn_layer.shape[3])) # 	for anchor_size in anchor_sizes: # 		for anchor_ratio in anchor_ratios: # 			# anchor_x = (128 * 1) / 16 = 8  => width of current anchor # 			# anchor_y = (128 * 2) / 16 = 16 => height of current anchor # 			anchor_x = (anchor_size * anchor_ratio[0])/C.rpn_stride # 			anchor_y = (anchor_size * anchor_ratio[1])/C.rpn_stride # 			# curr_layer: 0~8 (9 anchors) # 			# the Kth anchor of all position in the feature map (9th in total) # 			regr = regr_layer[0, :, :, 4 * curr_layer:4 * curr_layer + 4] # shape => (18, 25, 4) # 			regr = np.transpose(regr, (2, 0, 1)) # shape => (4, 18, 25) # 			# Create 18x25 mesh grid # 			# For every point in x, there are all the y points and vice versa # 			# X.shape = (18, 25) # 			# Y.shape = (18, 25) # 			X, Y = np.meshgrid(np.arange(cols),np. arange(rows)) # 			# Calculate anchor position and size for each feature map point # 			A[0, :, :, curr_layer] = X - anchor_x/2 # Top left x coordinate # 			A[1, :, :, curr_layer] = Y - anchor_y/2 # Top left y coordinate # 			A[2, :, :, curr_layer] = anchor_x       # width of current anchor # 			A[3, :, :, curr_layer] = anchor_y       # height of current anchor # 			# Apply regression to x, y, w and h if there is rpn regression layer # 			if use_regr: # 				A[:, :, :, curr_layer] = apply_regr_np(A[:, :, :, curr_layer], regr) # 			# Avoid width and height exceeding 1 # 			A[2, :, :, curr_layer] = np.maximum(1, A[2, :, :, curr_layer]) # 			A[3, :, :, curr_layer] = np.maximum(1, A[3, :, :, curr_layer]) # 			# Convert (x, y , w, h) to (x1, y1, x2, y2) # 			# x1, y1 is top left coordinate # 			# x2, y2 is bottom right coordinate # 			A[2, :, :, curr_layer] += A[0, :, :, curr_layer] # 			A[3, :, :, curr_layer] += A[1, :, :, curr_layer] # 			# Avoid bboxes drawn outside the feature map # 			A[0, :, :, curr_layer] = np.maximum(0, A[0, :, :, curr_layer]) # 			A[1, :, :, curr_layer] = np.maximum(0, A[1, :, :, curr_layer]) # 			A[2, :, :, curr_layer] = np.minimum(cols-1, A[2, :, :, curr_layer]) # 			A[3, :, :, curr_layer] = np.minimum(rows-1, A[3, :, :, curr_layer]) # 			curr_layer += 1 # 	all_boxes = np.reshape(A.transpose((0, 3, 1, 2)), (4, -1)).transpose((1, 0))  # shape=(4050, 4) # 	all_probs = rpn_layer.transpose((0, 3, 1, 2)).reshape((-1))                   # shape=(4050,) # 	x1 = all_boxes[:, 0] # 	y1 = all_boxes[:, 1] # 	x2 = all_boxes[:, 2] # 	y2 = all_boxes[:, 3] # 	# Find out the bboxes which is illegal and delete them from bboxes list # 	idxs = np.where((x1 - x2 >= 0) | (y1 - y2 >= 0)) # 	all_boxes = np.delete(all_boxes, idxs, 0) # 	all_probs = np.delete(all_probs, idxs, 0) # 	# Apply non_max_suppression # 	# Only extract the bboxes. Don't need rpn probs in the later process # 	result = non_max_suppression_fast(all_boxes, all_probs, overlap_thresh=overlap_thresh, max_boxes=max_boxes)[0] # 	return result # def format_img_map(img, C): #     """Format image for mAP. Resize original image to C.im_size (300 in here) #     Args: #             img: cv2 image #             C: config #     Returns: #             img: Scaled and normalized image with expanding dimension #             fx: ratio for width scaling #             fy: ratio for height scaling #     """ #     img_min_side = float(C.im_size) #     (height, width, _) = img.shape #     if width <= height: #         f = img_min_side/width #         new_height = int(f * height) #         new_width = int(img_min_side) #     else: #         f = img_min_side/height #         new_width = int(f * width) #         new_height = int(img_min_side) #     fx = width/float(new_width) #     fy = height/float(new_height) #     img = cv2.resize(img, (new_width, new_height), #                      interpolation=cv2.INTER_CUBIC) #     # Change image channel from BGR to RGB #     img = img[:, :, (2, 1, 0)] #     img = img.astype(np.float32) #     img[:, :, 0] -= C.img_channel_mean[0] #     img[:, :, 1] -= C.img_channel_mean[1] #     img[:, :, 2] -= C.img_channel_mean[2] #     img /= C.img_scaling_factor #     # Change img shape from (height, width, channel) to (channel, height, width) #     img = np.transpose(img, (2, 0, 1)) #     # Expand one dimension at axis 0 #     # img shape becames (1, channel, height, width) #     img = np.expand_dims(img, axis=0) #     return img, fx, fy # T = {} # P = {} # mAPs = [] # for idx, img_data in enumerate(test_imgs): #     print('{}/{}'.format(idx, len(test_imgs))) #     st = time.time() #     filepath = img_data['filepath'] #     img = cv2.imread(filepath) #     X, fx, fy = format_img_map(img, C) #     # Change X (img) shape from (1, channel, height, width) to (1, height, width, channel) #     X = np.transpose(X, (0, 2, 3, 1)) #     # get the feature maps and output from the RPN #     [Y1, Y2, F] = model_rpn.predict(X) #     R = rpn_to_roi(Y1, Y2, C, K.image_data_format(), overlap_thresh=0.7) #     # convert from (x1,y1,x2,y2) to (x,y,w,h) #     R[:, 2] -= R[:, 0] #     R[:, 3] -= R[:, 1] #     # apply the spatial pyramid pooling to the proposed regions #     bboxes = {} #     probs = {} #     for jk in range(R.shape[0] // C.num_rois + 1): #         ROIs = np.expand_dims( #             R[C.num_rois * jk:C.num_rois * (jk + 1), :], axis=0) #         if ROIs.shape[1] == 0: #             break #         if jk == R.shape[0] // C.num_rois: #             # pad R #             curr_shape = ROIs.shape #             target_shape = (curr_shape[0], C.num_rois, curr_shape[2]) #             ROIs_padded = np.zeros(target_shape).astype(ROIs.dtype) #             ROIs_padded[:, :curr_shape[1], :] = ROIs #             ROIs_padded[0, curr_shape[1]:, :] = ROIs[0, 0, :] #             ROIs = ROIs_padded #         [P_cls, P_regr] = model_classifier_only.predict([F, ROIs]) #         # Calculate all classes' bboxes coordinates on resized image (300, 400) #         # Drop 'bg' classes bboxes #         for ii in range(P_cls.shape[1]): #             # If class name is 'bg', continue #             if np.argmax(P_cls[0, ii, :]) == (P_cls.shape[2] - 1): #                 continue #             # Get class name #             cls_name = class_mapping[np.argmax(P_cls[0, ii, :])] #             if cls_name not in bboxes: #                 bboxes[cls_name] = [] #                 probs[cls_name] = [] #             (x, y, w, h) = ROIs[0, ii, :] #             cls_num = np.argmax(P_cls[0, ii, :]) #             try: #                 (tx, ty, tw, th) = P_regr[0, ii, 4 * cls_num:4 * (cls_num + 1)] #                 tx /= C.classifier_regr_std[0] #                 ty /= C.classifier_regr_std[1] #                 tw /= C.classifier_regr_std[2] #                 th /= C.classifier_regr_std[3] #                 x, y, w, h = roi_helpers.apply_regr(x, y, w, h, tx, ty, tw, th) #             except: #                 pass #             bboxes[cls_name].append( #                 [16 * x, 16 * y, 16 * (x + w), 16 * (y + h)]) #             probs[cls_name].append(np.max(P_cls[0, ii, :])) #     all_dets = [] #     for key in bboxes: #         bbox = np.array(bboxes[key]) #         # Apply non-max-suppression on final bboxes to get the output bounding boxe #         new_boxes, new_probs = non_max_suppression_fast( #             bbox, np.array(probs[key]), overlap_thresh=0.5) #         for jk in range(new_boxes.shape[0]): #             (x1, y1, x2, y2) = new_boxes[jk, :] #             det = {'x1': x1, 'x2': x2, 'y1': y1, 'y2': y2, #                   'class': key, 'prob': new_probs[jk]} #             all_dets.append(det) #     print('Elapsed time = {}'.format(time.time() - st)) #     t, p = get_map(all_dets, img_data['bboxes'], (fx, fy)) #     for key in t.keys(): #         if key not in T: #             T[key] = [] #             P[key] = [] #         T[key].extend(t[key]) #         P[key].extend(p[key]) #     all_aps = [] #     for key in T.keys(): #         ap = average_precision_score(T[key], P[key]) #         print('{} AP: {}'.format(key, ap)) #         all_aps.append(ap) #     print('mAP = {}'.format(np.mean(np.array(all_aps)))) #     mAPs.append(np.mean(np.array(all_aps))) #     print(T) #     print(P) # print() # print('mean average precision:', np.nanmean(np.array(mAPs)))