text:
import cv2
import numpy as np
from mss import mss
import time
import win32api, win32con, win32gui
import pydirectinput
from PIL import Image
import pytesseract
import concurrent.futures
import account_league
import threading
from pyWinhook import HookManager
import os
import gc

## PARAMETERS & CONSTANTS

pydirectinput.FAILSAFE = False
pytesseract.pytesseract.tesseract_cmd = (
    "C:\\Program Files\\Tesseract-OCR\\tesseract.exe"
)

# Client
CLIENT_BOX = {"left": 320, "top": 180, "width": 1280, "height": 720}
CLIENT_LOGIN_BOX = {"left": 480, "top": 200, "width": 100, "height": 150}
CLIENT_PLAY_BOX = {"left": 330, "top": 160, "width": 200, "height": 80}
CLIENT_MATCHMAKING_BOX = {"left": 730, "top": 820, "width": 250, "height": 100}
CLIENT_CHAMPSELECT_BOX = {"left": 760, "top": 230, "width": 150, "height": 80}
CLIENT_GGSCREEN_BOX = {"left": 800, "top": 200, "width": 300, "height": 60}
CLIENT_GGNEXT_BOX = {"left": 920, "top": 780, "width": 100, "height": 100}

# In-game
EOG_BOX = {"left": 860, "top": 600, "width": 200, "height": 80}
FIGHT_BOX = {"left": 300, "top": 0, "width": 1620, "height": 800}
START_BOX = {"left": 1000, "top": 300, "width": 600, "height": 400}
SHOP_BOX = {"left": 350, "top": 130, "width": 730, "height": 760}
SHOP_OPEN_BOX = {"left": 350, "top": 775, "width": 90, "height": 95}
SHOP_CONSUMABLE_BOX = {"left": 375, "top": 195, "width": 45, "height": 295}
SHOP_STARTER_BOX = {"left": 505, "top": 330, "width": 275, "height": 60}
SHOP_BOOTS_BOX = {"left": 375, "top": 530, "width": 45, "height": 215}
SHOP_BASIC_BOX = {"left": 500, "top": 440, "width": 500, "height": 70}
SHOP_EPIC_BOX = {"left": 500, "top": 560, "width": 500, "height": 145}
SHOP_LEGENDARY_BOX = {"left": 500, "top": 750, "width": 555, "height": 70}
GOLD_BOX = {"left": 1200, "top": 1045, "width": 90, "height": 22}
INVENTORY_BOX = {"left": 1130, "top": 940, "width": 190, "height": 100}
MINIMAP_BOX = {"left": 1640, "top": 800, "width": 280, "height": 280}
MINIMAP_CORNER_BOX = {"left": 1630, "top": 790, "width": 60, "height": 60}
PLAYER_BOX = {"left": 660, "top": 200, "width": 600, "height": 400}

MELEE_ITEMS = [
    {
        "name": "doranblade",
        "price": 450,
        "bought": False,
        "box": SHOP_STARTER_BOX,
        "pos": (695, 350),
    },
    {
        "name": "healthpotion",
        "price": 50,
        "bought": False,
        "box": SHOP_CONSUMABLE_BOX,
        "pos": (400, 215),
    },
    {
        "name": "ward",
        "price": 0,
        "bought": False,
        "box": SHOP_CONSUMABLE_BOX,
        "pos": (400, 290),
    },
    {
        "name": "longsword",
        "price": 350,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (640, 465),
    },
    {
        "name": "rubycrystal",
        "price": 400,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (700, 465),
    },
    {
        "name": "phage",
        "price": 350,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (1030, 585),
    },
    {
        "name": "sheen",
        "price": 700,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (530, 585),
    },
    {
        "name": "rubycrystal",
        "price": 400,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (700, 465),
    },
    {
        "name": "kindledgem",
        "price": 400,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (695, 585),
    },
    {
        "name": "divine",
        "price": 700,
        "bought": False,
        "box": SHOP_BOX,
        "pos": (615, 775),
    },
    {
        "name": "boots",
        "price": 300,
        "bought": False,
        "box": SHOP_BOOTS_BOX,
        "pos": (400, 555),
    },
    {
        "name": "clotharmor",
        "price": 300,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (530, 465),
    },
    {
        "name": "platedboots",
        "price": 500,
        "bought": False,
        "box": SHOP_BOOTS_BOX,
        "pos": (400, 700),
    },
    {
        "name": "longsword",
        "price": 350,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (640, 465),
    },
    {
        "name": "rubycrystal",
        "price": 400,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (700, 465),
    },
    {
        "name": "phage",
        "price": 350,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (1030, 585),
    },
    {
        "name": "pickaxe",
        "price": 875,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (865, 465),
    },
    {
        "name": "rubycrystal",
        "price": 400,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (700, 465),
    },
    {
        "name": "sterak",
        "price": 725,
        "bought": False,
        "box": SHOP_LEGENDARY_BOX,
        "pos": (925, 775),
    },
    {
        "name": "pickaxe",
        "price": 875,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (865, 465),
    },
    {
        "name": "tiamat",
        "price": 325,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (640, 655),
    },
    {
        "name": "longsword",
        "price": 350,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (640, 465),
    },
    {
        "name": "vampscepter",
        "price": 550,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (810, 585),
    },
    {
        "name": "ravenous",
        "price": 1200,
        "bought": False,
        "box": SHOP_LEGENDARY_BOX,
        "pos": (1035, 775),
    },
    {
        "name": "hammer",
        "price": 1100,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (585, 655),
    },
    {
        "name": "deathdance",
        "price": 200,
        "bought": False,
        "box": SHOP_LEGENDARY_BOX,
        "pos": (865, 775),
    },
]

CASTER_ITEMS = [
    {
        "name": "doranring",
        "price": 400,
        "bought": False,
        "box": SHOP_STARTER_BOX,
        "pos": (695, 350),
    },
    {
        "name": "healthpotion",
        "price": 50,
        "bought": False,
        "box": SHOP_CONSUMABLE_BOX,
        "pos": (400, 215),
    },
    {
        "name": "healthpotion",
        "price": 50,
        "bought": False,
        "box": SHOP_CONSUMABLE_BOX,
        "pos": (400, 215),
    },
    {
        "name": "ward",
        "price": 0,
        "bought": False,
        "box": SHOP_CONSUMABLE_BOX,
        "pos": (400, 290),
    },
    {
        "name": "amplifyingtome",
        "price": 435,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (755, 465),
    },
    {
        "name": "amplifyingtome",
        "price": 435,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (755, 465),
    },
    {
        "name": "lostchapter",
        "price": 430,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (530, 660),
    },
    {
        "name": "blastingwand",
        "price": 850,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (925, 465),
    },
    {
        "name": "luden",
        "price": 1250,
        "bought": False,
        "box": SHOP_BOX,
        "pos": (550, 400),
    },
    {
        "name": "boots",
        "price": 300,
        "bought": False,
        "box": SHOP_BOOTS_BOX,
        "pos": (400, 550),
    },
    {
        "name": "sorcerershoes",
        "price": 800,
        "bought": False,
        "box": SHOP_BOOTS_BOX,
        "pos": (400, 630),
    },
    {
        "name": "amplifyingtome",
        "price": 435,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (755, 465),
    },
    {
        "name": "blastingwand",
        "price": 850,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (925, 465),
    },
    {
        "name": "akuma",
        "price": 1715,
        "bought": False,
        "box": SHOP_BOX,
        "pos": (550, 775),
    },
    {
        "name": "amplifyingtome",
        "price": 435,
        "bought": False,
        "box": SHOP_BASIC_BOX,
        "pos": (755, 465),
    },
    {
        "name": "armguard",
        "price": 465,
        "bought": False,
        "box": SHOP_EPIC_BOX,
        "pos": (811, 580),
    },
    {
        "name": "zhonya",
        "price": 1600,
        "bought": False,
        "box": SHOP_LEGENDARY_BOX,
        "pos": (700, 775),
    },
    {
        "name": "bansheeveil",
        "price": 2500,
        "bought": False,
        "box": SHOP_LEGENDARY_BOX,
        "pos": (755, 775),
    },
]

# Global variables

shop_list = MELEE_ITEMS
pick_rotation = ["illaoi", "jax", "ahri"]
current_screen = "unknown"
last_screen = "unknown"
game_state = "start"
sct = mss()
ratio = 1

## LOGGING

class Logger:
    def __init__(self, debug=False):
        self.create_log_folder()
        self.logfile = "logs/log-" + str(time.time()) + ".txt"
        self.debug = debug

    def create_log_folder(self):
        if not os.path.exists("logs"):
            os.makedirs("logs")

    def log_timestamp(self):
        timestamp = "[" + time.strftime("%H:%M:%S") + "]"
        return timestamp

    def plog(self, message):
        if self.debug:
            print(f"{self.log_timestamp()} {message}")
        print(f"{self.log_timestamp()} {message}", file=open(self.logfile, "a"))

## MOUSE AND KEYBOARD

# Move the mouse to coordinates
def move_mouse(x, y):
    try:
        win32api.SetCursorPos((x, y))
    except:
        logger.plog(f"Couldn't lock mouse, 10s sleep...")
        time.sleep(10)

# Left click
def left_click(x, y):
    move_mouse(x, y)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN, 0, 0)
    time.sleep(0.1)
    win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP, 0, 0)
    time.sleep(0.1)

# Right click
def right_click(x, y):
    move_mouse(x, y)
    win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTDOWN, 0, 0)
    time.sleep(0.1)
    win32api.mouse_event(win32con.MOUSEEVENTF_RIGHTUP, 0, 0)
    time.sleep(0.1)

# Write chars one by one
def keyboard_write(message):
    for letter in message:
        if letter.isupper():
            pydirectinput.keyDown("shift")
            pydirectinput.press(letter.lower())
            pydirectinput.keyUp("shift")
        else:
            pydirectinput.press(letter)

# Global hotkey class to quit the script ('k')
class Keystroke_Watcher(object):
    def __init__(self):
        self.hm = HookManager()
        self.hm.KeyDown = self.on_keyboard_event
        self.hm.HookKeyboard()

    def on_keyboard_event(self, event):
        try:
            if event.KeyID == 75:  # k
                self.stop_script()
        finally:
            return True

    def stop_script(self):
        logger.plog(f"Exiting script...")
        os.system("taskkill /IM python.exe /f")  # lol bruteforce

    def shutdown(self):
        win32gui.PostQuitMessage(0)
        self.hm.UnhookKeyboard()

