#
# 吴恩达老师深度学习第一课例子
#

import numpy as np
import matplotlib.pyplot as plt
import h5py
import scipy
from PIL import Image
from scipy import ndimage
import os
import imageio
from skimage.transform import resize
import skimage

dir_name = os.path.dirname(__file__)
if dir_name == "":
    dir_name= "."
#吴恩达老师的猫,通过网上下载
#有209张图片作为训练集，50张图片作为测试集，图片中有的是猫的图片，有的不是。
#每张图片的像素大小为64*64
# y 里存储的是0,1 。其中0表示不是猫，1表示是猫
def load_data():
    with h5py.File(dir_name+'/train_catvnoncat.h5', "r") as train_dataset:
        train_set_x_orig = np.array(train_dataset["train_set_x"][:])
        train_set_y_orig = np.array(train_dataset["train_set_y"][:])

    with h5py.File(dir_name+'/test_catvnoncat.h5', "r") as test_dataset:
        test_set_x_orig = np.array(test_dataset["test_set_x"][:])
        test_set_y_orig = np.array(test_dataset["test_set_y"][:])
        classes = np.array(test_dataset["list_classes"][:])

    train_set_y_orig = train_set_y_orig.reshape((1, train_set_y_orig.shape[0]))
    test_set_y_orig = test_set_y_orig.reshape((1, test_set_y_orig.shape[0]))

    return train_set_x_orig, train_set_y_orig, test_set_x_orig, test_set_y_orig, classes

# 1.  第一步加载数据
train_x_orig, train_y, test_x_orig, test_y, classes = load_data()

# Example of a picture
index = 10
plt.imshow(train_x_orig[index])
print ("y标签 = " + str(train_y[0, index]) + ". It's a " + classes[train_y[0, index]].decode("utf-8") + " picture.")

# 2. 显示数据的维度

### START CODE HERE ### (≈ 3 lines of code)
m_train = train_x_orig.shape[0]
num_px = train_x_orig.shape[1]
m_test = test_x_orig.shape[0]

### END CODE HERE ###

print ("训练样本个数 " + str(m_train))
print ("测试样本个数 " + str(m_test))
print ("图片的高和宽" + str(num_px))
print ("每个图片的大小 (" + str(num_px) + ", " + str(num_px) + ", 3)")
print ("训练数据的shape" + str(train_x_orig.shape))
print ("训练数据y标签shape: " + str(train_y.shape))
print ("测试数据的 shape: " + str(test_x_orig.shape))
print ("测试数据y标签 shape: " + str(test_y.shape))

# 3. 将数据整理 64*64*3 = 12288 ，整理后就是像素点

### START CODE HERE ### (≈ 2 lines of code)
train_x_flatten = train_x_orig.reshape(train_x_orig.shape[0], -1).T
test_x_flatten =  test_x_orig.reshape(test_x_orig.shape[0], -1).T
### END CODE HERE ###

print ("整理后的训练数据shape: " + str(train_x_flatten.shape))
print ("整理后的训练y标签 shape: " + str(train_y.shape))
print ("整理后的测试数据 shape: " + str(test_x_flatten.shape))
print ("整理后的测试y标签 shape: " + str(test_y.shape))
print ("显示部分数据: " + str(train_x_flatten[0:5,0]))

# 4. 标准化数据，把RGB 像素点数据归化
# RGB 0-255，变成 0.0-1.0
train_x = train_x_flatten/255.
test_x = test_x_flatten/255.

# 5. 定义激活函数sigmoid
# 下面的写法基本是标准定义的做法
# GRADED FUNCTION: sigmoid

def sigmoid(Z):
    """
    Implements the sigmoid activation in numpy

    Arguments:
    Z -- numpy array of any shape

    Returns:
    A -- output of sigmoid(z), same shape as Z
    cache -- returns Z as well, useful during backpropagation
    """

    A = 1 / (1 + np.exp(-Z))
    cache = Z

    return A, cache

def relu(Z):
    """
    Implement the RELU function.
    Arguments:
    Z -- Output of the linear layer, of any shape
    Returns:
    A -- Post-activation parameter, of the same shape as Z
    cache -- a python dictionary containing "A" ; stored for computing the backward pass efficiently
    """

    A = np.maximum(0, Z)

    assert (A.shape == Z.shape)

    cache = Z
    return A, cache

def relu_backward(dA, cache):
    """
    Implement the backward propagation for a single RELU unit.
    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently
    Returns:
    dZ -- Gradient of the cost with respect to Z
    """

    Z = cache
    dZ = np.array(dA, copy=True)  # just converting dz to a correct object.

    # When z <= 0, you should set dz to 0 as well.
    dZ[Z <= 0] = 0

    assert (dZ.shape == Z.shape)

    return dZ

def sigmoid_backward(dA, cache):
    """
    Implement the backward propagation for a single SIGMOID unit.
    Arguments:
    dA -- post-activation gradient, of any shape
    cache -- 'Z' where we store for computing backward propagation efficiently
    Returns:
    dZ -- Gradient of the cost with respect to Z
    """

    Z = cache

    s = 1 / (1 + np.exp(-Z))
    dZ = dA * s * (1 - s)

    assert (dZ.shape == Z.shape)

    return dZ

