import os
import sys
import random
import warnings

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt

from itertools import chain
from skimage.io import imread, imshow, imread_collection, concatenate_images
from skimage.transform import resize
from skimage.morphology import label
import tensorflow as tf
from keras import backend as K

# Set some parameters
IMG_WIDTH = 256
IMG_HEIGHT = 256
TEST_PATH = 'stage1_test/'

warnings.filterwarnings('ignore', category=UserWarning, module='skimage')
seed = 42
random.seed = seed
np.random.seed = seed

# Get train and test IDs
test_ids = next(os.walk(TEST_PATH))[1]

# Get and resize train images and masks
Y_test = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
Y_predict = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
print('Getting and resizing train images and masks ... ')
sys.stdout.flush()
for n, id_ in enumerate(test_ids):
    if id_ == '<KEY>':
        n_target = n
        print n_target

    path = TEST_PATH + id_
    mask = np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
    for mask_file in next(os.walk(path + '/masks/'))[2]:
        mask_ = imread(path + '/masks/' + mask_file)
        mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
                                      preserve_range=True), axis=-1)
        mask = np.maximum(mask, mask_)
    Y_test[n] = mask

    pred = np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
    # for mask_file in next(os.walk(path + '/Unet_masks/'))[2]:
    #     mask_ = imread(path + '/Unet_masks/' + mask_file)
    #     mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
    #                                   preserve_range=True), axis=-1)
    #     pred = np.maximum(pred, mask_)
    for mask_file in next(os.walk(path + '/AGAIN_CNN_cluster/'))[2]:
        mask_ = imread(path + '/AGAIN_CNN_cluster/' + mask_file)
        mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
                                      preserve_range=True), axis=-1)
        pred = np.maximum(pred, mask_)
    Y_predict[n] = pred

print('Done!')

# Check if training data looks all right
# ix = random.randint(0, len(test_ids))
# imshow(np.squeeze(Y_test[n_target]))
# plt.show()
# imshow(np.squeeze(Y_predict[n_target]))
# plt.show()

def iou_metric(y_true_in, y_pred_in, print_table=False):
    labels = label(y_true_in > 0.5)
    y_pred = label(y_pred_in > 0.5)
    
    true_objects = len(np.unique(labels))
    pred_objects = len(np.unique(y_pred))

    intersection = np.histogram2d(labels.flatten(), y_pred.flatten(), bins=(true_objects, pred_objects))[0]

    # Compute areas (needed for finding the union between all objects)
    area_true = np.histogram(labels, bins = true_objects)[0]
    area_pred = np.histogram(y_pred, bins = pred_objects)[0]
    area_true = np.expand_dims(area_true, -1)
    area_pred = np.expand_dims(area_pred, 0)

    # Compute union
    union = area_true + area_pred - intersection

    # Exclude background from the analysis
    intersection = intersection[1:,1:]
    union = union[1:,1:]
    union[union == 0] = 1e-9

    # Compute the intersection over union
    iou = intersection / union

    # Precision helper function
    def precision_at(threshold, iou):
        matches = iou > threshold
        true_positives = np.sum(matches, axis=1) == 1   # Correct objects
        false_positives = np.sum(matches, axis=0) == 0  # Missed objects
        false_negatives = np.sum(matches, axis=1) == 0  # Extra objects
        tp, fp, fn = np.sum(true_positives), np.sum(false_positives), np.sum(false_negatives)
        return tp, fp, fn

    # Loop over IoU thresholds
    prec = []
    if print_table:
        print("Thresh\tTP\tFP\tFN\tPrec.")
    for t in np.arange(0.5, 1.0, 0.05):
        tp, fp, fn = precision_at(t, iou)
        if (tp + fp + fn) > 0:
            p = float(tp)/float(tp+fp+fn)
        else:
            p = 0
        if print_table:
            print("{:1.3f}\t{}\t{}\t{}\t{:1.3f}".format(t, tp, fp, fn, p))
        prec.append(p)
    
    if print_table:
        print("AP\t-\t-\t-\t{:1.3f}".format(np.mean(prec)))
    return np.mean(prec)

def iou_metric_batch(y_true_in, y_pred_in):
    batch_size = y_true_in.shape[0]
    metric = []
    for batch in range(batch_size):
        value = iou_metric(y_true_in[batch], y_pred_in[batch])
        metric.append(value)
    return np.array(np.mean(metric), dtype=np.float32)

def my_iou_metric(label, pred):
    metric_value = tf.py_func(iou_metric_batch, [label, pred], tf.float32)
    return metric_value

# print iou_metric(np.squeeze(Y_test[1]), np.squeeze(Y_predict[1]), print_table=True)

final_iou = 0
for i in range(len(Y_test)):
    print test_ids[i]
    final_iou += iou_metric(np.squeeze(Y_test[i]), np.squeeze(Y_predict[i]), print_table=True)/len(Y_test)

print 'final_iou', final_iou


import os
import sys
import random
import warnings

import numpy as np
import pandas as pd

import matplotlib.pyplot as plt

from itertools import chain
from skimage.io import imread, imshow, imread_collection, concatenate_images
from skimage.transform import resize
from skimage.morphology import label
import tensorflow as tf
from keras import backend as K

# Set some parameters
IMG_WIDTH = 256
IMG_HEIGHT = 256
TEST_PATH = 'stage1_test/'

warnings.filterwarnings('ignore', category=UserWarning, module='skimage')
seed = 42
random.seed = seed
np.random.seed = seed