# Object listening to global hotkey
def listen_k():
    watcher = Keystroke_Watcher()
    win32gui.PumpMessages()

## VISION

# Screenshots
def capture_window(bounding_box):
    sct_img = sct.grab(bounding_box)
    width = int(bounding_box["width"] / ratio)
    height = int(bounding_box["height"] / ratio)
    sct_img_resized = cv2.resize(np.array(sct_img), (width, height))
    del sct_img
    gc.collect()
    return sct_img_resized

# Lookup and return x, y coordinates
def lookup(bounding_box, template):
    sct_img = capture_window(bounding_box)
    x, y, *_ = template_match(sct_img, template)
    del sct_img
    gc.collect()
    return (x, y)

# Lookup specific to the multithread loop inside farm_lane
def lookup_thread(bounding_box, template):
    sct_img = capture_window(bounding_box)
    x, y, name, loc, width, height = template_match(sct_img, template)
    return name, loc, width, height, sct_img, bounding_box["left"], bounding_box["top"]

# Infinite loop to look for a pattern until found
def look_for(bounding_box, template, retries=0):
    while True:
        retries -= 1  # an initial value of 0 means infinite loop
        x, y = lookup(bounding_box, template)
        if x != 0 and y != 0:
            break
        if retries == 0:
            break

    return int(x + bounding_box["left"]), int(y + bounding_box["top"])

# Matching template to the screenshot taken
def template_match(img_bgr, template_img):
    img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)
    template = cv2.imread(template_img, 0)
    name = template_img.split("/")[-1].split(".")[0]
    width = int(template.shape[1] / ratio)
    height = int(template.shape[0] / ratio)
    # template = cv2.resize(template, (width,height))
    res = cv2.matchTemplate(img_gray, template, cv2.TM_CCOEFF_NORMED)
    threshold = 0.90
    if name == "minion":
        threshold = 0.99
    if "tower" in name:
        threshold = 0.85
    # if 'shop' in template_img: threshold = 0.95
    if "inventory" in template_img:
        threshold = 0.85
    if name == "start" or name == "ward" or name == "luden":
        threshold = 0.80
    loc = np.where(res > threshold)
    x = 0
    y = 0
    for pt in zip(*loc[::-1]):
        x += pt[0]
        y += pt[1]
        break
    if x != 0 and y != 0:
        x += width * ratio / 2
        y += height * ratio / 2

    del img_bgr
    del img_gray
    del template
    del res
    gc.collect()

    return int(x), int(y), name, loc, width, height

# Pixel color on a match to understand if ally (blue), enemy (red) or self (yellow)
def mark_the_spot(sct_img, pt, width, height, name):
    x = 0
    y = 0
    side = None
    if pt[0] != 0 and pt[1] != 0:
        x += int((width * ratio / 2) + pt[0])
        y += int((height * ratio / 2) + pt[1])
        color = tuple(int(x) for x in sct_img[y][x])
        if color[0] > 120 and color[2] < 120:
            side = "ally"
        elif color[2] > 120 and color[0] < 120:
            side = "enemy"
        else:
            side = "neutral"
        if name == "low":
            offset = 0
            yellow_pixels = []
            while offset < 25:
                color = tuple(int(x) for x in sct_img[y][pt[0] - offset])
                if color[0] < 100 and color[1] > 150 and color[2] > 150:
                    logger.plog(
                        f"Low life pixel color match {color} at position ({y},{pt[0]-offset}) and offset {offset}..."
                    )
                    yellow_pixels.append(color)
                offset += 1
            if len(yellow_pixels) == 0:
                x = 0
                y = 0

    del sct_img
    gc.collect()

    return x, y, side

# Watch the screen and update the current_screen global variable with the latest perceived screen
def screen_watcher():
    global current_screen
    global last_screen

    while True:
        if current_screen != "unknown":
            if current_screen != last_screen:
                logger.plog(
                    f"Current screen is: {current_screen}, last screen is {last_screen}"
                )  # )
            last_screen = current_screen
        if lookup(CLIENT_LOGIN_BOX, "patterns/client/login.png") != (0, 0):
            current_screen = "login"
        elif lookup(CLIENT_PLAY_BOX, "patterns/client/play.png") != (0, 0):
            current_screen = "play"
        elif lookup(CLIENT_MATCHMAKING_BOX, "patterns/client/matchmaking.png") != (
            0,
            0,
        ):
            current_screen = "matchmaking"
        elif lookup(CLIENT_CHAMPSELECT_BOX, "patterns/client/champselect.png") != (
            0,
            0,
        ):
            current_screen = "champselect"
        elif lookup(MINIMAP_CORNER_BOX, "patterns/minimap/corner.png") != (0, 0):
            current_screen = "ingame"
        elif lookup(EOG_BOX, "patterns/client/endofgame.png") != (0, 0):
            current_screen = "endofgame"
        elif lookup(CLIENT_GGSCREEN_BOX, "patterns/client/ggscreen.png") != (0, 0):
            current_screen = "postmatch"
        else:
            current_screen = "unknown"

## CLIENT MENU

# Login sequence
def login():
    left_click(x=400, y=420)
    counter = 1
    while True:
        if counter == 1:
            logger.plog(f"Typing login...")
            keyboard_write(account_league.login)
        elif counter == 2:
            logger.plog(f"Typing password...")
            keyboard_write(account_league.password)
        elif counter == 7:
            logger.plog(f"Logging in...")
            pydirectinput.press("enter")
            time.sleep(5)
        elif counter == 8:
            logger.plog(f"Starting game")
            pydirectinput.press("enter")
            break
        pydirectinput.press("tab")
        counter += 1

# Click sequence for menus
def screen_sequence(path, steps):
    for step in steps:
        logger.plog(f"Next click is {step}")
        left_click(*look_for(CLIENT_BOX, path + step + ".png"))
        time.sleep(0.1)
        left_click(1070, 710)  # Accept key fragment reward
        time.sleep(0.1)

# Click the menus to go to the correct matchmaking
def play(practice=False):
    if practice:
        screen_sequence(
            path="patterns/client/",
            steps=["play", "training", "practice", "confirm", "gamestart"],
        )
    else:
        screen_sequence(
            path="patterns/client/", steps=["play", "ai", "beginner", "confirm"]
        )

# Queue for matchmaking and pick a champ
def matchup():
    global shop_list
    global game_state

    while True:

        if current_screen == "matchmaking":
            left_click(
                *look_for(CLIENT_BOX, "patterns/client/matchmaking.png", retries=1)
            )

        if lookup(CLIENT_BOX, "patterns/client/accept.png") != (0, 0):
            logger.plog(f" Found accept!...")
            left_click(955, 750)

        elif lookup(CLIENT_BOX, "patterns/client/pickerror.png") != (0, 0):
            logger.plog(f" Found pickerror!...")
            left_click(960, 550)

        elif current_screen == "champselect":
            logger.plog(f"Sequence Champselect...")
            for pick in pick_rotation:
                logger.plog(f"Looking for patterns/champselect/{pick}.png...")
                x, y = look_for(
                    CLIENT_BOX, "patterns/champselect/" + pick + ".png", retries=1
                )
                if (x, y) != (0, 0):
                    left_click(x, y)
                time.sleep(0.1)
                x, y = look_for(CLIENT_BOX, "patterns/client/lock.png", retries=1)
                if (x, y) != (0, 0):
                    left_click(x, y)
                time.sleep(0.1)

        elif lookup(CLIENT_BOX, "patterns/champselect/illaoipicked.png") != (0, 0):
            logger.plog(f"Locked Illaoi...")
            shop_list = MELEE_ITEMS

        elif lookup(CLIENT_BOX, "patterns/champselect/jaxpicked.png") != (0, 0):
            logger.plog(f"Locked Jax...")
            shop_list = MELEE_ITEMS

        elif lookup(CLIENT_BOX, "patterns/champselect/ahripicked.png") != (0, 0):
            logger.plog(f"Locked Ahri...")
            shop_list = CASTER_ITEMS

        elif last_screen == "ingame":
            logger.plog(f"Game has started...")
            game_state = "start"
            break

# Postmatch and rematch
def postmatch():
    global shop_list
    global game_state

    for item in shop_list:
        item["bought"] = False

    game_state = "stop"

    time.sleep(5)

    while True:
        if lookup(CLIENT_GGNEXT_BOX, "patterns/client/ggnext.png") != (0, 0):
            logger.plog(f"GG someone...")
            left_click(590, 550)
        elif lookup(CLIENT_BOX, "patterns/client/ok.png") != (0, 0):
            logger.plog(f"Found a post end game OK button to click...")
            pydirectinput.press("space")
        elif lookup(CLIENT_BOX, "patterns/client/rematch.png") != (0, 0):
            logger.plog(f"Found the rematch button to click, exiting loop...")
            left_click(765, 855)
            break
        else:  # Lazy method to pick a champ reward
            logger.plog(f"Just clicking at 1385, 570...")
            left_click(1385, 570)
        time.sleep(1)

## GAMEPLAY

# Run on game start to level 3rd spell and to start shopping only after 15sc
def game_start():
    time.sleep(10)
    logger.plog(f"Level up E spell")
    pydirectinput.keyDown("ctrl")
    pydirectinput.press("e")
    pydirectinput.keyUp("ctrl")
    time.sleep(5)
    if last_screen == "ingame":
        buy_from_shop(shop_list)

# OCR to read the gold
def check_number(box):
    conf = r"--oem 3 --psm 6 outputbase digits"
    sct_img = capture_window(GOLD_BOX)
    sct_img = cv2.cvtColor(sct_img, cv2.COLOR_BGR2GRAY)
    sct_img = 0 - sct_img
    ksize = (3, 3)
    sct_img = cv2.blur(sct_img, ksize)
    sct_img[sct_img < 100] = 0
    sct_img[sct_img > 200] = 255
    pil_img = Image.fromarray(cv2.cvtColor(sct_img, cv2.COLOR_BGR2RGB))
    text = pytesseract.image_to_string(pil_img, config=conf)
    try:
        number = 0
        number += int(text)
    except:
        number = 0
    return number