def initialize_parameters(n_x, n_h, n_y):
    """
    Argument:
    n_x -- size of the input layer
    n_h -- size of the hidden layer
    n_y -- size of the output layer

    Returns:
    parameters -- python dictionary containing your parameters:
                    W1 -- weight matrix of shape (n_h, n_x)
                    b1 -- bias vector of shape (n_h, 1)
                    W2 -- weight matrix of shape (n_y, n_h)
                    b2 -- bias vector of shape (n_y, 1)
    """

    np.random.seed(1)

    W1 = np.random.randn(n_h, n_x) * 0.01
    b1 = np.zeros((n_h, 1))
    W2 = np.random.randn(n_y, n_h) * 0.01
    b2 = np.zeros((n_y, 1))

    assert (W1.shape == (n_h, n_x))
    assert (b1.shape == (n_h, 1))
    assert (W2.shape == (n_y, n_h))
    assert (b2.shape == (n_y, 1))

    parameters = {"W1": W1,
                  "b1": b1,
                  "W2": W2,
                  "b2": b2}

    return parameters

def initialize_parameters_deep(layer_dims):
    """
    Arguments:
    layer_dims -- python array (list) containing the dimensions of each layer in our network

    Returns:
    parameters -- python dictionary containing your parameters "W1", "b1", ..., "WL", "bL":
                    Wl -- weight matrix of shape (layer_dims[l], layer_dims[l-1])
                    bl -- bias vector of shape (layer_dims[l], 1)
    """

    np.random.seed(1)
    parameters = {}
    L = len(layer_dims)  # number of layers in the network

    for l in range(1, L):
        parameters['W' + str(l)] = np.random.randn(layer_dims[l], layer_dims[l - 1]) / np.sqrt(
            layer_dims[l - 1])  # *0.01
        parameters['b' + str(l)] = np.zeros((layer_dims[l], 1))

        assert (parameters['W' + str(l)].shape == (layer_dims[l], layer_dims[l - 1]))
        assert (parameters['b' + str(l)].shape == (layer_dims[l], 1))

    return parameters

def linear_forward(A, W, b):
    """
    Implement the linear part of a layer's forward propagation.
    Arguments:
    A -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)
    Returns:
    Z -- the input of the activation function, also called pre-activation parameter
    cache -- a python dictionary containing "A", "W" and "b" ; stored for computing the backward pass efficiently
    """

    Z = W.dot(A) + b

    assert (Z.shape == (W.shape[0], A.shape[1]))
    cache = (A, W, b)

    return Z, cache

def linear_activation_forward(A_prev, W, b, activation):
    """
    Implement the forward propagation for the LINEAR->ACTIVATION layer
    Arguments:
    A_prev -- activations from previous layer (or input data): (size of previous layer, number of examples)
    W -- weights matrix: numpy array of shape (size of current layer, size of previous layer)
    b -- bias vector, numpy array of shape (size of the current layer, 1)
    activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"
    Returns:
    A -- the output of the activation function, also called the post-activation value
    cache -- a python dictionary containing "linear_cache" and "activation_cache";
             stored for computing the backward pass efficiently
    """

    if activation == "sigmoid":
        # Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = sigmoid(Z)

    elif activation == "relu":
        # Inputs: "A_prev, W, b". Outputs: "A, activation_cache".
        Z, linear_cache = linear_forward(A_prev, W, b)
        A, activation_cache = relu(Z)

    assert (A.shape == (W.shape[0], A_prev.shape[1]))
    cache = (linear_cache, activation_cache)

    return A, cache

def L_model_forward(X, parameters):
    """
    Implement forward propagation for the [LINEAR->RELU]*(L-1)->LINEAR->SIGMOID computation

    Arguments:
    X -- data, numpy array of shape (input size, number of examples)
    parameters -- output of initialize_parameters_deep()

    Returns:
    AL -- last post-activation value
    caches -- list of caches containing:
                every cache of linear_relu_forward() (there are L-1 of them, indexed from 0 to L-2)
                the cache of linear_sigmoid_forward() (there is one, indexed L-1)
    """

    caches = []
    A = X
    L = len(parameters) // 2  # number of layers in the neural network

    # Implement [LINEAR -> RELU]*(L-1). Add "cache" to the "caches" list.
    for l in range(1, L):
        A_prev = A
        A, cache = linear_activation_forward(A_prev, parameters['W' + str(l)], parameters['b' + str(l)],
                                             activation="relu")
        caches.append(cache)

    # Implement LINEAR -> SIGMOID. Add "cache" to the "caches" list.
    AL, cache = linear_activation_forward(A, parameters['W' + str(L)], parameters['b' + str(L)], activation="sigmoid")
    caches.append(cache)

    assert (AL.shape == (1, X.shape[1]))

    return AL, caches

def compute_cost(AL, Y):
    """
    Implement the cost function defined by equation (7).
    Arguments:
    AL -- probability vector corresponding to your label predictions, shape (1, number of examples)
    Y -- true "label" vector (for example: containing 0 if non-cat, 1 if cat), shape (1, number of examples)
    Returns:
    cost -- cross-entropy cost
    """

    m = Y.shape[1]

    # Compute loss from aL and y.
    cost = (1. / m) * (-np.dot(Y, np.log(AL).T) - np.dot(1 - Y, np.log(1 - AL).T))

    cost = np.squeeze(cost)  # To make sure your cost's shape is what we expect (e.g. this turns [[17]] into 17).
    assert (cost.shape == ())

    return cost

def linear_backward(dZ, cache):
    """
    Implement the linear portion of backward propagation for a single layer (layer l)
    Arguments:
    dZ -- Gradient of the cost with respect to the linear output (of current layer l)
    cache -- tuple of values (A_prev, W, b) coming from the forward propagation in the current layer
    Returns:
    dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    dW -- Gradient of the cost with respect to W (current layer l), same shape as W
    db -- Gradient of the cost with respect to b (current layer l), same shape as b
    """
    A_prev, W, b = cache
    m = A_prev.shape[1]

    dW = 1. / m * np.dot(dZ, A_prev.T)
    db = 1. / m * np.sum(dZ, axis=1, keepdims=True)
    dA_prev = np.dot(W.T, dZ)

    assert (dA_prev.shape == A_prev.shape)
    assert (dW.shape == W.shape)
    assert (db.shape == b.shape)

    return dA_prev, dW, db

