From 983da36ce65d873d5dc56d8b2bc4e86bd14004e2 Mon Sep 17 00:00:00 2001 From: Ivan Perzhinsky <94743980+xzripper@users.noreply.github.com> Date: Tue, 26 Mar 2024 03:33:39 +0200 Subject: [PATCH] V1.1.0 V1.1.0 --- draw.py | 44 ++++++++++++++++++++++++++----- main.py | 75 +++++++++++++++++++++++++++++++++++++++++++---------- ui_utils.py | 5 ++++ 3 files changed, 104 insertions(+), 20 deletions(-) diff --git a/draw.py b/draw.py index f5eca20..66b7932 100644 --- a/draw.py +++ b/draw.py @@ -1,6 +1,6 @@ from imgui_standalone import ImGuiStandaloneUtilities -from cv2 import Canny, imread, resize, cvtColor, COLOR_BGR2GRAY +from cv2 import Canny, Laplacian, imread, resize, cvtColor, COLOR_BGR2GRAY, CV_64F from mouse import move, click @@ -17,9 +17,9 @@ def draw_more_black_r_white(image_path: str, area: tuple, threshold: int, invers pixels_drawn = 0 for y in range(area[1]): - if _utils.get_value('request_stop') or is_pressed('F5'): break - - for x in range(area[0]): + for x in range(area[0]): + if _utils.get_value('request_stop') or is_pressed('F5'): break + b, g, r = image[y, x] if pixels_drawn == _utils.get_value('skip_after'): @@ -43,9 +43,9 @@ def draw_brightness_threshold(image_path: str, area: tuple, threshold: int, inve pixels_drawn = 0 for y in range(area[1]): - if _utils.get_value('request_stop') or is_pressed('F5'): break - for x in range(area[0]): + if _utils.get_value('request_stop') or is_pressed('F5'): break + if pixels_drawn == _utils.get_value('skip_after'): pixels_drawn = 0 @@ -67,9 +67,39 @@ def draw_edge(image_path: str, area: tuple, threshold: list, inversed: bool, del pixels_drawn = 0 for y in range(area[1]): - if _utils.get_value('request_stop') or is_pressed('F5'): break + for x in range(area[0]): + if _utils.get_value('request_stop') or is_pressed('F5'): break + + if pixels_drawn == _utils.get_value('skip_after'): + pixels_drawn = 0 + + else: + if (not (edges[y, x] > 0)) if inversed else edges[y, x] > 0: + pixels_drawn += 1 + + move(area[2] + x, area[3] + y); click() + sleep(delay) + +def draw_laplacian(image_path: str, area: tuple, threshold: int, inversed: bool, delay: float, _utils: ImGuiStandaloneUtilities) -> None: + if threshold > 31: + threshold = 31 + + if threshold > 1 and threshold % 2 == 0: + threshold += 1 + + image = imread(image_path) + + image = resize(image, (area[0], area[1])) + + edges = Laplacian(cvtColor(image, COLOR_BGR2GRAY), CV_64F, ksize=threshold) + + pixels_drawn = 0 + + for y in range(area[1]): for x in range(area[0]): + if _utils.get_value('request_stop') or is_pressed('F5'): break + if pixels_drawn == _utils.get_value('skip_after'): pixels_drawn = 0 diff --git a/main.py b/main.py index ffbd6f5..6fd333b 100644 --- a/main.py +++ b/main.py @@ -2,18 +2,18 @@ from imgui import text, text_disabled, button, radio_button, checkbox, input_int, input_int2, input_float, dummy, same_line -from ui_utils import ask_image, ask_area +from ui_utils import error, ask_image, ask_area -from draw import draw_more_black_r_white, draw_brightness_threshold, draw_edge +from draw import draw_more_black_r_white, draw_brightness_threshold, draw_edge, draw_laplacian from time import perf_counter from loguru import logger -logger.info('Ready!') +MID_VERSION: str = 'v1.1.0-alpha' -MID_VERSION: str = 'v1.0.0' +DEFAULT_THRESHOLD_EDGE: list = [25, 25] ImGuiStandaloneUtilities.set_value('image', None) @@ -33,7 +33,7 @@ ImGuiStandaloneUtilities.set_value('_EDGE', True) -ImGuiStandaloneUtilities.set_value('_threshold', 0) +ImGuiStandaloneUtilities.set_value('_threshold', DEFAULT_THRESHOLD_EDGE) logger.info(f'Registered {", ".join(ImGuiStandaloneUtilities.values.keys())}.') @@ -88,23 +88,33 @@ def main() -> None: if not isinstance(ImGuiStandaloneUtilities.get_value('_threshold'), int): logger.info('Casting _threshold to INT...') - ImGuiStandaloneUtilities.set_value('_threshold', 0) + ImGuiStandaloneUtilities.set_value('_threshold', ImGuiStandaloneUtilities.get_value('_threshold')[0]) - ImGuiStandaloneUtilities.set_value('_threshold', 0 if (_t := input_int('Threshold.', ImGuiStandaloneUtilities.get_value('_threshold'))[1]) < 0 else _t) + ImGuiStandaloneUtilities.set_value('_threshold', 255 if ImGuiStandaloneUtilities.get_value('_threshold') > 255 else \ + (0 if (_t := input_int('Threshold.', ImGuiStandaloneUtilities.get_value('_threshold'))[1]) < 0 else _t)) else: if not isinstance(ImGuiStandaloneUtilities.get_value('_threshold'), list): logger.info('Casting _threshold to LIST...') - ImGuiStandaloneUtilities.set_value('_threshold', [0, 0]) + ImGuiStandaloneUtilities.set_value('_threshold', [25, 25]) - ImGuiStandaloneUtilities.set_value('_threshold', [0, 0] if sum(_t := input_int2('Threshold.', *ImGuiStandaloneUtilities.get_value('_threshold'))[1]) < 0 else _t) + _threshold = input_int2('Threshold.', *ImGuiStandaloneUtilities.get_value('_threshold'))[1] + + if _threshold[0] < 0: _threshold[0] = 0 + elif _threshold[0] > 255: _threshold[0] = 255 + + if _threshold[1] < 0: _threshold[1] = 0 + elif _threshold[1] > 255: _threshold[1] = 255 + + ImGuiStandaloneUtilities.set_value('_threshold', _threshold) ImGuiStandaloneUtilities.set_value('skip_after', -1 if (_s := input_int('Skip each:...', ImGuiStandaloneUtilities.get_value('skip_after'))[1]) < -1 else _s) if radio_button('MORE_BLACK_R_WHITE', ImGuiStandaloneUtilities.get_value('_MORE_BLACK_R_WHITE')): ImGuiStandaloneUtilities.set_value('_BRIGHTNESS_THRESHOLDING', False) ImGuiStandaloneUtilities.set_value('_EDGE', False) + ImGuiStandaloneUtilities.set_value('_LAPLACIAN', False) ImGuiStandaloneUtilities.set_value('_MORE_BLACK_R_WHITE', not ImGuiStandaloneUtilities.get_value('_MORE_BLACK_R_WHITE')) @@ -115,14 +125,16 @@ def main() -> None: if radio_button('BRIGHTNESS_THRESHOLDING', ImGuiStandaloneUtilities.get_value('_BRIGHTNESS_THRESHOLDING')): ImGuiStandaloneUtilities.set_value('_MORE_BLACK_R_WHITE', False) ImGuiStandaloneUtilities.set_value('_EDGE', False) + ImGuiStandaloneUtilities.set_value('_LAPLACIAN', False) ImGuiStandaloneUtilities.set_value('_BRIGHTNESS_THRESHOLDING', not ImGuiStandaloneUtilities.get_value('_BRIGHTNESS_THRESHOLDING')) logger.info('Mode: BRIGHTNESS_THRESHOLDING.') - if radio_button('EDGE', ImGuiStandaloneUtilities.get_value('_EDGE')): + if radio_button('EDGE_CANNY', ImGuiStandaloneUtilities.get_value('_EDGE')): ImGuiStandaloneUtilities.set_value('_MORE_BLACK_R_WHITE', False) ImGuiStandaloneUtilities.set_value('_BRIGHTNESS_THRESHOLDING', False) + ImGuiStandaloneUtilities.set_value('_LAPLACIAN', False) ImGuiStandaloneUtilities.set_value('_EDGE', not ImGuiStandaloneUtilities.get_value('_EDGE')) @@ -130,7 +142,16 @@ def main() -> None: same_line() - text_disabled('COLOR_CLUSTERING'); same_line() + if radio_button('LAPLACIAN', ImGuiStandaloneUtilities.get_value('_LAPLACIAN')): + ImGuiStandaloneUtilities.set_value('_MORE_BLACK_R_WHITE', False) + ImGuiStandaloneUtilities.set_value('_BRIGHTNESS_THRESHOLDING', False) + ImGuiStandaloneUtilities.set_value('_EDGE', False) + + ImGuiStandaloneUtilities.set_value('_LAPLACIAN', not ImGuiStandaloneUtilities.get_value('_LAPLACIAN')) + + logger.info('Mode: LAPLACIAN.') + + same_line() ImGuiStandaloneUtilities.set_value('inversed', checkbox('Inverse.', ImGuiStandaloneUtilities.get_value('inversed'))[1]) @@ -142,6 +163,16 @@ def main() -> None: if not ImGuiStandaloneUtilities.get_value('drawing'): if button('Draw.'): + if not ImGuiStandaloneUtilities.get_value('image'): + error('Missing image.', 'Please specify image.') + + return + + if not ImGuiStandaloneUtilities.get_value('draw_area'): + error('Missing area.', 'Please specify area.') + + return + before_drawing = perf_counter() if ImGuiStandaloneUtilities.get_value('_MORE_BLACK_R_WHITE'): @@ -186,8 +217,24 @@ def main() -> None: ImGuiStandaloneUtilities.get_value('delay'), ImGuiStandaloneUtilities) + elif ImGuiStandaloneUtilities.get_value('_LAPLACIAN'): + logger.info('Starting drawing with mode LAPLACIAN.') + + draw_laplacian( + ImGuiStandaloneUtilities.get_value('image'), + + ImGuiStandaloneUtilities.get_value('draw_area'), + + ImGuiStandaloneUtilities.get_value('_threshold'), + + ImGuiStandaloneUtilities.get_value('inversed'), + + ImGuiStandaloneUtilities.get_value('delay'), ImGuiStandaloneUtilities) + ImGuiStandaloneUtilities.set_value('_drawing_took', perf_counter() - before_drawing) + logger.info(f'Drawing took: {ImGuiStandaloneUtilities.get_value("_drawing_took"):.2f}s.') + else: text_disabled('Draw.') same_line() @@ -202,8 +249,10 @@ def main() -> None: else: text_disabled('Stop. (F5).') - same_line(); text(f'MID {MID_VERSION}'); same_line(); dummy(20, 0); same_line(); text(F'imgui-s {IMGUI_STANDALONE_VERSION}') + same_line(); text(f'MID {MID_VERSION}'); same_line(); dummy(15, 0); same_line(); text(F'imgui-s {IMGUI_STANDALONE_VERSION}') logger.info('Initializing window...') -ImGuiStandalone('Mouse Image Drawer.', 375, 215, True, None, None).loop(main) +ImGuiStandalone('Mouse Image Drawer.', 390, 215, False, None, None).loop(main) + +logger.info('Window closed.') diff --git a/ui_utils.py b/ui_utils.py index c66355d..d4148b2 100644 --- a/ui_utils.py +++ b/ui_utils.py @@ -2,6 +2,8 @@ from tkinter.filedialog import askopenfilename +from tkinter.messagebox import showerror + from threading import Thread @@ -9,6 +11,9 @@ _area = [None] +def error(title: str, message: str) -> None: + showerror(title, message) + def ask_image() -> str: return askopenfilename(filetypes=[('Image', '*.png *.jpg *.jpeg')], title='Select image.')