# Loop to buy a list of items from shop
def buy_from_shop(items):
    time.sleep(2)
    pydirectinput.press("p")
    for item in items:
        if item["bought"] == True:
            continue
        elif item["bought"] == False and check_number(GOLD_BOX) >= item["price"]:
            buy_item(item)
        else:
            logger.plog(f"Not enough gold for {item['name']}")
            break
    pydirectinput.press("p")
    if last_screen == "ingame":
        go_toplane()

# Buy one item from shop
def buy_item(item):
    retries = 3
    while retries > 0:
        if lookup(SHOP_OPEN_BOX, "patterns/shop/open.png") == (0, 0):
            logger.plog(f"Opening shop..")
            pydirectinput.press("p")
        left_click(755, 155)
        logger.plog(f"Buying {item['name']}")
        if item["name"] in ["akuma", "luden", "divine"]:
            left_click(545, 155)
            time.sleep(0.5)
            x, y = look_for(
                SHOP_BOX, "patterns/shop/" + item["name"] + ".png", retries=1
            )
            if (x, y) != (SHOP_BOX["left"], SHOP_BOX["top"]):
                right_click(x, y)
            time.sleep(0.5)
        else:
            right_click(*item["pos"])
        left_click(755, 155)
        if last_screen != "ingame":
            break
        elif lookup(INVENTORY_BOX, "patterns/inventory/" + item["name"] + ".png") != (
            0,
            0,
        ):
            logger.plog(f"Bought {item['name']}")
            item["bought"] = True
            break
        elif lookup(INVENTORY_BOX, "patterns/inventory/empty.png") == (0, 0):
            logger.plog(f"Inventory full")
            break
        elif item["price"] > check_number(GOLD_BOX):
            logger.plog(f"Insufficient gold for {item['price']}")
            break
        else:
            logger.plog(f"Retrying to buy {item['name']} {retries} more time")
            retries -= 1

# Go back to lane, check if camera lock is on
def go_toplane():
    pydirectinput.keyDown("shift")
    right_click(1675, 890)
    pydirectinput.keyUp("shift")
    logger.plog(f"Going toplane...")
    logger.plog(f"Sleep 25sc while walking...")
    time.sleep(15)
    if (
        lookup(PLAYER_BOX, "patterns/unit/player.png") == (0, 0)
        and last_screen == "ingame"
    ):
        logger.plog(f"Can't see player, lock camera")
        pydirectinput.press("y")
    time.sleep(10)
    if last_screen == "ingame":
        farm_lane()

# Level up abilities at the beginning of each farm_lane cycle
def level_up_abilities():
    pydirectinput.keyUp("shift")
    pydirectinput.keyDown("ctrl")
    pydirectinput.press("r")
    time.sleep(0.1)
    pydirectinput.press("w")
    time.sleep(0.1)
    pydirectinput.press("q")
    time.sleep(0.1)
    pydirectinput.press("e")
    pydirectinput.keyUp("ctrl")
    pydirectinput.keyUp("ctrl")

# Go back to base and shop
def back_and_recall():
    pydirectinput.keyUp("shift")
    pydirectinput.press("f")
    pydirectinput.press("g")
    pydirectinput.press("s")
    right_click(1665, 1060)
    time.sleep(10)
    pydirectinput.press("b")
    time.sleep(10)
    buy_from_shop(shop_list)

# Retreat
def fall_back(x=1680, y=890, timer=0):
    pydirectinput.keyUp("shift")
    pydirectinput.press("s")
    right_click(x, y)
    time.sleep(timer)

# Attack
def attack_position(
    x, y, q=False, w=True, e=False, r=False, target_champion=False, spelltarget=(0, 0)
):
    pydirectinput.keyDown("shift")
    if target_champion:
        pydirectinput.keyDown("c")
    right_click(x, y)
    if target_champion:
        pydirectinput.keyUp("c")
    pydirectinput.keyUp("shift")
    if spelltarget == (0, 0):
        spelltarget = (x, y)
    left_click(spelltarget[0], spelltarget[1])
    if e:
        pydirectinput.press("e")
    if r:
        pydirectinput.press("r")
    if w:
        pydirectinput.press("w")
    if q:
        pydirectinput.press("q")

# Needed to calculate the average position of a group of units
def average_tuple_list(tuple_list):
    length = len(tuple_list)
    first = sum(v[0] for v in tuple_list)
    second = sum(v[1] for v in tuple_list)
    average_tuple = (int(first / length), int(second / length))
    logger.plog(f"average_tuple: {average_tuple}")
    return average_tuple

# What to do when game ends
def end_of_game():
    logger.plog(f"End of game button")
    time.sleep(1)
    left_click(960, 640)

# Main loop to look for patterns and decide how to fight
def farm_lane():

    patterns = [
        {"box": PLAYER_BOX, "pattern": "patterns/unit/low.png"},
        {"box": START_BOX, "pattern": "patterns/shop/start.png"},
        {"box": FIGHT_BOX, "pattern": "patterns/unit/minion.png"},
        {"box": FIGHT_BOX, "pattern": "patterns/unit/champion.png"},
        {"box": FIGHT_BOX, "pattern": "patterns/unit/tower.png"},
        {"box": FIGHT_BOX, "pattern": "patterns/unit/tower2.png"},
    ]

    loop_time = time.time()

    while True:

        low_life = False
        start_point = False
        nb_enemy_minion = 0
        pos_enemy_minion = []
        pos_closest_enemy_minion = (960, 540)
        nb_enemy_champion = 0
        pos_enemy_champion = (0, 0)
        nb_enemy_tower = 0
        nb_ally_tower = 0
        nb_ally_minion = 0
        pos_ally_minion = []
        pos_safer_ally_minion = (960, 540)
        pos_riskier_ally_minion = (960, 540)
        pos_safe_player = (960, 540)
        pos_median_enemy_minion = (960, 540)

        level_up_abilities()

        # Start pattern matching threads
        with concurrent.futures.ThreadPoolExecutor() as executor:
            results = [
                executor.submit(lookup_thread, *(pattern["box"], pattern["pattern"]))
                for pattern in patterns
            ]
            for f in concurrent.futures.as_completed(results):
                name, loc, width, height, sct_img, left, top = f.result()

                for pt in zip(*loc[::-1]):
                    x, y, side = mark_the_spot(sct_img, pt, width, height, name)

                    if (x, y) != (0, 0):
                        x = x + left
                        y = y + top
                        pass
                    else:
                        continue

                    if name == "start":
                        start_point = True
                    if name == "low":
                        low_life = True
                    if name == "minion" and side == "enemy":
                        nb_enemy_minion += 1
                        pos_enemy_minion.append((x, y))
                    if name == "champion" and side == "enemy":
                        nb_enemy_champion += 1
                        pos_enemy_champion = (x, y)
                    if "tower" in name and side == "enemy":
                        nb_enemy_tower += 1
                    if "tower" in name and side == "ally":
                        nb_ally_tower += 1
                    if name == "minion" and side == "ally":
                        nb_ally_minion += 1
                        pos_ally_minion.append((x, y))

                del sct_img
                del loc
                gc.collect()

        # Calculating positions
        if nb_ally_minion > 0:
            pos_safer_ally_minion = min(pos_ally_minion, key=lambda item: item[0])
            logger.plog(f"pos_safer_ally_minion: {pos_safer_ally_minion}")
            # pos_riskier_ally_minion = max(pos_ally_minion,key=lambda item:item[0])
            risky_minions = []
            for pos_one_ally in pos_ally_minion:
                pos_x = int((pos_one_ally[0] / 1920) * 100)
                pos_y = 100 - int((pos_one_ally[1] / 1080) * 100)
                risky_minions.append(int((pos_x + pos_y) / 2))
            # max(enumerate(a), key=lambda x: x[1])[0]
            pos_riskier_ally_minion = pos_ally_minion[
                risky_minions.index(max(risky_minions))
            ]
            logger.plog(f"pos_riskier_ally_minion: {pos_riskier_ally_minion}")
            pos_safe_player = (
                max(pos_safer_ally_minion[0] - 50, 0),
                min(pos_safer_ally_minion[1] + 50, 1080),
            )
            logger.plog(f"pos_safe_player: {pos_safe_player}")
        if nb_enemy_minion > 0:
            pos_closest_enemy_minion = min(pos_enemy_minion, key=lambda item: item[0])
            pos_median_enemy_minion = average_tuple_list(pos_enemy_minion)
            logger.plog(
                f"pos_median_enemy_minion: {pos_median_enemy_minion} and type: {type(pos_median_enemy_minion)}"
            )

        # Logging
        logger.plog(f"low_life: {low_life} | start_point: {start_point}")
        logger.plog(
            f"nb_enemy_minion: {nb_enemy_minion} | pos_enemy_minion: {pos_enemy_minion}"
        )
        logger.plog(
            f"nb_enemy_champion: {nb_enemy_champion} | pos_enemy_champion: {pos_enemy_champion}"
        )
        logger.plog(
            f"nb_enemy_tower: {nb_enemy_tower} | nb_ally_tower: {nb_ally_tower}"
        )
        logger.plog(
            f"nb_ally_minion: {nb_ally_minion} | pos_ally_minion: {pos_ally_minion}"
        )

        # Priority conditions
        if current_screen == "endofgame":
            end_of_game()
            break
        elif last_screen != "ingame":
            break
        elif low_life:
            logger.plog(f"low life")
            back_and_recall()
            break
        elif start_point:
            logger.plog(f"back at the shop")
            buy_from_shop(shop_list)
            break

        # fight sequences
        if nb_enemy_minion > 0 or nb_enemy_champion > 0:

            # fall back if no allies or 2- minions + a tower or if tower + champion or too many enemies
            # if nb_ally_minion == 0  or (nb_ally_minion <= 2 and nb_enemy_tower > 0) or (nb_enemy_tower > 0 and nb_enemy_champion > 0) or nb_enemy_champion > 3: # more aggressive
            if (
                nb_ally_minion == 0
                or (nb_ally_minion <= 5 and nb_enemy_tower > 0)
                or (nb_enemy_tower > 0 and nb_enemy_champion > 0)
                or nb_enemy_champion > 2
            ):  # more defensive
                logger.plog(f"falling back")
                fall_back(timer=2)
                attack_position(960, 540)

            # primarily attack champions
            elif nb_enemy_champion > 0:
                logger.plog(f"attack enemy champion")
                if nb_enemy_minion > nb_ally_minion and nb_ally_tower == 0:
                    fall_back(1)
                attack_position(
                    *pos_enemy_champion, q=True, e=True, r=True, target_champion=True
                )

            # normal attack sequence
            else:
                logger.plog(f"fight, back if lower numbers")
                if nb_enemy_minion > nb_ally_minion and nb_ally_tower == 0:
                    fall_back()
                attack_position(
                    *pos_closest_enemy_minion,
                    spelltarget=pos_median_enemy_minion,
                    q=True,
                )

        # if no enemies follow minions
        elif nb_ally_minion > 0 and (
            pos_riskier_ally_minion[0] > 960 or pos_riskier_ally_minion[1] < 450
        ):
            logger.plog(f"follow ally minions")
            pydirectinput.keyDown("shift")
            right_click(*pos_riskier_ally_minion)
            pydirectinput.keyUp("shift")

        # no one around, might be lost go back to lane tower
        else:
            logger.plog(f"I feel lost... walking to top tower...")
            fall_back()

        logger.plog(f"FPS {round(1 /(time.time() - loop_time), 2)}\n")
        loop_time = time.time()