def linear_activation_backward(dA, cache, activation):
    """
    Implement the backward propagation for the LINEAR->ACTIVATION layer.

    Arguments:
    dA -- post-activation gradient for current layer l
    cache -- tuple of values (linear_cache, activation_cache) we store for computing backward propagation efficiently
    activation -- the activation to be used in this layer, stored as a text string: "sigmoid" or "relu"

    Returns:
    dA_prev -- Gradient of the cost with respect to the activation (of the previous layer l-1), same shape as A_prev
    dW -- Gradient of the cost with respect to W (current layer l), same shape as W
    db -- Gradient of the cost with respect to b (current layer l), same shape as b
    """
    linear_cache, activation_cache = cache

    if activation == "relu":
        dZ = relu_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)

    elif activation == "sigmoid":
        dZ = sigmoid_backward(dA, activation_cache)
        dA_prev, dW, db = linear_backward(dZ, linear_cache)

    return dA_prev, dW, db

def L_model_backward(AL, Y, caches):
    """
    Implement the backward propagation for the [LINEAR->RELU] * (L-1) -> LINEAR -> SIGMOID group

    Arguments:
    AL -- probability vector, output of the forward propagation (L_model_forward())
    Y -- true "label" vector (containing 0 if non-cat, 1 if cat)
    caches -- list of caches containing:
                every cache of linear_activation_forward() with "relu" (there are (L-1) or them, indexes from 0 to L-2)
                the cache of linear_activation_forward() with "sigmoid" (there is one, index L-1)

    Returns:
    grads -- A dictionary with the gradients
             grads["dA" + str(l)] = ...
             grads["dW" + str(l)] = ...
             grads["db" + str(l)] = ...
    """
    grads = {}
    L = len(caches)  # the number of layers
    m = AL.shape[1]
    Y = Y.reshape(AL.shape)  # after this line, Y is the same shape as AL

    # Initializing the backpropagation
    dAL = - (np.divide(Y, AL) - np.divide(1 - Y, 1 - AL))

    # Lth layer (SIGMOID -> LINEAR) gradients. Inputs: "AL, Y, caches". Outputs: "grads["dAL"], grads["dWL"], grads["dbL"]
    current_cache = caches[L - 1]
    grads["dA" + str(L)], grads["dW" + str(L)], grads["db" + str(L)] = linear_activation_backward(dAL, current_cache,
                                                                                activation="sigmoid")

    for l in reversed(range(L - 1)):
        # lth layer: (RELU -> LINEAR) gradients.
        current_cache = caches[l]
        dA_prev_temp, dW_temp, db_temp = linear_activation_backward(grads["dA" + str(l + 2)], current_cache,
                                                                    activation="relu")
        grads["dA" + str(l + 1)] = dA_prev_temp
        grads["dW" + str(l + 1)] = dW_temp
        grads["db" + str(l + 1)] = db_temp

    return grads

def update_parameters(parameters, grads, learning_rate):
    """
    Update parameters using gradient descent

    Arguments:
    parameters -- python dictionary containing your parameters
    grads -- python dictionary containing your gradients, output of L_model_backward

    Returns:
    parameters -- python dictionary containing your updated parameters
                  parameters["W" + str(l)] = ...
                  parameters["b" + str(l)] = ...
    """

    L = len(parameters) // 2  # number of layers in the neural network

    # Update rule for each parameter. Use a for loop.
    for l in range(L):
        parameters["W" + str(l + 1)] = parameters["W" + str(l + 1)] - learning_rate * grads["dW" + str(l + 1)]
        parameters["b" + str(l + 1)] = parameters["b" + str(l + 1)] - learning_rate * grads["db" + str(l + 1)]

    return parameters

def predict(X, y, parameters):
    """
    This function is used to predict the results of a  L-layer neural network.

    Arguments:
    X -- data set of examples you would like to label
    parameters -- parameters of the trained model

    Returns:
    p -- predictions for the given dataset X
    """

    m = X.shape[1]
    n = len(parameters) // 2  # number of layers in the neural network
    p = np.zeros((1, m))

    # Forward propagation
    probas, caches = L_model_forward(X, parameters)

    # convert probas to 0/1 predictions
    for i in range(0, probas.shape[1]):
        if probas[0, i] > 0.5:
            p[0, i] = 1
        else:
            p[0, i] = 0

    # print results
    # print ("predictions: " + str(p))
    # print ("true labels: " + str(y))
    if y is not None:
        print("Accuracy: " + str(np.sum((p == y) / m)))

    return p

def print_mislabeled_images(classes, X, y, p):
    """
    Plots images where predictions and truth were different.
    X -- dataset
    y -- true labels
    p -- predictions
    """
    a = p + y
    mislabeled_indices = np.asarray(np.where(a == 1))
    plt.rcParams['figure.figsize'] = (40.0, 40.0)  # set default size of plots
    num_images = len(mislabeled_indices[0])
    for i in range(num_images):
        index = mislabeled_indices[1][i]

        plt.subplot(2, num_images, i + 1)
        plt.imshow(X[:, index].reshape(64, 64, 3), interpolation='nearest')
        plt.axis('off')
        plt.title(
            "Prediction: " + classes[int(p[0, index])].decode("utf-8") + " \n Class: " + classes[y[0, index]].decode(
                "utf-8"))

