def test_Nighthawks():
    import time
    import numpy as np
    from PIL import Image
    import matplotlib
    from matplotlib import pyplot as plt
    from csrk import HybridGP

    # Load image pixel data
    tic = time.perf_counter()
    raw = Image.open("originals/Nighthawks_1600_870.jpg")
    pixels = raw.load()
    width, height = raw.size
    toc = time.perf_counter()
    print(f"Pillow initialization time: {toc-tic:.6f} s")

    tic = time.perf_counter()
    # Define what we want to do wth the GP
    train_width = 480
    train_height = int(train_width * (height / width))
    train_height = min(train_height, height)
    train_width = min(train_width, width)
    sample_width = 1920
    sample_height = int(sample_width * (height / width))
    scale = np.full(2,2.0)
    whitenoise = 0.
    order = 1

    # Define training x data
    training_x_loc = np.arange(train_width)
    training_y_loc = np.arange(train_height)
    training_x_loc, training_y_loc = np.meshgrid(training_x_loc, training_y_loc)
    training_x_loc = training_x_loc.flatten()
    training_y_loc = training_y_loc.flatten()
    X = np.column_stack([training_x_loc, training_y_loc])
    # Define Y_err
    Y_err = np.zeros(X.shape[0])

    # Define sample data
    eval_x_loc = np.arange(sample_width) * (train_width / sample_width)
    eval_y_loc = np.arange(sample_height) * (train_height / sample_height)
    eval_x_loc, eval_y_loc = np.meshgrid(eval_x_loc, eval_y_loc)
    eval_x_loc = eval_x_loc.flatten()
    eval_y_loc = eval_y_loc.flatten()
    X_eval = np.column_stack((eval_x_loc, eval_y_loc)).astype(float)
    
    # Define block width / height
    block_width = int(np.floor(width / train_width))
    block_height = int(np.floor(height / train_height))
    block_size = block_height * block_height

    # Define block "stamp"
    block_x = np.arange(block_width).astype(int)
    block_y = np.arange(block_height).astype(int)
    block_x, block_y = np.meshgrid(block_x, block_y)
    block_x = block_x.flatten()
    block_y = block_y.flatten()

    # Define Y data
    Y_red       = []
    Y_green     = []
    Y_blue      = []
    Y_gray      = []
    for (i, j) in X:
        x_start = i * block_width
        y_start = j * block_height
        x = block_x + x_start
        y = block_y + y_start
        reds, blues, greens = 0, 0, 0
        for (xi, yi) in zip(x,y):
            r, g, b = pixels[xi, yi]
            reds += r
            greens += g
            blues += b
        Y_red.append(   reds    / block_size)
        Y_blue.append(  blues   / block_size)
        Y_green.append( greens  / block_size)
        Y_gray.append((reds + blues + greens) / (3 * block_size))

    Y_red = np.asarray(Y_red)
    Y_green = np.asarray(Y_green)
    Y_blue = np.asarray(Y_blue)
    Y_gray = np.asarray(Y_gray)
    # Change X to float
    X = X.astype(float)

    toc = time.perf_counter()
    print(f"Setting up training data time: {toc-tic:.6f} s!")
    # Grayscale
    print(f"Training grayscale GP on {train_width} by {train_height} grid!")
    tic = time.perf_counter()
    gp = HybridGP(
        X,
        Y_gray,
        Y_err,
        scale,
        whitenoise,
        order,
    )
    toc = time.perf_counter()
    print(f"time: {toc-tic:.6f} s")
    # Eval gray
    print(f"Evaluating grayscale GP on {sample_width} by {sample_height} grid!")
    tic = time.perf_counter()
    y_eval = gp.predict_mean(X_eval)
    toc = time.perf_counter()
    print(f"time: {toc-tic:.6f} s")
    y_img = y_eval.reshape((sample_height, sample_width))
    plt.imshow(y_img, cmap='gray')
    plt.savefig("test_Nighthawks_gray.png")
    plt.close()

if __name__ == "__main__":
    test_Nighthawks()