# Main program loop
def main():
    logger.plog(f"Main script starting in 5 seconds...")
    time.sleep(5)
    global game_state

    while True:
        if current_screen == "login":
            login()
        if current_screen == "play":
            play()
        if current_screen == "matchmaking":
            matchup()
        if current_screen == "champselect":
            matchup()
        if current_screen == "ingame" and game_state == "start":
            game_start()
            game_state = "playing"
        if current_screen == "postmatch":
            postmatch()

# Start the program and different threads
if __name__ == "__main__":
    logger = Logger(debug=True)
    threads = []
    threads.append(threading.Thread(target=listen_k))
    threads.append(threading.Thread(target=main))
    threads.append(threading.Thread(target=screen_watcher))

    for thread in threads:
        thread.start()

    for thread in threads:
        thread.join()

max_stars_repo_name: TierynnB/LeaguePyBot

max_issues_repo_name: TierynnB/LeaguePyBot

max_forks_repo_name: TierynnB/LeaguePyBot


text:
import os
import pickle
import random
import shutil
from copy import deepcopy
from os import listdir
from os.path import join, isfile
from pathlib import Path

import cv2
import numpy as np
from scipy.ndimage import gaussian_filter

min_sigma = 0
max_sigma = 3  # [0,3]
channel = 1024
image_size = 32

def unpickle(file):
    """
    Unpickle a pickled dict.

    :param file: Path to the pickled file
    :return: unpickled (dict): Unpickled dict
    """
    with open(file, 'rb') as fo:
        d = pickle.load(fo, encoding='bytes')
    return d

def load_cifar(path):
    """
    Loads the cifar dataset.

    :param path: Path to the cifar dataset
    :return: dict: for each set (train, val (not loaded here), test), the loaded images
    """
    print('Loading CIFAR-10')
    # List all files
    files = [f for f in listdir(path) if isfile(join(path, f)) and 'batch' in f]
    files.sort()

    train = []
    test = []
    for file in files:
        filename = os.path.join(path, file)
        # Unpickle the batch
        batch = unpickle(filename)

        if 'data_batch' in filename:
            train.append(batch)
        elif 'test_batch' in filename:
            test.append(batch)

    return {'train': train, 'val': [], 'test': test}

def blur_cifar(ds):  # TODO1 do multiprocessing
    """
    Applies gaussian blurring with random stdev in [0, 3].

    The saved dataset was created with seed = 42.

    :param ds (np.array): Loaded dataset
    :return: blurred (np.array): Blurred dataset
    """
    print('Blurring CIFAR-10')
    result = {key: [] for key in ds}

    for key in ds:
        for entry in ds[key]:
            tmp = []

            for image in entry[b'data']:
                blurred = []  # 0 = red, 1 = green, 2 = blue
                # Compute the random sigma
                sigma = random.randint(min_sigma, max_sigma)

                # for sigma in range(4):
                #    blurred = []
                for i in range(3):
                    # For each channel, blur the image
                    img_c = np.reshape(image[channel * i:channel * (i + 1)], (image_size, image_size))

                    blurred_c = np.reshape(gaussian_filter(img_c, sigma), (channel,))
                    # blurred_c = np.reshape(cv2.GaussianBlur(src=img_c, sigmaX=sigma), (channel,)) # TODO1 check
                    blurred.extend(blurred_c)

                tmp.append(blurred)
                # img = np.array(reshape_img(blurred))
                # cv2.imwrite('/home/alby/'+str(sigma)+'.png', img)

            new_entry = deepcopy(entry)  # a bit heavy
            new_entry[b'data'] = np.array(tmp)
            result[key].append(new_entry)

    return result

def reshape_img(image):
    """
    Reshape an image into the form (height, width, channels).

    :param image (np.array): Loaded image
    :return: reshaped (np.array): Reshaped image
    """
    img = []

    for i in range(3):
        img_c = np.reshape(image[channel * i:channel * (i + 1)], (image_size, image_size))

        img.append(img_c)

    reshaped = np.array(img).swapaxes(0, 1).swapaxes(1, 2)  # (3, 32, 32) -> (32, 32, 3)

    return reshaped

def reshape_cifar(ds):  # TODO1 do multiprocessing
    """
    Reshape the cifar into the form (n_images, height, width, channels).

    :param ds (np.array): Loaded dataset
    :return: reshaped (np.array): Reshaped dataset
    """
    print('Reshaping CIFAR-10')
    result = []

    for entry in ds:
        for image in entry[b'data']:
            img = []

            for i in range(3):
                img_c = np.reshape(image[channel * i:channel * (i + 1)], (image_size, image_size))

                img.append(img_c)

            img_m = np.array(img).swapaxes(0, 1).swapaxes(1, 2)  # (3, 32, 32) -> (32, 32, 3)
            result.append(img_m)

    return np.array(result)

def save_cifar(ds, path):
    """
    Save the images of cifar dataset.

    :param ds (np.array): Loaded dataset
    :param path (string): Path where to save images
    :return: void
    """
    print('Saving updated CIFAR-10 images')
    count = 0

    for image in ds:
        cv2.imwrite(path+str(count)+'.png', image)
        count += 1

def reds_merge(input_path):
    """
    Merge all the reds scene into a single folder (flow_from_directory format)
    :param input_path (string): Path containing the reds dataset
    :return: void
    """
    print('Merging REDS {}'.format(input_path))

    root, dirs, files = next(os.walk(input_path))
    dirs.sort()

    count = 0
    for dir_ in dirs:
        root_n, dirs_n, files_n = next(os.walk(os.path.join(root, dir_)))
        files_n.sort()

        for file in files_n:
            filename = os.path.join(root_n, file)
            # or move/copy to a 'merged' folder
            # shutil.move(filename, os.path.join(input_path, str(count)+".png"))

            # Copy to the new folder
            shutil.copyfile(filename, os.path.join(input_path, str(count)+".png"))

            count += 1

        shutil.rmtree(root_n)

def keras_folder(paths):
    """
    Adds a dummy folder to be compatible with the flow_from_directory (e.g. train/train_blur/folder/<list of images>).
    :param paths (dict): dict containing for each set (train, val, test) the paths to the dataset
    :return: new_paths (dict): updated paths
    """
    print('Moving images into the folder needed by the flow_from_directory')

    res = {key: '' for key in paths}

    for key in paths:
        p = paths[key]
        # Add the 'folder/' directory
        new_p = p + 'folder/'

        files = [f for f in listdir(p)]

        # Create the folder if not existing
        Path(new_p).mkdir(parents=True, exist_ok=True)
        for f in files:
            # Move to the new folder
            shutil.move(p + f, new_p)

        res[key] = new_p

    return res

'''
if __name__ == "__main__":
    cifar_path = '../../res/datasets/cifar-10/'
    cifar_path_modified = cifar_path + 'modified/'
    cifar_train_path = cifar_path_modified + 'data_batch_unified'
    cifar_test_path = cifar_path_modified + 'test_batch'
    cifar_blurred_train_path = cifar_path_modified + 'data_batch_unified_blurred'
    cifar_blurred_test_path = cifar_path_modified + 'test_batch_blurred'
    cifar_saved_paths = {'train': cifar_path + 'saved/train/original/', 'train_b': cifar_path + 'saved/train/blurred/',
                         'test': cifar_path + 'saved/test/original/', 'test_b': cifar_path + 'saved/test/blurred/'}

    cifar = {'train': unpickle(cifar_train_path), 'test': unpickle(cifar_test_path),
             'train_b': unpickle(cifar_blurred_train_path), 'test_b': unpickle(cifar_blurred_test_path)}
    dataset = load_cifar(cifar_path)
    ds_blurred = blur_cifar(dataset)
'''

ext: py

max_stars_repo_name: albertobagnacani/Deblur

max_issues_repo_name: albertobagnacani/Deblur

max_forks_repo_name: albertobagnacani/DeepDeblur

reason: import numpy,from scipy


text:
from nn_learn_back_propagation_engine import Network
from utils import sigmoid , dsigmoid_to_dval , softplus , dsoftplus_to_dval
import numpy as np

def learn_logical_and():
    net = Network([2, 1],sigmoid , dsigmoid_to_dval)
    # by default it start with random numbers
    net.biases[0][0][0] = -25 # exact value is -30
    net.weights[0][0][0] = 15 # exact value is 20
    net.weights[0][0][1] = 15 # exact value is 20

    net.print_shapes()

    x1 = np.array([1 , 0 , 0 , 1])
    x2 = np.array([1 , 0 , 1 , 0])
    y =  np.array([1 , 0 , 0 , 0]) # logic and gate
    x= np.vstack((x1,x2)).T

    mini_batch = [(x_sample.reshape(x_sample.size,1),y_sample) for x_sample , y_sample in zip(x,y)]
    epochs = 30
    net.train(mini_batch,epochs,0.01)

    for x_sample in x:
        print(f"net.feedforward({x_sample}) : {net.feedforward(x_sample)}")

