From 468f62633c3cd7f5202b2ce0ec1e597361cec673 Mon Sep 17 00:00:00 2001 From: Arne van Iterson Date: Mon, 2 Oct 2023 23:27:30 +0200 Subject: [PATCH] Improved image control (very epic) --- src/helpers/algorithms.py | 0 src/helpers/gui/main.ui | 57 +++++++++---- src/suite.py | 165 +++++++++++++++++++++++--------------- 3 files changed, 143 insertions(+), 79 deletions(-) delete mode 100644 src/helpers/algorithms.py diff --git a/src/helpers/algorithms.py b/src/helpers/algorithms.py deleted file mode 100644 index e69de29..0000000 diff --git a/src/helpers/gui/main.ui b/src/helpers/gui/main.ui index a410225..4594100 100644 --- a/src/helpers/gui/main.ui +++ b/src/helpers/gui/main.ui @@ -169,9 +169,9 @@ - + + imgCtl < Prev img - 2 10 @@ -181,9 +181,9 @@ - + + imgCtl Next img > - 3 10 @@ -197,10 +197,10 @@ Export PNG - 3 + 1 1 - 10 - 6 + 30 + 8 1 @@ -208,10 +208,10 @@ int:export_id - 15 + 10 - 2 - 6 + 0 + 8 @@ -219,9 +219,9 @@ Export Image by ID - 2 + 0 2 - 5 + 7 @@ -280,9 +280,9 @@ - + + applyAll Export ID for entire dataset - 2 2 @@ -303,17 +303,42 @@ - + + applyAll Run analysis for entire dataset (!) - 2 2 15 + 5 8 + + + imgCtl + < Prev tree + + 2 + 10 + 5 + 5 + + + + + + imgCtl + Next tree > + + 3 + 10 + 5 + 5 + + + diff --git a/src/suite.py b/src/suite.py index d486684..842c590 100644 --- a/src/suite.py +++ b/src/suite.py @@ -27,6 +27,7 @@ config_json = json.load(config_file) log = Logger(config_json["out"]) + ## UI class setup class MainApp: def __init__(self, master=None): @@ -101,25 +102,47 @@ class MainApp: """ self.mainwindow.mainloop() - def img_prev(self, event=None): + def imgCtl(self, widget_id): """ - Open previous image from path + Bunch a functions to switch between images in the given dataset """ - if self.img_current == 0: - self.img_current = self.img_max - 1 - else: - self.img_current = self.img_current - 1 + cmd = widget_id.split("_") + + # Determine detection based on widget id + if cmd[0] == "next": + dir = 1 + elif cmd[0] == "prev": + dir = -1 + + # Get name of current img + start = copy.deepcopy( + self.img_name.split("_")[0] + ) # deepcopy cus snaky boi language likes to create pointers + next = start + + while start == next: + # Check for limits + self.img_current += dir + if self.img_current == self.img_max: + self.img_current = 0 + elif self.img_current == -1: + self.img_current = self.img_max - 1 + + if cmd[1] == "img": + break # Stop if only one image should be skipped + elif cmd[1] == "tree": + self.updatePath() + next = copy.deepcopy(self.img_name.split("_")[0]) + + # Update UI self.update(self) - def img_next(self, event=None): - """ - Open next image from path - """ - if self.img_current == (self.img_max - 1): - self.img_current = 0 - else: - self.img_current = self.img_current + 1 - self.update(self) + """ + TODO: + - Primitive surface area + - Derivative max x and y pos + - Function min, max + y position + """ def apply(self, event=None, path=None): """ @@ -150,14 +173,19 @@ class MainApp: else: print("Nothing to export!") - def apply_all(self, event=None, export = True): + def applyAll(self, widget_id): """ Export given preprocess id for every image in the dataset folder """ + if widget_id == "export": + export = True + elif widget_id == "analyse": + export = False + img_id = self.export_id.get() img_current = copy.deepcopy(self.img_current) - if (export): + if export: now = datetime.datetime.now() path = pathlib.Path( config_json["out"], @@ -166,28 +194,24 @@ class MainApp: os.mkdir(path) while True: - self.img_next() - - if (export): + if export: self.apply(path=path) + self.imgCtl("next_img") if self.img_current == img_current: break ## Ensure display is always correct with image self.update() - def analyse_all(self, event=None): - self.apply_all(export=False) - - def add_output(self, data, name: str): + def addOutput(self, data, name: str): """ Add CV2 image to canvas output """ self.output[0].append(data) self.output[1].append(name) - def draw_output(self, size): + def drawOutput(self, size): # Check if size of canvas has updated drawW = self.canvas.winfo_width() @@ -253,14 +277,17 @@ class MainApp: for th1 in range(0, canny_max, canny_step): for th2 in range(0, canny_max, canny_step): - # Canny Edge Detection - edges = cv2.Canny(image=img, threshold1=th1, threshold2=th2) - - w_res = cv2.countNonZero(edges) y_ind = (int)(th1 / canny_step) x_ind = (int)(th2 / canny_step) - results[y_ind].append(w_res) + # Ignore all edges where th1 > th2 + if th1 <= th2: + # Canny Edge Detection + edges = cv2.Canny(image=img, threshold1=th1, threshold2=th2) + w_res = cv2.countNonZero(edges) + results[y_ind].append(w_res) + else: + results[y_ind].append(0) # print(f"Result at thres {th1}, {th2}; \tIndex {y_ind}, {x_ind} \t= {w_res}") # print(results[y_ind]) @@ -313,23 +340,12 @@ class MainApp: log.add(f"Mean {label}", mean[idx]) log.add(f"Std {label}", std[idx]) - def update(self, event=None, part_update=None): + def updatePath(self): + """ + Only update image name and path + """ path = self.img_path.get() - ## Check if hist and canny hm have to be rerendered - if part_update == None: ## If partial update has not been forced, check if full update is required - if self.img_current != self.img_old or self.img_size != self.img_size_old: - part_update = False - self.img_old = self.img_current - self.img_size_old = self.img_size - else: - part_update = True - else: - if part_update == True: - print("Partial update forced!") - else: - print("Full update forced!") - if path != None and path != "": # Get all images at current path images = [] @@ -341,6 +357,28 @@ class MainApp: self.img_max = len(images) self.img_name = os.path.split(images[self.img_current])[1] + return True + else: + return False + + def update(self, event=None, part_update=None): + ## Check if hist and canny hm have to be rerendered + if ( + part_update == None + ): ## If partial update has not been forced, check if full update is required + if self.img_current != self.img_old or self.img_size != self.img_size_old: + part_update = False + self.img_old = self.img_current + self.img_size_old = self.img_size + else: + part_update = True + else: + if part_update == True: + print("Partial update forced!") + else: + print("Full update forced!") + + if self.updatePath(): log.add("Img", self.img_name) # Get all user vars @@ -355,26 +393,27 @@ class MainApp: self.output = [[] for x in range(2)] # Import and resize image - img = cv2.imread(images[self.img_current]) + # img = cv2.imread(images[self.img_current]) + img = cv2.imread(os.path.join(self.img_path.get(), self.img_name)) img = cv2.resize(img, (size, size), interpolation=cv2.INTER_AREA) - self.add_output(img, "Original") + self.addOutput(img, "Original") # Set grayscale img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) - self.add_output(img_gray, "Grayscale") - + self.addOutput(img_gray, "Grayscale") + # Contrast / brightness boost contrast_val = contrast / 100 bright_val = bright / 100 img_contrast = np.clip( contrast_val * (img_gray + bright_val), 0, 255 ).astype(np.uint8) - # self.add_output(img_contrast, F"Contrast / Brightness\n c+{contrast_val} b+{bright_val}") - self.add_output(img_contrast, f"BCG") + # self.addOutput(img_contrast, F"Contrast / Brightness\n c+{contrast_val} b+{bright_val}") + self.addOutput(img_contrast, f"BCG") # Blurred edition img_blur = cv2.GaussianBlur(img_gray, (3, 3), 0) - self.add_output(img_blur, "Blurred_k3") + self.addOutput(img_blur, "Blurred_k3") # Sobel edge if sxy in ["x", "y", "both"]: @@ -394,17 +433,17 @@ class MainApp: else: img_sobel = img_gray - self.add_output(img_sobel, "Sobel_edge") + self.addOutput(img_sobel, "Sobel_edge") log.add("Sobel nonzero", cv2.countNonZero(img_sobel)) # Canny edge img_canny = cv2.Canny(image=img_blur, threshold1=ct1, threshold2=ct2) - self.add_output(img_canny, "Canny_edge") + self.addOutput(img_canny, "Canny_edge") # BGR - self.add_output(img[:, :, 0], "BGR_B") - self.add_output(img[:, :, 1], "BGR_G") - self.add_output(img[:, :, 2], "BGR_R") + self.addOutput(img[:, :, 0], "BGR_B") + self.addOutput(img[:, :, 1], "BGR_G") + self.addOutput(img[:, :, 2], "BGR_R") if img is not None: self.drawHist(img, ("B", "G", "R"), 0, 0) @@ -412,10 +451,10 @@ class MainApp: # HSV img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) - self.add_output(img_hsv, "HSV") - self.add_output(img_hsv[:, :, 0], "HSV_H") # H - self.add_output(img_hsv[:, :, 1], "HSV_S") # S - self.add_output(img_hsv[:, :, 2], "HSV_V") # V + self.addOutput(img_hsv, "HSV") + self.addOutput(img_hsv[:, :, 0], "HSV_H") # H + self.addOutput(img_hsv[:, :, 1], "HSV_S") # S + self.addOutput(img_hsv[:, :, 2], "HSV_V") # V if not part_update: if img_hsv is not None: @@ -430,11 +469,11 @@ class MainApp: if not part_update: log.update() else: - log.clear() # Prevent partial updates from breaking log + log.clear() # Prevent partial updates from breaking log # Show all data plt.show(block=False) ## Graphs - self.draw_output(size) ## Images + self.drawOutput(size) ## Images if __name__ == "__main__":