### CONSTANTS DEFINING THE MODEL ####
n_x = 12288     # num_px * num_px * 3
n_h = 7
n_y = 1
layers_dims = (n_x, n_h, n_y)

# GRADED FUNCTION: two_layer_model

def two_layer_model(X, Y, layers_dims, learning_rate=0.0075, num_iterations=3000, print_cost=False):
    """
    Implements a two-layer neural network: LINEAR->RELU->LINEAR->SIGMOID.

    Arguments:
    X -- input data, of shape (n_x, number of examples)
    Y -- true "label" vector (containing 0 if cat, 1 if non-cat), of shape (1, number of examples)
    layers_dims -- dimensions of the layers (n_x, n_h, n_y)
    num_iterations -- number of iterations of the optimization loop
    learning_rate -- learning rate of the gradient descent update rule
    print_cost -- If set to True, this will print the cost every 100 iterations

    Returns:
    parameters -- a dictionary containing W1, W2, b1, and b2
    """

    np.random.seed(1)
    grads = {}
    costs = []                              # to keep track of the cost
    m = X.shape[1]                           # number of examples
    (n_x, n_h, n_y) = layers_dims

    # Initialize parameters dictionary, by calling one of the functions you'd previously implemented
    ### START CODE HERE ### (≈ 1 line of code)
    parameters = initialize_parameters(n_x, n_h, n_y)
    ### END CODE HERE ###

    # Get W1, b1, W2 and b2 from the dictionary parameters.
    W1 = parameters["W1"]
    b1 = parameters["b1"]
    W2 = parameters["W2"]
    b2 = parameters["b2"]

    # Loop (gradient descent)

    for i in range(0, num_iterations):

        # Forward propagation: LINEAR -> RELU -> LINEAR -> SIGMOID. Inputs: "X, W1, b1". Output: "A1, cache1, A2, cache2".
        ### START CODE HERE ### (≈ 2 lines of code)
        A1, cache1 = linear_activation_forward(X, W1, b1, 'relu')
        A2, cache2 = linear_activation_forward(A1, W2, b2, 'sigmoid')
        ### END CODE HERE ###

        # Compute cost
        ### START CODE HERE ### (≈ 1 line of code)
        cost = compute_cost(A2, Y)
        ### END CODE HERE ###

        # Initializing backward propagation
        dA2 = - (np.divide(Y, A2) - np.divide(1 - Y, 1 - A2))

        # Backward propagation. Inputs: "dA2, cache2, cache1". Outputs: "dA1, dW2, db2; also dA0 (not used), dW1, db1".
        ### START CODE HERE ### (≈ 2 lines of code)
        dA1, dW2, db2 = linear_activation_backward(dA2, cache2, 'sigmoid')
        dA0, dW1, db1 = linear_activation_backward(dA1, cache1, 'relu')
        ### END CODE HERE ###

        # Set grads['dWl'] to dW1, grads['db1'] to db1, grads['dW2'] to dW2, grads['db2'] to db2
        grads['dW1'] = dW1
        grads['db1'] = db1
        grads['dW2'] = dW2
        grads['db2'] = db2

        # Update parameters.
        ### START CODE HERE ### (approx. 1 line of code)
        parameters = update_parameters(parameters, grads, learning_rate)
        ### END CODE HERE ###

        # Retrieve W1, b1, W2, b2 from parameters
        W1 = parameters["W1"]
        b1 = parameters["b1"]
        W2 = parameters["W2"]
        b2 = parameters["b2"]

        # Print the cost every 100 training example
        if print_cost and i % 100 == 0:
            print("Cost after iteration {}: {}".format(i, np.squeeze(cost)))
        if print_cost and i % 100 == 0:
            costs.append(cost)

    # plot the cost

    plt.plot(np.squeeze(costs))
    plt.ylabel('cost')
    plt.xlabel('iterations (per tens)')
    plt.title("Learning rate =" + str(learning_rate))
    plt.show()

    return parameters

parameters = two_layer_model(train_x, train_y, layers_dims = (n_x, n_h, n_y), num_iterations = 2500, print_cost=True)

predictions_train = predict(train_x, train_y, parameters)
predictions_test = predict(test_x, test_y, parameters)

def pred_cat(filename):
    image = np.array(Image.open(filename).convert('RGB'))
    # resize convert RGB(0-255) to 0-1
    my_image = resize(image, output_shape=(num_px,num_px),order=1)
    my_image = skimage.img_as_float(my_image).reshape(1,(num_px*num_px*3)).T
    pred = predict(my_image,None,parameters)
    return int(pred[0][0])

if __name__ == '__main__':
    import sys
    filename = sys.argv[1]
    plt.imshow(resize(np.array(Image.open(filename).convert('RGB')),output_shape=(num_px,num_px)))
    pred = pred_cat(filename)
    print(pred)
    plt.show()


# Importing Libraries
import numpy as np
import cv2

# img = cv2.imread('smarties.png')
img = cv2.imread('shapes1.jpg')

output = img.copy()
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# We blur the image as Hough Circle Transform works better with blurred images
gray = cv2.medianBlur(gray, 5)

circles = cv2.HoughCircles(gray, cv2.HOUGH_GRADIENT, 1, 20, param1=50, param2=30, minRadius=0, maxRadius=0)

if circles is not None:
    detected_circles = np.uint16(np.around(circles))

    for x, y, r in detected_circles[0, :]:
        cv2.circle(output, (x, y), r, (0, 255, 0), 3)
        cv2.circle(output, (x, y), 2, (0, 255, 255), 3)

cv2.imshow('output', output)
cv2.waitKey(0)
cv2.destroyAllWindows()