def learn_StatsQuest():
    # this will NOT match StatsQuest because there the activation on layer 3 is linear
    # while the activation on layer 2 is softplus .
    # However , currently Network class has the same activation for every layer.
    # it is not difficult to support activation per nuron but currently it is not supported
    net = Network([1 , 2, 1],softplus , dsoftplus_to_dval)

    # layer 1 -> layer 2
    net.biases[0][0][0] =  0.50560784 # StatsQuest b1 , exact is  0.50560784
    net.biases[0][1][0] = -10.69737385 # StatsQuest b2 , exact is -10.69737385

    net.weights[0][0][0] =  0.54058468 # StatsQuest w1 , exact is  0.54058468
    net.weights[0][1][0] = 12.98906751 # StatsQuest w2 , exact is 12.98906751

    # layer 2 -> layer 3
    net.biases[1][0][0] = -5.59668029 # StatsQuest b3 , exact is -5.5966802
    net.weights[1][0][0] = 5.72510687 # StatsQuest w3 , exact is 5.72510687
    net.weights[1][0][1] = -0.88626893 # StatsQuest w4 , exact is -0.88626893

    net.print_shapes()

    x = np.array([0 , 0.5  , 1])
    y =  np.array([0 , 1 , 0])

    mini_batch = [(x_sample.reshape(x_sample.size,1),y_sample) for x_sample , y_sample in zip(x,y)]
    epochs = 30
    net.train(mini_batch,epochs,0.01)

    for x_sample in x:
        print(f"net.feedforward({x_sample}) : {net.feedforward(x_sample)}")

# main
learn_logical_and()
#learn_StatsQuest()

reason: import numpy


text:
import numpy as np
from dataclasses import dataclass
from stereo_calibration import StereoCalibration
from common_lab_utils import PerspectiveCamera
import cv2
import pyvista as pv
from pylie import SE3

class Scene3D:
    """Visualises the lab in 3D"""

    _do_exit = False
    _current_camera_actors = ()

    def __init__(self, stereo_model: StereoCalibration):
        """Sets up the 3D viewer"""

        self._stereo_model = stereo_model
        self._plotter = pv.Plotter()
        self._point_cloud_actors = None

        # Left camera.
        left_camera_model = PerspectiveCamera(stereo_model.k_left, stereo_model.distortion_left, SE3())
        add_frustum(self._plotter, left_camera_model, stereo_model.img_size, 0.02)
        add_axis(self._plotter, left_camera_model.pose_world_camera, 0.02)

        # Right camera.
        right_camera_model = PerspectiveCamera(stereo_model.k_right, stereo_model.distortion_right, stereo_model.pose_left_right)
        add_frustum(self._plotter, right_camera_model, stereo_model.img_size, 0.02)
        add_axis(self._plotter, right_camera_model.pose_world_camera, 0.02)

        # Set camera.
        self._plotter.camera.position = (-0.017032, -0.160165, -0.518498)
        self._plotter.camera.up = (0.0189573, -0.978103, 0.207257)
        self._plotter.camera.focal_point = (-0.0355778, 0.0142925, 0.306513)

        # Show window.
        self._plotter.show(title="3D visualisation", interactive=True, interactive_update=True)

    def _update_current_camera_visualisation(self, pts_3d: np.ndarray):
        # Remove old visualisation.
        if self._point_cloud_actors is not None:
            self._plotter.remove_actor(self._point_cloud_actors, render=False)

        if len(pts_3d) > 0:
            # Render new visualisation.
            point_cloud = pv.PolyData(pts_3d)
            point_cloud['Depth'] = pts_3d[:, -1]

            self._point_cloud_actors = self._plotter.add_mesh(point_cloud, render_points_as_spheres=True)

    def update(self, pts_3d, time=10):
        """Updates the viewer with new point cloud"""

        self._update_current_camera_visualisation(pts_3d.T)
        self._plotter.update(time)

def add_axis(plotter, pose: SE3, scale=10.0):
    """Adds a 3D axis object to the pyvista plotter"""

    T = pose.to_matrix()

    point = pv.Sphere(radius=0.1 * scale)
    point.transform(T)

    x_arrow = pv.Arrow(direction=(1.0, 0.0, 0.0), scale=scale)
    x_arrow.transform(T)

    y_arrow = pv.Arrow(direction=(0.0, 1.0, 0.0), scale=scale)
    y_arrow.transform(T)

    z_arrow = pv.Arrow(direction=(0.0, 0.0, 1.0), scale=scale)
    z_arrow.transform(T)

    axis_actors = (
        plotter.add_mesh(point),
        plotter.add_mesh(x_arrow, color='red', render=False),
        plotter.add_mesh(y_arrow, color='green', render=False),
        plotter.add_mesh(z_arrow, color='blue', render=False)
    )
    return axis_actors

def add_frustum(plotter, camera_model, image_size, scale=0.1):
    """Adds a camera frustum to the pyvista plotter"""

    S = camera_model.pose_world_camera.to_matrix() @ np.diag([scale, scale, scale, 1.0])

    img_width, img_height = image_size

    point_bottom_left = np.squeeze(camera_model.pixel_to_normalised(np.array([img_width-1., img_height-1.])))
    point_bottom_right = np.squeeze(camera_model.pixel_to_normalised(np.array([0., img_height-1.])))
    point_top_left = np.squeeze(camera_model.pixel_to_normalised(np.array([0., 0.])))
    point_top_right = np.squeeze(camera_model.pixel_to_normalised(np.array([img_width-1., 0.])))

    point_focal = np.zeros([3])

    pyramid = pv.Pyramid([point_bottom_left, point_bottom_right, point_top_left, point_top_right, point_focal])
    pyramid.transform(S)

    rectangle = pv.Rectangle([point_bottom_left, point_bottom_right, point_top_left, point_top_right])
    rectangle.texture_map_to_plane(inplace=True)
    rectangle.transform(S)

    frustum_actor = plotter.add_mesh(pyramid, show_edges=True, style='wireframe', render=False)

    return frustum_actor

@dataclass
class Colours:
    green = (0, 255, 0)
    red = (0, 0, 255)
    white = (255, 255, 255)
    black = (0, 0, 0)

@dataclass
class Font:
    face = cv2.FONT_HERSHEY_PLAIN
    scale = 1.0

def visualise_matches(stereo_pair, stereo_matcher, duration_rectification, duration_matching):
    """ This function will create an image that shows corresponding keypoints in two images."""

    if stereo_matcher.matches is None or not stereo_matcher.keypoints_left or not stereo_matcher.keypoints_right:
        return np.hstack((stereo_pair.left, stereo_pair.right))

    cv2.putText(stereo_pair.left, "LEFT", (10, 20), Font.face, Font.scale, Colours.black)
    cv2.putText(stereo_pair.right, "RIGHT", (10, 20), Font.face, Font.scale, Colours.black)
    vis_img = cv2.drawMatches(
        stereo_pair.left, stereo_matcher.keypoints_left,
        stereo_pair.right, stereo_matcher.keypoints_right,
        stereo_matcher.matches, None, flags=2)
    cv2.putText(vis_img, f"Rectification:  {round(duration_rectification)} ms", (10, 40), Font.face, Font.scale, Colours.red)
    cv2.putText(vis_img, f"Matching:  {round(duration_matching)} ms", (10, 60), Font.face, Font.scale, Colours.red)
    cv2.putText(vis_img, f"Number of matches:  {len(stereo_matcher.matches)}", (10, 80), Font.face, Font.scale, Colours.red)
    return vis_img

def visualise_depths(stereo_pair, pts_left, depths):
    """"""

    vis_depth = cv2.cvtColor(stereo_pair.left, cv2.COLOR_GRAY2BGR)

    marker_size = 5
    for pt, depth in zip(pts_left, depths):
        px = pt.astype(int)
        cv2.drawMarker(vis_depth, px, Colours.green, cv2.MARKER_CROSS, marker_size)
        cv2.putText(vis_depth, f"{depth:.2f}", px, Font.face, Font.scale, Colours.green)

    return vis_depth

def visualise_dense(dense_depth: np.ndarray, min_depth, max_depth, duration_dense):
    vis_dense_depth = dense_depth / max_depth
    vis_dense_depth = cv2.cvtColor(vis_dense_depth * 255, cv2.COLOR_GRAY2BGR).astype(np.uint8)
    vis_dense_depth = cv2.applyColorMap(vis_dense_depth, cv2.COLORMAP_JET)

    cv2.putText(vis_dense_depth, f"Dense:  {round(duration_dense)} ms", (10, 20), Font.face, Font.scale, Colours.white)
    cv2.putText(vis_dense_depth, f"Depth range:  [{min_depth:.2f}, {max_depth:.2f}]", (10, 40), Font.face, Font.scale, Colours.white)

    return vis_dense_depth


text:
#!/usr/bin/env python
"""
Test PSF measurement scripts.

Hazen 01/18
"""
import inspect
import numpy
import os
import tifffile

import storm_analysis
import storm_analysis.sa_library.ia_utilities_c as iaUtilsC
import storm_analysis.sa_library.parameters as parameters
import storm_analysis.sa_library.sa_h5py as saH5Py

import storm_analysis.simulator.background as background
import storm_analysis.simulator.camera as camera
import storm_analysis.simulator.drift as drift
import storm_analysis.simulator.emitters_on_grid as emittersOnGrid
import storm_analysis.simulator.emitters_uniform_random as emittersUniformRandom
import storm_analysis.simulator.photophysics as photophysics
import storm_analysis.simulator.psf as psf
import storm_analysis.simulator.simulate as simulate

import storm_analysis.spliner.measure_psf_beads as measurePSFBeads
import storm_analysis.spliner.measure_psf as spMeasurePSF

import storm_analysis.multi_plane.measure_psf as mpMeasurePSF
import storm_analysis.multi_plane.psf_zstack as psfZStack

import storm_analysis.diagnostics.measure_psf.settings as settings

def psfDiffCheck(psf1, psf2, atol = 1.0e-3, rtol = 1.0e-6):
    is_different = False
    for i in range(psf1.shape[0]):
        #print(i, numpy.max(numpy.abs(psf1[i,:,:] - psf2[i,:,:])))
        if not numpy.allclose(psf1[i,:,:], psf2[i,:,:], atol = atol, rtol = rtol):
            is_different = True
            print("Difference of",
                  numpy.max(numpy.abs(psf1[i,:,:] - psf2[i,:,:])),
                  "at z section", i)

    if is_different:
        with tifffile.TiffWriter("diff.tif") as tf:
            for i in range(psf1.shape[0]):
                tf.save((psf1[i,:,:] - psf2[i,:,:]).astype(numpy.float32))

    return is_different

