from copy import deepcopy import tkinter as tk from os.path import join from PIL import Image, ImageTk from cv2 import convertScaleAbs, cvtColor, COLOR_BGR2RGB from json import load, dump from fileutils import dslice, summarize, DIROUT IMAGES = [] CURIMINDEX = 0 CURQUEUE = {} WIDTH = 1028 HEIGHT = 1080 def init(imgList): global CURQUEUE IMAGES.extend(imgList) CURQUEUE = deepcopy(IMAGES[CURIMINDEX].opqueue) loadCMPImage() loadImage() def convertImage(img): # Currently only expect grayscale and RGB images if img.dtype == "uint16": img = convertScaleAbs(img, alpha=255.0/65535.0) if len(img.shape) > 2: img = cvtColor(img, COLOR_BGR2RGB) img = Image.fromarray(img) return ImageTk.PhotoImage(img) def loadImage(event=None): IMAGES[CURIMINDEX].apply(CURQUEUE) label = IMAGES[CURIMINDEX].__repr__() img = convertImage(IMAGES[CURIMINDEX].data) IMLABEL.configure(text=label) IMLABEL.text = label CURIMAGE.configure(image=img) CURIMAGE.image = img def loadCMPImage(event=None): IMAGES[CURIMINDEX].apply(dslice(CURQUEUE, 0, int(S_CMPIMAGE.get()))) img = convertImage(IMAGES[CURIMINDEX].data) CMPIMAGE.configure(image=img) CMPIMAGE.image = img def loadImageNext(event=None): global CURIMINDEX CURIMINDEX = (CURIMINDEX+1) % (len(IMAGES)) reset() loadCMPImage() def loadImagePrevious(event=None): global CURIMINDEX CURIMINDEX = (CURIMINDEX-1) % (len(IMAGES)) reset() loadCMPImage() def reset(event=None): global CURQUEUE CURQUEUE = deepcopy(IMAGES[CURIMINDEX].opqueue) if "wshed" in CURQUEUE: S_BLURSIZE.set(CURQUEUE["wshed"][2]["blur"]) S_THRESH.set(CURQUEUE["wshed"][2]["min_thresh"]) S_SIZE.set(CURQUEUE["wshed"][2]["min_size"]) S_DISTANCE.set(CURQUEUE["wshed"][2]["dist"]) S_MBRIGHT.set(CURQUEUE["wshed"][2]["min_mean_brightness"]) S_ROUND.set(CURQUEUE["wshed"][2]["min_roundness"]) loadImage() def apply(event=None): IMAGES[CURIMINDEX].opqueue = deepcopy(CURQUEUE) def set_blursize(ksize): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["blur"] = int(ksize)-1 loadImage() def set_min_thresh(min_thresh): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["min_thresh"] = int(min_thresh) loadImage() def set_min_size(min_size): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["min_size"] = int(min_size) loadImage() def set_distance(dist): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["dist"] = int(dist) loadImage() def set_min_mean_brightness(min_mean_brightness): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["min_mean_brightness"] = int(min_mean_brightness) loadImage() def set_min_roundness(min_roundness): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["min_roundness"] = float(min_roundness) loadImage() def set_comp(qslice): loadCMPImage() def add_pos(event): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["ignore"].append((event.x, event.y)) loadImage() def remove_pos(event): if "wshed" in CURQUEUE: # print(f"box_x: {event.x-5}, {event.x+5}") # print(f"box_y: {event.y-5}, {event.y+5}") CURQUEUE["wshed"][2]["ignore"] = [ pos for pos in CURQUEUE["wshed"][2]["ignore"] if (((event.x-15) < pos[0] < (event.x+15)) is False) and (((event.y-15) < pos[1] < (event.y+15)) is False) ] loadImage() def clear_pos(event): if "wshed" in CURQUEUE: CURQUEUE["wshed"][2]["ignore"] = [] loadImage() def export(event=None): [(f.apply(f.opqueue), f.save(True, f.opqueue)) for f in IMAGES] summary = summarize([f.meta for f in IMAGES]) summary.to_csv(join(DIROUT, "summary.csv"), index=False) summary.groupby(["Hour", "Culture"]).mean().round(4).to_csv(join(DIROUT, "summary_mean.csv")) summary.groupby(["Hour", "Culture"]).std().round(4).to_csv(join(DIROUT, "summary_std.csv")) def settings_load(event=None): with open("imageConfig.json", "r") as f: settings = load(f) for (n, i) in enumerate(IMAGES): if repr(i) in settings: [ IMAGES[n].opqueue.__setitem__(k, [i.opqueue[k][0]] + settings[repr(i)][k] ) for k in i.opqueue if k in settings[repr(i)] ] reset() def settings_save(event=None): with open("imageConfig.json", "w") as f: dump(dict([[repr(i), dict([[o, i.opqueue[o][1:]] for o in i.opqueue])] for i in IMAGES]), f) def run(): ROOT.mainloop() ROOT = tk.Tk() ROOT.wm_title("FP Analysis") ROOT.geometry(f"{WIDTH}x{HEIGHT}") ROOT.rowconfigure(0, weight=3) ROOT.rowconfigure(1, weight=10) ROOT.rowconfigure(2, weight=1) ROOT.bind("", loadImagePrevious) ROOT.bind("", loadImageNext) ROOT.bind("q", loadImagePrevious) ROOT.bind("w", loadImageNext) ROOT.bind("a", apply) ROOT.bind("r", reset) ROOT.bind("s", settings_save) ROOT.bind("l", settings_load) ROOT.bind("e", export) ROOT.bind("c", clear_pos) F_SLIDERS = tk.Frame(ROOT, width=WIDTH, height=50) F_SLIDERS.grid(row=0) F_IMAGE = tk.Canvas(ROOT, width=WIDTH, height=500) F_IMAGE.grid(row=1) F_IMAGE.rowconfigure(0, weight=0) F_IMAGE.rowconfigure(1, weight=10) F_BUTTONS = tk.Frame(ROOT, width=WIDTH, height=50) F_BUTTONS.grid(row=2) S_BLURSIZE = tk.Scale(F_SLIDERS, label='Blur Size', from_=0, to=255, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=25, resolution=2, command=set_blursize) S_BLURSIZE.grid(row=0, column=0, sticky="N") S_THRESH = tk.Scale(F_SLIDERS, label='Min Threshold', from_=0, to=255, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=25, resolution=1, command=set_min_thresh) S_THRESH.grid(row=1, column=0, sticky="N") S_DISTANCE = tk.Scale(F_SLIDERS, label='Distance Transform', from_=0, to=50, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=10, resolution=1, command=set_distance) S_DISTANCE.grid(row=2, column=0, sticky="N") S_SIZE = tk.Scale(F_SLIDERS, label='Filter: Min Size', from_=0, to=500, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=25, resolution=1, command=set_min_size) S_SIZE.grid(row=3, column=0, sticky="N") S_MBRIGHT = tk.Scale(F_SLIDERS, label='Filter: Min Mean Brightness', from_=0, to=255, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=25, resolution=1, command=set_min_mean_brightness) S_MBRIGHT.grid(row=4, column=0, sticky="N") S_ROUND = tk.Scale(F_SLIDERS, label='Filter: Min Roundness', from_=0, to=1, orient=tk.HORIZONTAL, length=WIDTH-10, showvalue=True, tickinterval=0.1, resolution=0.05, command=set_min_roundness) S_ROUND.grid(row=5, column=0, sticky="N") S_CMPIMAGE = tk.Scale(F_IMAGE, label=None, from_=0, to=4, orient=tk.HORIZONTAL, length=WIDTH/2-10, showvalue=False, tickinterval=1, resolution=1, command=set_comp) S_CMPIMAGE.grid(row=0, column=0, sticky="N") IMLABEL = tk.Label(F_IMAGE, text="", height=1) IMLABEL.grid(row=0, column=1) CURIMAGE = tk.Label(F_IMAGE, image=None) CURIMAGE.grid(row=1, column=1) CMPIMAGE = tk.Label(F_IMAGE, image=None) CMPIMAGE.grid(row=1, column=0) CURIMAGE.bind("