import folium # library for maps
import time
import csv

arr = []
rows = []

#instead of csv we had to use sql databases
with open('file.csv', 'r') as file:
    reader = csv.reader(file)
    for row in reader:
        arr.append(row)

larr = len(arr) + 1

while True:

    #send request to database
    #arr=database

    if len(arr) == larr:
        # if nothing has chached, map is not generated again
        larr=len(arr)
        time.sleep(60)
        continue

    #Map generate
    m = folium.Map(location=[51.107883, 17.038538], zoom_start=10) #wroclaw location

    for i in range(1, len(arr)):
        if arr[i][1] == "Sport":
            folium.Marker(
                [arr[i][2], arr[i][3]],
                popup= arr[i][0],
                icon=folium.Icon(color="blue", icon="heart")).add_to(m)
        elif arr[i][1] == "Restaurant":
            folium.Marker(
                [arr[i][2], arr[i][3]],
                popup= arr[i][0],
                icon=folium.Icon(color="red", icon="cutlery")).add_to(m)
        elif arr[i][1] == "Museum":
            folium.Marker(
                [arr[i][2], arr[i][3]],
                popup= arr[i][0],
                icon=folium.Icon(color="green", icon="book")).add_to(m)

    m.save("EF_map.html")
    larr = len(arr)
    time.sleep(5)


from termcolor import cprint

class Road:

    def __init__(self, start, end, distance):
        self.start = start
        self.end = end
        self.distance = distance

class Warehouse:

    def __init__(self, name, content):
        self.name = name
        self.content = content
        self.road_out = None
        self.queue_in = []
        self.queue_out = []

    def __str__(self):
        return 'In {} warehouse {} KG goods.'.format(self.name, self.content)

    def set_road_out(self, road):
        self.road_out = road

    def truck_arrived(self, truck):
        self.queue_in.append(truck)
        truck.place = self
        print('{} arrived to warehouse {}.'.format(truck, self.name))

    def get_next_truck(self):
        if self.queue_in:
            truck = self.queue_in.pop()
            return truck

    def truck_ready(self, truck):
        self.queue_out.append(truck)
        print('{} is ready warehouse - {}.'.format(truck, self.name))

    def act(self):
        while self.queue_out:
            truck = self.queue_out.pop()
            truck.go_to(road=self.road_out)

class Vehicle:
    fuel_rate = 0
    total_fuel = 0

    def __init__(self, model):
        self.model = model
        self.fuel = 0

    def __str__(self):
        return '{} has {} fuel'.format(self.model, self.fuel)

    def tank_up(self):
        self.fuel += 1000
        Vehicle.total_fuel += self.fuel
        print('{} is refueled'.format(self.model))

class Truck(Vehicle):
    dead_time = 0

    def __init__(self, model, body_space):
        super().__init__(model=model)
        self.body_space = body_space
        self.cargo = 0
        self.velocity = 80
        self.place = None
        self.dictance_to_target = 0

    def __str__(self):
        res = super().__str__()
        return res + ' {} cargo'.format(self.cargo)

    def ride(self):
        if self.dictance_to_target >= self.velocity:
            self.dictance_to_target -= self.velocity
            self.fuel -= 50
        else:
            self.fuel -= self.dictance_to_target * 0.625  # gasoline uses for the remaining distance to target
            self.dictance_to_target -= self.dictance_to_target
            self.place = self.place.end
            self.place.truck_arrived(self)
            print('{} is arrived'.format(self.model))
        self.fuel -= 50
        print('{} is going on the road, {} km left'.format(self.model, self.dictance_to_target))

    def go_to(self, road):
        self.place = road
        self.dictance_to_target = road.distance
        print('{} started driving along the road'.format(self.model))

    def act(self):
        if self.fuel <= 100:
            self.tank_up()
        elif isinstance(self.place, Road):
            self.ride()
        else:
            Truck.dead_time += 1

class AutoLoader(Vehicle):
    dead_time = 0

    def __init__(self, model, bucket_capacity, warehouse=None, type_of_al='loader'):
        super().__init__(model=model)
        self.bucket_capacity = bucket_capacity
        self.warehouse = warehouse
        self.type_of_al = type_of_al
        self.truck = None

    def __str__(self):
        res = super().__str__()
        if self.truck is None:
            return res + ' waiting for truck...'
        else:
            return res + ' shipping {} goods'.format(self.truck)

    def load(self):
        if self.warehouse.content <= 0:
            print('Nothing in warehouse {}'.format(self.warehouse))
            if self.truck:
                self.warehouse.truck_ready(self.truck)
                self.truck = None
                return
        truck_cargo_rest = self.truck.body_space - self.truck.cargo
        if truck_cargo_rest >= self.bucket_capacity:
            self.warehouse.content -= self.bucket_capacity
            self.truck.cargo += self.bucket_capacity
        else:
            self.warehouse.content -= truck_cargo_rest
            self.truck.cargo += truck_cargo_rest
        print('{} is loading {}...'.format(self.model, self.truck))
        if self.truck.cargo == self.truck.body_space:
            self.warehouse.truck_ready(self.truck)
            self.truck = None

    def unload(self):
        if self.truck.cargo >= self.bucket_capacity:
            self.warehouse.content += self.bucket_capacity
            self.truck.cargo -= self.bucket_capacity
        else:
            self.warehouse.content += self.truck.cargo
            self.truck.cargo -= self.truck.cargo
        print('{} is unloading {}...'.format(self.model, self.truck))
        if self.truck.cargo == 0:
            self.warehouse.truck_ready(self.truck)
            self.truck = None

    def act(self):
        if self.fuel <= 50:
            self.fuel += 500
            self.total_fuel += self.fuel
            print('{} is refueled'.format(self.model))
        elif self.truck is None:
            self.truck = self.warehouse.get_next_truck()
            if self.truck is None:
                AutoLoader.dead_time += 1
        elif self.type_of_al == 'loader':
            self.load()
        else:
            self.unload()