def measurePSF():

    # Create sparse random localizations for PSF measurement.
    #
    print("Creating random localization.")
    emittersUniformRandom.emittersUniformRandom("sparse_random.hdf5",
                                                0.0002,
                                                settings.margin,
                                                settings.x_size,
                                                settings.y_size,
                                                0.0)

    # Create sparser grid for PSF measurement.
    #
    print("Creating data for PSF measurement.")
    emittersOnGrid.emittersOnGrid("sparse_grid.hdf5",
                                  8,
                                  3,
                                  1.5,
                                  40,
                                  0.0,
                                  0.0)

    # Create text files for PSF measurement.
    #
    locs = saH5Py.loadLocalizations("sparse_random.hdf5")
    [xf, yf] = iaUtilsC.removeNeighbors(locs["x"], locs["y"], 2.0 * ((settings.psf_size/2)+1))
    numpy.savetxt("sparse_random.txt", numpy.transpose(numpy.vstack((xf, yf))))

    locs = saH5Py.loadLocalizations("sparse_grid.hdf5")
    numpy.savetxt("sparse_grid.txt", numpy.transpose(numpy.vstack((locs['x'], locs['y']))))

    # Create drift file, this is used to displace the localizations in the
    # PSF measurement movie.
    #
    dz = numpy.arange(-settings.psf_z_range, settings.psf_z_range + 0.001, 0.010)
    drift_data = numpy.zeros((dz.size, 3))
    drift_data[:,2] = dz
    numpy.savetxt("drift.txt", drift_data)

    # Also create the z-offset file.
    #
    z_offset = numpy.ones((dz.size, 2))
    z_offset[:,1] = dz
    numpy.savetxt("z_offset.txt", z_offset)

    z_offset[:,0] = 0
    numpy.savetxt("z_offset_none_valid.txt", z_offset)

    # Create simulated data for PSF measurement.
    #
    bg_f = lambda s, x, y, i3 : background.UniformBackground(s, x, y, i3, photons = 10)
    cam_f = lambda s, x, y, i3 : camera.Ideal(s, x, y, i3, 100.)
    drift_f = lambda s, x, y, i3 : drift.DriftFromFile(s, x, y, i3, "drift.txt")
    pp_f = lambda s, x, y, i3 : photophysics.AlwaysOn(s, x, y, i3, 20000.0)
    psf_f = lambda s, x, y, i3 : psf.PupilFunction(s, x, y, i3, 100.0, settings.zmn)

    sim = simulate.Simulate(background_factory = bg_f,
                            camera_factory = cam_f,
                            drift_factory = drift_f,
                            photophysics_factory = pp_f,
                            psf_factory = psf_f,
                            x_size = settings.x_size,
                            y_size = settings.y_size)

    if True:
        sim.simulate("sparse_grid.tif", "sparse_grid.hdf5", dz.size)
        sim.simulate("sparse_random.tif", "sparse_random.hdf5", dz.size)

    # Measure the PSF using spliner/measure_psf_beads.py and multiplane/measure_psf.py
    #

    diff_detected = False

    # Grid.
    if True:

        # Remove old results.
        for elt in ["sparse_grid_beads.psf", "sparse_grid_hdf5_zo.psf",
                    "sparse_grid_hdf5.psf", "sparse_grid_hdf5_mp_zo.psf"]:
            if os.path.exists(elt):
                os.remove(elt)

        print("Measuring PSF (beads).")
        measurePSFBeads.measurePSFBeads("sparse_grid.tif",
                                        "z_offset.txt",
                                        "sparse_grid.txt",
                                        "sparse_grid_beads.psf",
                                        aoi_size = int(settings.psf_size/2 + 1),
                                        z_range = settings.psf_z_range,
                                        z_step = settings.psf_z_step)

        print("Measuring PSF (HDF5, with zoffset).")
        spMeasurePSF.measurePSF("sparse_grid.tif",
                                "z_offset.txt",
                                "sparse_grid_ref.hdf5",
                                "sparse_grid_hdf5_zo.psf",
                                aoi_size = int(settings.psf_size/2 + 1),
                                z_range = settings.psf_z_range,
                                z_step = settings.psf_z_step)

        print("Measuring PSF (HDF5).")
        spMeasurePSF.measurePSF("sparse_grid.tif",
                                "",
                                "sparse_grid_ref.hdf5",
                                "sparse_grid_hdf5.psf",
                                aoi_size = int(settings.psf_size/2 + 1),
                                z_range = settings.psf_z_range,
                                z_step = settings.psf_z_step)

        multiplane_path = os.path.dirname(inspect.getfile(storm_analysis)) + "/multi_plane/"
        print("Measure PSF (multiplane).")
        psfZStack.psfZStack("sparse_grid.tif",
                            "sparse_grid.hdf5",
                            "sparse_grid_zstack",
                            aoi_size = int(settings.psf_size/2 + 1))

        mpMeasurePSF.measurePSF("sparse_grid_zstack.npy",
                                "z_offset.txt",
                                "sparse_grid_hdf5_mp_zo.psf",
                                z_range = settings.psf_z_range,
                                z_step = settings.psf_z_step,
                                normalize = True)

        # Check that the PSFs are the same.
        psf_beads = numpy.load("sparse_grid_beads.psf", allow_pickle = True)["psf"]
        psf_hdf5_zo = numpy.load("sparse_grid_hdf5_zo.psf", allow_pickle = True)["psf"]
        psf_hdf5 = numpy.load("sparse_grid_hdf5.psf", allow_pickle = True)["psf"]
        psf_hdf5_mp_zo = numpy.load("sparse_grid_hdf5_mp_zo.psf", allow_pickle = True)["psf"]

        diff_detected = diff_detected or psfDiffCheck(psf_beads, psf_hdf5_zo)
        diff_detected = diff_detected or psfDiffCheck(psf_beads, psf_hdf5)

        # Here we are only checking they are close.
        if (settings.psf_size >= 20):
            diff_detected = diff_detected or psfDiffCheck(psf_beads, psf_hdf5_mp_zo, atol = 0.17, rtol = 0.17)

    # Grid, no valid z offsets. These are supposed to fail.
    #
    if True:
        print("Measuring PSF (beads).")
        try:
            measurePSFBeads.measurePSFBeads("sparse_grid.tif",
                                            "z_offset_none_valid.txt",
                                            "sparse_grid.txt",
                                            "sparse_grid_beads.psf",
                                            aoi_size = int(settings.psf_size/2 + 1),
                                            z_range = settings.psf_z_range,
                                            z_step = settings.psf_z_step)
        except AssertionError:
            pass
        else:
            assert False, "spliner.measure_psf_beads did not fail!"

        print("Measuring PSF (HDF5, with zoffset).")
        try:
            spMeasurePSF.measurePSF("sparse_grid.tif",
                                    "z_offset_none_valid.txt",
                                    "sparse_grid_ref.hdf5",
                                    "sparse_grid_hdf5_zo.psf",
                                    aoi_size = int(settings.psf_size/2 + 1),
                                    z_range = settings.psf_z_range,
                                    z_step = settings.psf_z_step)
        except AssertionError:
            pass
        else:
            assert False, "spliner.measure_psf did not fail!"

        print("Measure PSF (multiplane).")
        try:
            psfZStack.psfZStack("sparse_grid.tif",
                                "sparse_grid.hdf5",
                                "sparse_grid_zstack",
                                aoi_size = int(settings.psf_size/2 + 1))

            mpMeasurePSF.measurePSF("sparse_grid_zstack.npy",
                                    "z_offset_none_valid.txt",
                                    "sparse_grid_hdf5_mp_zo.psf",
                                    z_range = settings.psf_z_range,
                                    z_step = settings.psf_z_step,
                                    normalize = True)
        except AssertionError:
            pass
        else:
            assert False, "multiplane PSF measurement did not fail!"

    # Random.
    if True:

        # Remove old results.
        for elt in ["sparse_random_beads.psf", "sparse_random_hdf5_zo.psf", "sparse_random_hdf5.psf"]:
            if os.path.exists(elt):
                os.remove(elt)

        print("Measuring PSF (beads).")
        measurePSFBeads.measurePSFBeads("sparse_random.tif",
                                        "z_offset.txt",
                                        "sparse_random.txt",
                                        "sparse_random_beads.psf",
                                        aoi_size = int(settings.psf_size/2 + 1),
                                        z_range = settings.psf_z_range,
                                        z_step = settings.psf_z_step)

        print("Measuring PSF (HDF5, with zoffset).")
        spMeasurePSF.measurePSF("sparse_random.tif",
                                "z_offset.txt",
                                "sparse_random_ref.hdf5",
                                "sparse_random_hdf5_zo.psf",
                                aoi_size = int(settings.psf_size/2 + 1),
                                z_range = settings.psf_z_range,
                                z_step = settings.psf_z_step)

        print("Measuring PSF (HDF5).")
        spMeasurePSF.measurePSF("sparse_random.tif",
                                "",
                                "sparse_random_ref.hdf5",
                                "sparse_random_hdf5.psf",
                                aoi_size = int(settings.psf_size/2 + 1),
                                z_range = settings.psf_z_range,
                                z_step = settings.psf_z_step)

        psf_beads = numpy.load("sparse_random_beads.psf", allow_pickle = True)["psf"]
        psf_hdf5_zo = numpy.load("sparse_random_hdf5_zo.psf", allow_pickle = True)["psf"]
        psf_hdf5 = numpy.load("sparse_random_hdf5.psf", allow_pickle = True)["psf"]

        diff_detected = diff_detected or psfDiffCheck(psf_beads, psf_hdf5_zo)
        diff_detected = diff_detected or psfDiffCheck(psf_beads, psf_hdf5)

    if diff_detected:
        print("Difference detected in PSF measurements!")
    else:
        print("No differences detected, all good.")

    if False:
        with tifffile.TiffWriter("psf_diff.tif") as tf:
            for i in range(psf_beads.shape[0]):
                tf.save((psf_beads[i,:,:] - psf_hdf5_zo[i,:,:]).astype(numpy.float32))

if (__name__ == "__main__"):
    measurePSF()

max_stars_repo_name: bintulab/storm-analysis

max_issues_repo_name: bintulab/storm-analysis

max_forks_repo_name: bintulab/storm-analysis


text:
import easygraph as eg
from collections.abc import Collection, Generator, Iterator
import warnings

__all__ = [
    "from_dict_of_dicts", "to_easygraph_graph", "from_edgelist",
    "from_dict_of_lists"
]