# Get train and test IDs
test_ids = next(os.walk(TEST_PATH))[1]

# Get and resize train images and masks
Y_test = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
Y_predict = np.zeros((len(test_ids), IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
print('Getting and resizing train images and masks ... ')
sys.stdout.flush()
for n, id_ in enumerate(test_ids):
    if id_ == '<KEY>':
        n_target = n
        print n_target

    path = TEST_PATH + id_
    mask = np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
    for mask_file in next(os.walk(path + '/masks/'))[2]:
        mask_ = imread(path + '/masks/' + mask_file)
        mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
                                      preserve_range=True), axis=-1)
        mask = np.maximum(mask, mask_)
    Y_test[n] = mask

    pred = np.zeros((IMG_HEIGHT, IMG_WIDTH, 1), dtype=np.bool)
    # for mask_file in next(os.walk(path + '/Unet_masks/'))[2]:
    #     mask_ = imread(path + '/Unet_masks/' + mask_file)
    #     mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
    #                                   preserve_range=True), axis=-1)
    #     pred = np.maximum(pred, mask_)
    for mask_file in next(os.walk(path + '/AGAIN_CNN_cluster/'))[2]:
        mask_ = imread(path + '/AGAIN_CNN_cluster/' + mask_file)
        mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', 
                                      preserve_range=True), axis=-1)
        pred = np.maximum(pred, mask_)
    Y_predict[n] = pred

print('Done!')

# Check if training data looks all right
# ix = random.randint(0, len(test_ids))
# imshow(np.squeeze(Y_test[n_target]))
# plt.show()
# imshow(np.squeeze(Y_predict[n_target]))
# plt.show()

def iou_metric(y_true_in, y_pred_in, print_table=False):
    labels = label(y_true_in > 0.5)
    y_pred = label(y_pred_in > 0.5)
    
    true_objects = len(np.unique(labels))
    pred_objects = len(np.unique(y_pred))

    intersection = np.histogram2d(labels.flatten(), y_pred.flatten(), bins=(true_objects, pred_objects))[0]

    # Compute areas (needed for finding the union between all objects)
    area_true = np.histogram(labels, bins = true_objects)[0]
    area_pred = np.histogram(y_pred, bins = pred_objects)[0]
    area_true = np.expand_dims(area_true, -1)
    area_pred = np.expand_dims(area_pred, 0)

    # Compute union
    union = area_true + area_pred - intersection

    # Exclude background from the analysis
    intersection = intersection[1:,1:]
    union = union[1:,1:]
    union[union == 0] = 1e-9

    # Compute the intersection over union
    iou = intersection / union

    # Precision helper function
    def precision_at(threshold, iou):
        matches = iou > threshold
        true_positives = np.sum(matches, axis=1) == 1   # Correct objects
        false_positives = np.sum(matches, axis=0) == 0  # Missed objects
        false_negatives = np.sum(matches, axis=1) == 0  # Extra objects
        tp, fp, fn = np.sum(true_positives), np.sum(false_positives), np.sum(false_negatives)
        return tp, fp, fn

    # Loop over IoU thresholds
    prec = []
    if print_table:
        print("Thresh\tTP\tFP\tFN\tPrec.")
    for t in np.arange(0.5, 1.0, 0.05):
        tp, fp, fn = precision_at(t, iou)
        if (tp + fp + fn) > 0:
            p = float(tp)/float(tp+fp+fn)
        else:
            p = 0
        if print_table:
            print("{:1.3f}\t{}\t{}\t{}\t{:1.3f}".format(t, tp, fp, fn, p))
        prec.append(p)
    
    if print_table:
        print("AP\t-\t-\t-\t{:1.3f}".format(np.mean(prec)))
    return np.mean(prec)

def iou_metric_batch(y_true_in, y_pred_in):
    batch_size = y_true_in.shape[0]
    metric = []
    for batch in range(batch_size):
        value = iou_metric(y_true_in[batch], y_pred_in[batch])
        metric.append(value)
    return np.array(np.mean(metric), dtype=np.float32)

def my_iou_metric(label, pred):
    metric_value = tf.py_func(iou_metric_batch, [label, pred], tf.float32)
    return metric_value

# print iou_metric(np.squeeze(Y_test[1]), np.squeeze(Y_predict[1]), print_table=True)

final_iou = 0
for i in range(len(Y_test)):
    print test_ids[i]
    final_iou += iou_metric(np.squeeze(Y_test[i]), np.squeeze(Y_predict[i]), print_table=True)/len(Y_test)

print 'final_iou', final_iou


# Set some parameters # Get train and test IDs # Get and resize train images and masks # for mask_file in next(os.walk(path + '/Unet_masks/'))[2]: #     mask_ = imread(path + '/Unet_masks/' + mask_file) #     mask_ = np.expand_dims(resize(mask_, (IMG_HEIGHT, IMG_WIDTH), mode='constant', #                                   preserve_range=True), axis=-1) #     pred = np.maximum(pred, mask_) # Check if training data looks all right # ix = random.randint(0, len(test_ids)) # imshow(np.squeeze(Y_test[n_target])) # plt.show() # imshow(np.squeeze(Y_predict[n_target])) # plt.show() # Compute areas (needed for finding the union between all objects) # Compute union # Exclude background from the analysis # Compute the intersection over union # Precision helper function # Correct objects # Missed objects # Extra objects # Loop over IoU thresholds # print iou_metric(np.squeeze(Y_test[1]), np.squeeze(Y_predict[1]), print_table=True)