LOADERS_ALL = int(input('How much loaders do you have? '))
UNLOADERS_ALL = int(input('How much unloaders do you have? '))
TRUCKS_ALL = int(input('How much trucks do you have? '))
TOTAL_CARGO_KG = 500000

Odessa = Warehouse(name='Odessa', content=TOTAL_CARGO_KG)
Kyiv = Warehouse(name='Kyiv', content=0)

odessa_kyiv = Road(start=Odessa, end=Kyiv, distance=490)
kyiv_odessa = Road(start=Kyiv, end=Odessa, distance=530)

Odessa.set_road_out(odessa_kyiv)
Kyiv.set_road_out(kyiv_odessa)

loaders = []
for number in range(LOADERS_ALL):
    loader = AutoLoader(model='Jeep G-2 #{}'.format(number), bucket_capacity=2000, warehouse=Odessa, type_of_al='loader')
    loaders.append(loader)

unloaders = []
for number in range(UNLOADERS_ALL):
    unloader = AutoLoader(model='Zaporozh CG-220{}'.format(number), bucket_capacity=1000, warehouse=Kyiv,
                          type_of_al='unloader')
    unloaders.append(unloader)

trucks = []
for number in range(TRUCKS_ALL):
    truck = Truck(model='Volvo KD-100 #{}'.format(number), body_space=10000)
    Odessa.truck_arrived(truck)
    trucks.append(truck)

hour = 0

while Kyiv.content < TOTAL_CARGO_KG:
    hour += 1
    cprint('=============== {} hour ==============='.format(hour), color='yellow')
    for truck in trucks:
        truck.act()
    for loader in loaders:
        loader.act()
    for unloader in unloaders:
        unloader.act()
    Odessa.act()
    Kyiv.act()
    for truck in trucks:
        cprint(truck, color='cyan')
    for loader in loaders:
        cprint(loader, color='cyan')
    for unloader in unloaders:
        cprint(unloader, color='cyan')
    cprint(Odessa, color='cyan')
    cprint(Kyiv, color='cyan')

print(Vehicle.total_fuel, 'litres gas')
print(Truck.dead_time, 'trucks dead time')
print(AutoLoader.dead_time, 'auto-loaders dead time')
cprint('{} hours takes transportation'.format(hour), on_color='on_green')


from arena_bot import ArenaBot
from models import Player, TaskProficiency

from discord.ext.commands import Cog, Context, command

class Core(Cog):
    """Cog holds Core commands"""

    def __init__(self, bot: ArenaBot):
        self.bot = bot

    @command()
    async def join(self, ctx: Context):
        """Join if not already."""
        if not await Player.objects.filter(id=ctx.author.id).exists():
            await Player.objects.create(id=ctx.author.id)
            # Get back from database to reconstruct object correctly.
            player = await Player.objects.get(id=ctx.author.id)
            await ctx.send(embed=await player.embed)
            return
        await ctx.reply(":x: Already have an account created", delete_after=5)

    @command()
    async def profile(self, ctx: Context):
        """Display the profile of the author."""
        player: Player = await Player.objects.get(id=ctx.author.id)
        task_proficiency = await TaskProficiency.objects.get(player=player)

        embed = await player.embed

        for field in task_proficiency.embed_fields:
            embed.add_field(**field)

        await ctx.reply(embed=embed)

def setup(bot: ArenaBot) -> None:
    """Add the cog to the bot"""
    bot.add_cog(Core(bot))

def teardown(bot: ArenaBot) -> None:
    """Remove the cog cleanly"""
    bot.remove_cog('Core')


DEBUG=True
def log(s):
    if DEBUG:
        print(s)

import torch
# import visdom
import argparse

from ptsemseg.models import get_model
from scipy.ndimage.interpolation import zoom

from ptsemseg.utils import *

# try:
#     import pydensecrf.densecrf as dcrf
# except:
#     print(
#         "Failed to import pydensecrf,\
#            CRF post-processing will not work"
#     )

def imgToTensor(img, device):
    # log('img before to tensor: {}'.format(img.shape))
    img = np.stack([img], axis=0)
    img = np.stack([img], axis=0)
    img = torch.from_numpy(img).float()
    # log('img after to tensor: {}'.format(img.size()))
    img = img.to(device)

    return img

# decode predicted result
def decoder(tensor):
    # log('tensor before to pred img: {}'.format(tensor.size()))
    pred = tensor.data.cpu().numpy()
    if args.task == 'regression':
        print('pred.shape {}'.format(pred.shape))
        pred = pred[0][0]
        print('----pred.shape {}'.format(pred.shape))
    elif args.task == 'classification':
        print('pred.shape {}'.format(pred.shape))
        # pred = (pred[0][0] < pred[0][1]).astype('int')
        pred = pred[0][1]
    else:
        exit(1)

    # log('pred img after to img: {}'.format(pred.shape))
    # ret = (pred[0][0]<pred[0][1]).astype('int')
    # log('final return label map: {}'.format(ret.shape))
    return pred