def to_easygraph_graph(data, create_using=None, multigraph_input=False):
    """Make a EasyGraph graph from a known data structure.

    The preferred way to call this is automatically
    from the class constructor

    >>> d = {0: {1: {"weight": 1}}}  # dict-of-dicts single edge (0,1)
    >>> G = eg.Graph(d)

    instead of the equivalent

    >>> G = eg.from_dict_of_dicts(d)

    Parameters
    ----------
    data : object to be converted

        Current known types are:
         any EasyGraph graph
         dict-of-dicts
         dict-of-lists
         container (e.g. set, list, tuple) of edges
         iterator (e.g. itertools.chain) that produces edges
         generator of edges
         Pandas DataFrame (row per edge)
         numpy matrix
         numpy ndarray
         scipy sparse matrix
         pygraphviz agraph

    create_using : EasyGraph graph constructor, optional (default=eg.Graph)
        Graph type to create. If graph instance, then cleared before populated.

    multigraph_input : bool (default False)
        If True and  data is a dict_of_dicts,
        try to create a multigraph assuming dict_of_dict_of_lists.
        If data and create_using are both multigraphs then create
        a multigraph from a multigraph.

    """

    # EasyGraph graph type
    if hasattr(data, "adj"):
        try:
            result = from_dict_of_dicts(
                data.adj,
                create_using=create_using,
                multigraph_input=data.is_multigraph(),
            )
            # data.graph should be dict-like
            result.graph.update(data.graph)
            # data.nodes should be dict-like
            # result.add_node_from(data.nodes.items()) possible but
            # for custom node_attr_dict_factory which may be hashable
            # will be unexpected behavior
            for n, dd in data.nodes.items():
                result._node[n].update(dd)
            return result
        except Exception as err:
            raise eg.EasyGraphError(
                "Input is not a correct EasyGraph graph.") from err

    # pygraphviz  agraph
    if hasattr(data, "is_strict"):
        try:
            return eg.from_pyGraphviz_agraph(data, create_using=create_using)
        except Exception as err:
            raise eg.EasyGraphError(
                "Input is not a correct pygraphviz graph.") from err

    # dict of dicts/lists
    if isinstance(data, dict):
        try:
            return from_dict_of_dicts(data,
                                      create_using=create_using,
                                      multigraph_input=multigraph_input)
        except Exception as err:
            if multigraph_input is True:
                raise eg.EasyGraphError(
                    f"converting multigraph_input raised:\n{type(err)}: {err}")
            try:
                return from_dict_of_lists(data, create_using=create_using)
            except Exception as err:
                raise TypeError("Input is not known type.") from err

    # Pandas DataFrame
    try:
        import pandas as pd

        if isinstance(data, pd.DataFrame):
            if data.shape[0] == data.shape[1]:
                try:
                    return eg.from_pandas_adjacency(data, create_using=create_using)
                except Exception as err:
                    msg = "Input is not a correct Pandas DataFrame adjacency matrix."
                    raise eg.EasyGraphError(msg) from err
            else:
                try:
                    return eg.from_pandas_edgelist(data, edge_attr=True, create_using=create_using)
                except Exception as err:
                    msg = "Input is not a correct Pandas DataFrame adjacency edge-list."
                    raise eg.EasyGraphError(msg) from err
    except ImportError:
        warnings.warn("pandas not found, skipping conversion test.", ImportWarning)

    # numpy matrix or ndarray
    try:
        import numpy as np

        if isinstance(data, np.ndarray):
            try:
                return eg.from_numpy_array(data, create_using=create_using)
            except Exception as err:
                raise eg.EasyGraphError(
                    "Input is not a correct numpy matrix or array."
                ) from err
    except ImportError:
        warnings.warn("numpy not found, skipping conversion test.", ImportWarning)

    # scipy sparse matrix - any format
    try:
        import scipy

        if hasattr(data, "format"):
            try:
                return eg.from_scipy_sparse_matrix(data, create_using=create_using)
            except Exception as err:
                raise eg.EasyGraphError(
                    "Input is not a correct scipy sparse matrix type."
                ) from err
    except ImportError:
        warnings.warn("scipy not found, skipping conversion test.", ImportWarning)

    # Note: most general check - should remain last in order of execution
    # Includes containers (e.g. list, set, dict, etc.), generators, and
    # iterators (e.g. itertools.chain) of edges

    if isinstance(data, (Collection, Generator, Iterator)):
        try:
            return from_edgelist(data, create_using=create_using)
        except Exception as err:
            raise eg.EasyGraphError("Input is not a valid edge list") from err

    raise eg.EasyGraphError("Input is not a known data type for conversion.")

def from_dict_of_lists(d, create_using=None):
    G = eg.empty_graph(0, create_using)
    G.add_nodes_from(d)
    if G.is_multigraph() and not G.is_directed():
        # a dict_of_lists can't show multiedges.  BUT for undirected graphs,
        # each edge shows up twice in the dict_of_lists.
        # So we need to treat this case separately.
        seen = {}
        for node, nbrlist in d.items():
            for nbr in nbrlist:
                if nbr not in seen:
                    G.add_edge(node, nbr)
            seen[node] = 1  # don't allow reverse edge to show up
    else:
        G.add_edges_from(
            ((node, nbr) for node, nbrlist in d.items() for nbr in nbrlist))
    return G

def from_dict_of_dicts(d, create_using=None, multigraph_input=False):
    G = eg.empty_graph(0, create_using)
    G.add_nodes_from(d)
    # does dict d represent a MultiGraph or MultiDiGraph?
    if multigraph_input:
        if G.is_directed():
            if G.is_multigraph():
                G.add_edges_from((u, v, key, data) for u, nbrs in d.items()
                                 for v, datadict in nbrs.items()
                                 for key, data in datadict.items())
            else:
                G.add_edges_from((u, v, data) for u, nbrs in d.items()
                                 for v, datadict in nbrs.items()
                                 for key, data in datadict.items())
        else:  # Undirected
            if G.is_multigraph():
                seen = set()  # don't add both directions of undirected graph
                for u, nbrs in d.items():
                    for v, datadict in nbrs.items():
                        if (u, v) not in seen:
                            G.add_edges_from((u, v, key, data)
                                             for key, data in datadict.items())
                            seen.add((v, u))
            else:
                seen = set()  # don't add both directions of undirected graph
                for u, nbrs in d.items():
                    for v, datadict in nbrs.items():
                        if (u, v) not in seen:
                            G.add_edges_from(
                                (u, v, data) for key, data in datadict.items())
                            seen.add((v, u))

    else:  # not a multigraph to multigraph transfer
        if G.is_multigraph() and not G.is_directed():
            # d can have both representations u-v, v-u in dict.  Only add one.
            # We don't need this check for digraphs since we add both directions,
            # or for Graph() since it is done implicitly (parallel edges not allowed)
            seen = set()
            for u, nbrs in d.items():
                for v, data in nbrs.items():
                    if (u, v) not in seen:
                        G.add_edge(u, v, key=0)
                        G[u][v][0].update(data)
                    seen.add((v, u))
        else:
            G.add_edges_from(((u, v, data) for u, nbrs in d.items()
                              for v, data in nbrs.items()))
    return G

def from_edgelist(edgelist, create_using=None):
    """Returns a graph from a list of edges.

    Parameters
    ----------
    edgelist : list or iterator
      Edge tuples

    create_using : EasyGraph graph constructor, optional (default=eg.Graph)
        Graph type to create. If graph instance, then cleared before populated.

    Examples
    --------
    >>> edgelist = [(0, 1)]  # single edge (0,1)
    >>> G = eg.from_edgelist(edgelist)

    or

    >>> G = eg.Graph(edgelist)  # use Graph constructor

    """
    G = eg.empty_graph(0, create_using)
    G.add_edges_from(edgelist)
    return G

max_stars_repo_name: tddschn/Easy-Graph

max_issues_repo_name: tddschn/Easy-Graph

max_forks_repo_name: tddschn/Easy-Graph

reason: import numpy,import scipy


text:
import gdal
import numpy as np
import os,glob,shutil
import netCDF4
# Use osgeo (gdal library) to load shapefile
from osgeo import ogr

################################################################################
# Set up paths etc.

# Path for DEM files (cropped for each catchment)
dem_dir = '/export/anthropocene/array-01/pu17449/parameter_transfer_datasets/MeritDEM_catchments'

# output elev_band file for FUSE:
elevbands_dir = '/export/anthropocene/array-01/pu17449/parameter_transfer_datasets/fuse_catchment_elevs'

if not os.path.exists(elevbands_dir):
	os.mkdir(elevbands_dir)

# Shapefile representing catchments used. Requires attributes:
# ID2: format 'GRDC XXXXXXX' specifying the GRDC catchment ID
# StatLat, StatLon: approximate lat-lon for the catchment.
catchments_metafile = '/export/anthropocene/array-01/pu17449/parameter_transfer_datasets/Beck2015_supplementary_data/Catchments.shp'

# Load catchments metadata (for lat/lon of catchment)
driver = ogr.GetDriverByName("ESRI Shapefile")
dataSource = driver.Open(catchments_metafile, 0)
layer = dataSource.GetLayer()

# Catchments have a single lat/lon point
n_outx = 1
n_outy = 1
# x,y are first index in lat/lon arrays
y=0
x=0

# Number of elevation bands to use for FUSE (user choice)
nbands = 5
# Note Error occured for some catchments, for those regions nbands = 5 was used

overwrite = False

# Change numpy setting to raise errors instead of printing warnings
np.seterr(all='raise')

################################################################################
# initialise output arrays:
elev = np.zeros([n_outy,n_outx],dtype=np.int)
mask = np.ones([n_outy,n_outx],dtype=np.int64)
frac = np.ones([n_outy,n_outx])

band_elev = np.zeros([nbands,n_outy,n_outx])
band_frac = np.zeros([nbands,n_outy,n_outx])

