226 lines
8.1 KiB
Python
226 lines
8.1 KiB
Python
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("<Left>", loadImagePrevious)
|
|
ROOT.bind("<Right>", 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("<Button 1>", add_pos)
|
|
CURIMAGE.bind("<Button 3>", remove_pos)
|
|
CURIMAGE.bind("<Button-1>", add_pos)
|
|
CURIMAGE.bind("<Button-3>", remove_pos)
|
|
|
|
B_RESET = tk.Button(F_BUTTONS, text="Reset", command=reset)
|
|
B_RESET.grid(row=0, column=0, sticky="W")
|
|
B_APPLY = tk.Button(F_BUTTONS, text="Apply", command=apply)
|
|
B_APPLY.grid(row=0, column=1, sticky="E")
|
|
B_PREVIOUS = tk.Button(F_BUTTONS, text="Previous", command=loadImagePrevious)
|
|
B_PREVIOUS.grid(row=0, column=2, sticky="E")
|
|
B_NEXT = tk.Button(F_BUTTONS, text="Next", command=loadImageNext)
|
|
B_NEXT.grid(row=0, column=3, sticky="E")
|
|
B_SLOAD = tk.Button(F_BUTTONS, text="Load Settings", command=settings_load)
|
|
B_SLOAD.grid(row=0, column=4, sticky="E")
|
|
B_SSAVE = tk.Button(F_BUTTONS, text="Save Settings", command=settings_save)
|
|
B_SSAVE.grid(row=0, column=5, sticky="E")
|
|
B_EXPORT = tk.Button(F_BUTTONS, text="Export Images", command=export)
|
|
B_EXPORT.grid(row=0, column=6, sticky="E")
|