def test(args):

    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

    model_file_name = os.path.split(args.model_path)[1]
    model_name = {'arch':model_file_name.split('/')[-1].split('_')[0]}
    log('model_name: {}'.format(model_name))

    # Setup image
    # print("Read Input Image from : {}".format(args.img_path))
    img = loadtiff3d(args.img_path)
    oldeShapeX = img.shape[0]
    oldeShapeY = img.shape[1]
    oldeShapeZ = img.shape[2]
    log('img before zoom has shape: {}'.format(img.shape))
    ratioX = max(img.shape[0], 160) / img.shape[0]
    ratioY = max(img.shape[1], 160) / img.shape[1]
    ratioZ = max(img.shape[2], 8) / img.shape[2]
    img = zoom(img, (ratioX, ratioY, ratioZ))
    log('img after zoom has shape: {}'.format(img.shape))
    shapeX = img.shape[0]
    shapeY = img.shape[1]
    shapeZ = img.shape[2]

    # Setup Model
    log('set up model')
    n_classes = 2
    log('model name: {}'.format(model_name))
    model = get_model(model_name, n_classes, version=args.dataset)
    state = convert_state_dict(torch.load(args.model_path)["model_state"])
    model.load_state_dict(state)
    model.eval()
    model.to(device)

    log('apply 160*160*8 network to the img')
    stack_alongX = None
    stack_alongY = None
    stack_alongZ = None
    overlapX = 0
    overlapY = 0
    overlapZ = 0
    x = 0
    y = 0
    z = 0
    while x < shapeX:
        # residual
        if x+160 > shapeX:
            overlapX = x - (shapeX - 160)
            x= shapeX - 160
            # log('overlapX: {}'.format(overlapX))
        y = 0
        while y < shapeY:
            # residual
            if y + 160 > shapeY:
                overlapY = y - (shapeY - 160)
                y = shapeY - 160
                # log('overlapY: {}'.format(overlapY))
            z = 0
            while z < shapeZ:
                # residual check
                if z+8 > shapeZ:
                    overlapZ = z - (shapeZ - 8)
                    z = shapeZ - 8
                    # log('overlapZ: {}'.format(overlapZ))
                patch = img[x:x+160, y:y+160, z:z+8]
                patch = imgToTensor(patch, device)
                # print('patch tensor size: {}'.format(patch.size()))
                pred = model(patch)
                # print('pred size: {}'.format(pred.type))
                # pred = pred[0]
                # log('pred after model: shape {}'.format(pred.size()))
                # print('pred shape: '.format(pred.size()))
                pred = decoder(pred)
                if overlapZ:
                    pred = pred[:,:,overlapZ:]
                    stack_alongZ = np.concatenate((stack_alongZ, pred), axis=2)
                    overlapZ = 0
                else:
                    if stack_alongZ is None:
                        stack_alongZ = pred
                    else:
                        stack_alongZ = np.concatenate((stack_alongZ, pred), axis=2)
                # log('===>z ({}/{}) loop: stack_alongZ shape: {}'.format(z, shapeZ, stack_alongZ.shape))

                z += 8

            if overlapY:
                stack_alongZ = stack_alongZ[:,overlapY:,:]
                stack_alongY = np.concatenate((stack_alongY, stack_alongZ), axis=1)
                overlapY = 0
            else:
                if stack_alongY is None:
                    stack_alongY = stack_alongZ
                else:
                    stack_alongY = np.concatenate((stack_alongY, stack_alongZ), axis=1)
            # log('==>y ({}/{}) loop: stack_alongY shape: {}'.format(y, shapeY, stack_alongY.shape))
            stack_alongZ = None

            y += 160

        if overlapX:
            stack_alongY = stack_alongY[overlapX:, :, :]
            stack_alongX = np.concatenate((stack_alongX, stack_alongY), axis=0)
            overlapX = 0
        else:
            if stack_alongX is None:
                stack_alongX = stack_alongY
            else:
                stack_alongX = np.concatenate((stack_alongX, stack_alongY), axis=0)
        # log('=>x ({}/{}) loop: stack_alongX shape: {}'.format(x, shapeX, stack_alongX.shape))
        stack_alongY = None

        x += 160
    log('save prediction in path: {}'.format(args.out_path))
    ratioX = oldeShapeX / stack_alongX.shape[0]
    ratioY = oldeShapeY / stack_alongX.shape[1]
    ratioZ = oldeShapeZ / stack_alongX.shape[2]
    stack_alongX = zoom(stack_alongX, (ratioX, ratioY, ratioZ))
    if stack_alongX.shape[0] != oldeShapeX or stack_alongX.shape[1] != oldeShapeY or stack_alongX.shape[2] != oldeShapeZ:
        print("Read Input Image from : {}".format(args.img_path))
        print('result shape is: {} but aimed shape is {}'.format(stack_alongX.shape,(oldeShapeX, oldeShapeY, oldeShapeZ)))
        exit(1)

    mask = (stack_alongX > 0).astype('int')
    stack_alongX = np.multiply(mask, stack_alongX)
    maxV = np.max(stack_alongX)
    minV = np.min(stack_alongX)
    stack_alongX = (stack_alongX - minV)/(maxV - minV)

    # maxV = np.max(stack_alongX)
    # minV = np.min(stack_alongX)
    # print('maximum: {} minimum: {}'.format(np.max(stack_alongX), np.min(stack_alongX)))
    # maxV = np.max(stack_alongX)
    # minV = np.min(stack_alongX)
    # threshold = (maxV + 0)/8
    # stack_alongX = (stack_alongX > threshold).astype('int')
    out_path = args.out_path
    img_name = out_path.split('/')[-1]
    pred_folder = out_path.replace(img_name, '')
    if not os.path.isdir(pred_folder):
        os.mkdir(pred_folder)
    else:
        print(pred_folder + ' already exists')
    writetiff3d(pred_folder+'/'+img_name, (stack_alongX*255))
    # writetiff3d(args.out_path, stack_alongX*255 > 60)

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Params")
    parser.add_argument(
        "--model_path",
        nargs="?",
        type=str,
        # default for mac
        # default="/Users/wonh/y3s2/isbi/segment_3D/runs/fcn3d_fly/65461/fcn3dnet_flyJanelia_best_model.pkl",
        #default for ubuntu
        default="/home/heng/Desktop/Research/isbi/runs/fcn3d_fly/65461/fcn3dnet_flyJanelia_best_model.pkl",
        help="Path to the saved model",
    )
    parser.add_argument(
        "--dataset",
        nargs="?",
        type=str,
        default="flyJanelia",
        help="Dataset to use ['flyJanelia, pascal, camvid, ade20k etc']",
    )

    parser.add_argument(
        "--task",
        nargs="?",
        type=str,
        default="regression",
        help="Task to use. Select from [regression, classification]",
    )

    # parser.add_argument(
    #     "--img_norm",
    #     dest="img_norm",
    #     action="store_true",
    #     help="Enable input image scales normalization [0, 1] \
    #                           | True by default",
    # )
    # parser.add_argument(
    #     "--no-img_norm",
    #     dest="img_norm",
    #     action="store_false",
    #     help="Disable input image scales normalization [0, 1] |\
    #                           True by default",
    # )
    # parser.set_defaults(img_norm=True)

    # parser.add_argument(
    #     "--dcrf",
    #     dest="dcrf",
    #     action="store_true",
    #     help="Enable DenseCRF based post-processing | \
    #                           False by default",
    # )
    # parser.add_argument(
    #     "--no-dcrf",
    #     dest="dcrf",
    #     action="store_false",
    #     help="Disable DenseCRF based post-processing | \
    #                           False by default",
    # )
    # parser.set_defaults(dcrf=False)

    parser.add_argument(
        "--img_path", nargs="?", type=str, default=None, help="Path of the input image"
    )
    parser.add_argument(
        "--out_path",
        nargs="?",
        type=str,
        default=None,
        help="Path of the output segmap",
    )
    args = parser.parse_args()
    test(args)