for dem_file in glob.glob(os.path.join(dem_dir,'dem_*.tif')):
	grdcid = os.path.basename(dem_file).split('_')[1][:-4]

	# Output file name
	elevbands_file = os.path.join(elevbands_dir,'catchment_'+grdcid+'_elev_bands.nc')

	if overwrite or not os.path.exists(elevbands_file):
		print('GRDCID:',grdcid)
		try:

			# find lat/lon from metadata shapefile
			latvals = None
			lonvals = None
			layer.ResetReading()
			for feature in layer:
				fid = feature.GetField('ID2')
				if fid[:4]=='GRDC' and grdcid == fid[5:]:
					latvals = [feature.GetField('StatLat')]
					lonvals = [feature.GetField('StatLon')]
			if latvals is None:
				raise Exception('Error, cant find lat/lon values. GRDCID: '+grdcid)

			################################################################################
			# Read in data to calculate grid box elevations
			f=gdal.Open(dem_file)
			rasterband = f.GetRasterBand(1)
			dem_arr = rasterband.ReadAsArray()
			missingval = -9999. # Todo, could read this from the file
			box = np.ma.masked_values(dem_arr,missingval).compressed()
			npoints = len(box)*1.0
			# Mean elevation
			elev[y,x] = box.mean()
			# Now split elevation into bands
			min_elev = box.min()
			max_elev = box.max()
			bands = np.linspace(min_elev,max_elev,num=nbands+1)
			#print(bands)
			for i in range(nbands):
				subset = box[np.logical_and(box> bands[i],box<bands[i+1])]
				band_elev[i,y,x] = subset.mean()
				if i == nbands-1: # Handle last band separately
					# Hack to make sure fracs sum to 1
					# (otherwise there is a small rounding error)
					band_frac[i,y,x] = 1- band_frac[:-1,y,x].sum()
				else:
					band_frac[i,y,x] = len(subset)/npoints
			print('debug area_sum',band_frac[:,y,x].sum())

		except Exception as e:
			print('Error',e)
			print('min/max elev',min_elev,max_elev)
			print('bands',bands)
			print('subset',i,subset)
			continue
			#raise

		###############################################################################
		# Write output file for FUSE elev bands
		# Follows example of file from fuse_grid example: cesm1-cam5_elev_bands.nc

		with netCDF4.Dataset(elevbands_file,'w') as f_out:
			f_out.createDimension('latitude',n_outy)
			f_out.createVariable('latitude',np.float,('latitude'))
			f_out.variables['latitude'].standard_name = "latitude"
			f_out.variables['latitude'].long_name = "latitude"
			f_out.variables['latitude'].units = "degrees_north"
			f_out.variables['latitude'].axis = "Y"
			f_out.variables['latitude'][:] = latvals

			f_out.createDimension('longitude',n_outx)
			f_out.createVariable('longitude',np.float,('longitude'))
			f_out.variables['longitude'].standard_name = "longitude"
			f_out.variables['longitude'].long_name = "longitude"
			f_out.variables['longitude'].units = "degrees_east"
			f_out.variables['longitude'].axis = "X"
			f_out.variables['longitude'][:] = lonvals

			f_out.createDimension('elevation_band',nbands)
			f_out.createVariable('elevation_band',np.int32,('elevation_band'))
			f_out.variables['elevation_band'].long_name = 'elevation_band'
			f_out.variables['elevation_band'].units = '-'
			f_out.variables['elevation_band'][:] = range(1,nbands+1)

			f_out.createVariable('area_frac',np.float32,('elevation_band', 'latitude', 'longitude'), fill_value=-9999)
			f_out.variables['area_frac'].units = "-" ;
			f_out.variables['area_frac'].long_name = "Fraction of grid cell covered by each elevation band."
			f_out.variables['area_frac'][:] = band_frac

			f_out.createVariable('mean_elev',np.float32,('elevation_band', 'latitude', 'longitude'),fill_value=-9999)
			f_out.variables['mean_elev'].units = "m asl" ;
			f_out.variables['mean_elev'].long_name = "Mean elevation of elevation band." ;
			f_out.variables['mean_elev'][:] = band_elev

			f_out.createVariable('prec_frac',np.float32,('elevation_band', 'latitude', 'longitude'), fill_value=-9999)
			f_out.variables['prec_frac'].units = "-" ;
			f_out.variables['prec_frac'].long_name = "Fraction of cell precipitation that falls on each elevation band." ;
			f_out.variables['prec_frac'].comment = 'PFU note: prec frac is just area_frac for now, need to implement scaling/lapse rate with elevation'
			f_out.variables['prec_frac'][:]=band_frac

max_stars_repo_name: BrisClimate/flood-cascade

max_issues_repo_name: BrisClimate/flood-cascade

max_forks_repo_name: BrisClimate/flood-cascade


text:
import numpy as np
import pandas as pd
import sys
import os
from time import time

import tensorflow_addons as tfa
import tensorflow as tf
import gc
import joblib
import pickle

import optuna
from optuna.integration import TFKerasPruningCallback
from optuna.trial import TrialState

#Getting specialty stuff from my git repo
!git clone https://github.com/Ottpocket/Neural.git
sys.path.append('/kaggle/working/Neural')
from layers import *
from models import *

train =
test =
ss =
FEATURES =
TARGET =

np.random.seed(42)
train_percent = .8
X_msk = np.random.choice(a=[True, False], size=int(train.shape[0]), replace=True, p=[.8,.2])

X = train.loc[X_msk,FEATURES].values
y = train.loc[X_msk, TARGET].values

val_X = train.loc[~X_msk,FEATURES].values
val_y = train.loc[~X_msk, TARGET].values

def ff(num_input_columns, BLOCKS, drop_rate, cutmix_noise, mixup_alpha, optimizer, block_sizes =None):

    if block_sizes is None:
        block_sizes = [num_input_columns for _ in range(BLOCKS)]
    else:
        if len(block_sizes) !=BLOCKS:
            print(f'block_sizes has {len(block_sizes)} blocks.  Needs {BLOCKS}.')

    #Input
    inp = tf.keras.layers.Input(num_input_columns)
    x = CutMix(noise = cutmix_noise)(inp)
    x = tf.keras.layers.BatchNormalization()(x)
    x = ResnetBlockTabular(output_dim = block_sizes[0], name=f'Resnet_0')(x)
    x = MixUp(alpha= mixup_alpha)(x)

    for i in range(1,BLOCKS):
        x = ResnetBlockTabular(output_dim = block_sizes[i], name=f'Resnet_{i}')(x)
        x = tf.keras.layers.Dropout(drop_rate)(x)
    x = tf.keras.layers.Dense(1, activation='sigmoid')(x)
    model = tf.keras.Model(inputs=inp, outputs=x)

    model.compile(optimizer=optimizer,
                  loss=tf.keras.losses.BinaryCrossentropy(),
                  metrics=[tf.keras.metrics.AUC()])
    return model

ES = tf.keras.callbacks.EarlyStopping(monitor='val_auc', min_delta=0, patience=20, verbose=0, mode='max')
def objective(trial):
    #from https://github.com/optuna/optuna-examples/blob/main/keras/keras_integration.py
    # Clear clutter from previous session graphs.
    tf.keras.backend.clear_session()
    batch_size = trial.suggest_categorical('batch_size', [512,1024])
    epochs = 200

    ###################################
    # Generate our trial model.
    ###################################
    #Model Architecture specifications
    num_input_columns= len(FEATURES)
    BLOCKS = trial.suggest_int("BLOCKS", 1, 10)
    drop_rate= trial.suggest_float("drop_rate", 0, .2, )

    #Sum of cutmix and mixup <=.5
    cutmix_noise= trial.suggest_float("cutmix_noise", 0., .5)
    mixup_alpha=trial.suggest_float("mixup_alpha", 0., .5 - cutmix_noise)

    #Model Optimizer Specifications
    #Copy pasted from https://github.com/optuna/optuna-examples/blob/main/tensorflow/tensorflow_eager_simple.py
    #Thanks y'all!
    kwargs = {}
    optimizer_options = ["RMSprop", "Adam", "SGD"]
    optimizer_selected = trial.suggest_categorical("optimizer", optimizer_options)
    if optimizer_selected == "RMSprop":
        kwargs["learning_rate"] = trial.suggest_float(
            "rmsprop_learning_rate", 1e-5, 1e-1, log=True
        )
        kwargs["decay"] = trial.suggest_float("rmsprop_decay", 0.85, 0.99)
        kwargs["momentum"] = trial.suggest_float("rmsprop_momentum", 1e-5, 1e-1, log=True)
    elif optimizer_selected == "Adam":
        kwargs["learning_rate"] = trial.suggest_float("adam_learning_rate", 1e-5, 1e-1, log=True)
    elif optimizer_selected == "SGD":
        kwargs["learning_rate"] = trial.suggest_float(
            "sgd_opt_learning_rate", 1e-5, 1e-1, log=True
        )
        kwargs["momentum"] = trial.suggest_float("sgd_opt_momentum", 1e-5, 1e-1, log=True)

    optimizer = getattr(tf.optimizers, optimizer_selected)(**kwargs)

    model = ff(num_input_columns, BLOCKS, drop_rate, cutmix_noise, mixup_alpha, optimizer)

    # Fit the model on the training data.
    # The KerasPruningCallback checks for pruning condition every epoch.
    model.fit(
        X,
        y,
        batch_size=batch_size,
        callbacks=[ES, TFKerasPruningCallback(trial, "val_auc")],
        epochs=epochs,
        validation_data=(val_X, val_y),
        verbose=1,
    )

    # Evaluate the model accuracy on the validation set.
    score = model.evaluate(val_X, val_y, batch_size=10000,verbose=0)
    return score[1]

  study = optuna.create_study(direction="maximize", pruner=optuna.pruners.MedianPruner())
study.optimize(objective, timeout = TIMEOUT) #Optimize for 5 hours.  Let's waste our gpu quota!
#study.optimize(objective, n_trials=5)
pruned_trials = study.get_trials(deepcopy=False, states=[TrialState.PRUNED])
complete_trials = study.get_trials(deepcopy=False, states=[TrialState.COMPLETE])
print("Study statistics: ")
print("  Number of finished trials: ", len(study.trials))
print("  Number of pruned trials: ", len(pruned_trials))
print("  Number of complete trials: ", len(complete_trials))

print("Best trial:")
trial = study.best_trial

print("  Value: ", trial.value)

print("  Params: ")
for key, value in trial.params.items():
    print("    {}: {}".format(key, value))

joblib.dump(study, "study.pkl")
#To regain this study: study = joblib.load("study.pkl") #https://optuna.readthedocs.io/en/stable/faq.html#how-can-i-save-and-resume-studies

max_stars_repo_name: Ottpocket/Neural

max_issues_repo_name: Ottpocket/Neural

max_forks_repo_name: Ottpocket/Neural