from aiohttp import web
import aiohttp
import threading
import queue
import numpy as np
import cv2
import jinja2
import aiohttp_jinja2
import os
import asyncio
import base64

cams_queue = queue.Queue(maxsize=10)
monitor_queue = []

face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml')
eyes_cascade = cv2.CascadeClassifier('haarcascade_eye_tree_eyeglasses.xml')

def cv2_processing(frame):
    try:
        frame_gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        frame_gray = cv2.equalizeHist(frame_gray)
        #-- Detect faces
        faces = face_cascade.detectMultiScale(frame_gray)
        for (x,y,w,h) in faces:
            center = (x + w//2, y + h//2)
            frame = cv2.ellipse(frame, center, (w//2, h//2), 0, 0, 360, (255, 0, 255), 4)
            faceROI = frame_gray[y:y+h,x:x+w]
            #-- In each face, detect eyes
            eyes = eyes_cascade.detectMultiScale(faceROI)
            for (x2,y2,w2,h2) in eyes:
                eye_center = (x + x2 + w2//2, y + y2 + h2//2)
                radius = int(round((w2 + h2)*0.25))
                frame = cv2.circle(frame, eye_center, radius, (255, 0, 0 ), 4)
    except:
        pass
    return frame

def handle_cams(cams_queue, monitor_queue):
    loop = asyncio.new_event_loop()
    mons = []

    while True:
        if not cams_queue.empty():
            cam = cams_queue.get()
            cam_id = cam[0]
            image_bytes = np.array(cam[1]).tobytes()
            image_bytes = np.frombuffer(image_bytes, dtype=np.uint8)
            img = cv2.imdecode(image_bytes, flags=cv2.IMREAD_COLOR)
            img = cv2_processing(img)
            retval, buffer = cv2.imencode('.jpg', img)
            jpg_as_text = base64.b64encode(buffer).decode("utf-8")
            for ws in monitor_queue:
                try:
                    loop.run_until_complete(ws.send_str(jpg_as_text))
                except:
                    print('websocket closed')
            #cv2.imshow('abc', img)
            #cv2.waitKey(0)
            #cv2.imwrite('tuan.jpg', img)

async def websocket_cam_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    data = []
    cam_id = None
    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if msg.data.startswith('start'):
                cam_id = msg.data.replace('start:', '')
                data = []
            elif msg.data == 'end':
                cams_queue.put([cam_id, data])
        elif msg.type == aiohttp.WSMsgType.BINARY:
            data.append(msg.data)
        elif msg.type == aiohttp.WSMsgType.ERROR:
            await ws.close()
            print(ws.exception())
    return ws

async def monitor_cam_handler(request):
    ws = web.WebSocketResponse()
    await ws.prepare(request)
    monitor_queue.append(ws)
    async for msg in ws:
        if msg.type == aiohttp.WSMsgType.TEXT:
            if msg.data == 'close':
                await ws.close()
        elif msg.type == aiohttp.WSMsgType.ERROR:
            await ws.close()
            print(ws.exception())
    return ws

@aiohttp_jinja2.template("index.html")
async def index(request):
    return {}

if __name__ == '__main__':
    p = threading.Thread(target=handle_cams, args=((cams_queue, monitor_queue)))
    p.start()

    app = web.Application()
    aiohttp_jinja2.setup(
        app, loader=jinja2.FileSystemLoader(os.path.join(os.getcwd(), "templates"))
    )
    app.router.add_get('/', index, name="index")
    app.router.add_get('/ws', websocket_cam_handler)
    app.router.add_get('/monitor', monitor_cam_handler)

    web.run_app(app)