From: Project Hentai AI Date: Wed, 2 Feb 2022 12:36:46 +0000 (+0000) Subject: Code and demo dataset added X-Git-Url: https://git.hentai-ai.org/?a=commitdiff_plain;h=0b89ff783ed8ec15e2a7c4a402f443127a161a7b;p=hentai-cropper.git%2F.git Code and demo dataset added --- diff --git a/demo_input_dir/thighs-0000.png b/demo_input_dir/thighs-0000.png new file mode 100644 index 0000000..4e5f8e6 Binary files /dev/null and b/demo_input_dir/thighs-0000.png differ diff --git a/demo_input_dir/thighs-0001.png b/demo_input_dir/thighs-0001.png new file mode 100644 index 0000000..7ce7f23 Binary files /dev/null and b/demo_input_dir/thighs-0001.png differ diff --git a/demo_input_dir/thighs-0002.png b/demo_input_dir/thighs-0002.png new file mode 100644 index 0000000..7e1545f Binary files /dev/null and b/demo_input_dir/thighs-0002.png differ diff --git a/demo_input_dir/thighs-0003.png b/demo_input_dir/thighs-0003.png new file mode 100644 index 0000000..039d4dc Binary files /dev/null and b/demo_input_dir/thighs-0003.png differ diff --git a/demo_input_dir/thighs-0004.png b/demo_input_dir/thighs-0004.png new file mode 100644 index 0000000..09eac98 Binary files /dev/null and b/demo_input_dir/thighs-0004.png differ diff --git a/demo_input_dir/thighs-0005.png b/demo_input_dir/thighs-0005.png new file mode 100644 index 0000000..5477e17 Binary files /dev/null and b/demo_input_dir/thighs-0005.png differ diff --git a/demo_input_dir/thighs-0006.png b/demo_input_dir/thighs-0006.png new file mode 100644 index 0000000..eddf6fe Binary files /dev/null and b/demo_input_dir/thighs-0006.png differ diff --git a/demo_input_dir/thighs-0007.png b/demo_input_dir/thighs-0007.png new file mode 100644 index 0000000..6fc6be1 Binary files /dev/null and b/demo_input_dir/thighs-0007.png differ diff --git a/demo_input_dir/thighs-0008.png b/demo_input_dir/thighs-0008.png new file mode 100644 index 0000000..1969cc2 Binary files /dev/null and b/demo_input_dir/thighs-0008.png differ diff --git a/demo_input_dir/thighs-0009.png b/demo_input_dir/thighs-0009.png new file mode 100644 index 0000000..87f3bcb Binary files /dev/null and b/demo_input_dir/thighs-0009.png differ diff --git a/demo_input_dir/thighs-0010.png b/demo_input_dir/thighs-0010.png new file mode 100644 index 0000000..c183196 Binary files /dev/null and b/demo_input_dir/thighs-0010.png differ diff --git a/demo_input_dir/thighs-0011.png b/demo_input_dir/thighs-0011.png new file mode 100644 index 0000000..5860bca Binary files /dev/null and b/demo_input_dir/thighs-0011.png differ diff --git a/demo_input_dir/thighs-0012.png b/demo_input_dir/thighs-0012.png new file mode 100644 index 0000000..1ee6312 Binary files /dev/null and b/demo_input_dir/thighs-0012.png differ diff --git a/demo_input_dir/thighs-0013.png b/demo_input_dir/thighs-0013.png new file mode 100644 index 0000000..da8089e Binary files /dev/null and b/demo_input_dir/thighs-0013.png differ diff --git a/demo_input_dir/thighs-0014.png b/demo_input_dir/thighs-0014.png new file mode 100644 index 0000000..5f5f25b Binary files /dev/null and b/demo_input_dir/thighs-0014.png differ diff --git a/demo_input_dir/thighs-0015.png b/demo_input_dir/thighs-0015.png new file mode 100644 index 0000000..b5b7b04 Binary files /dev/null and b/demo_input_dir/thighs-0015.png differ diff --git a/demo_input_dir/thighs-0016.png b/demo_input_dir/thighs-0016.png new file mode 100644 index 0000000..b6f3fb5 Binary files /dev/null and b/demo_input_dir/thighs-0016.png differ diff --git a/demo_input_dir/thighs-0017.png b/demo_input_dir/thighs-0017.png new file mode 100644 index 0000000..f65479f Binary files /dev/null and b/demo_input_dir/thighs-0017.png differ diff --git a/demo_input_dir/thighs-0018.png b/demo_input_dir/thighs-0018.png new file mode 100644 index 0000000..59b99be Binary files /dev/null and b/demo_input_dir/thighs-0018.png differ diff --git a/demo_input_dir/thighs-0019.png b/demo_input_dir/thighs-0019.png new file mode 100644 index 0000000..f52e7a7 Binary files /dev/null and b/demo_input_dir/thighs-0019.png differ diff --git a/demo_input_dir/thighs-0020.png b/demo_input_dir/thighs-0020.png new file mode 100644 index 0000000..a08ff48 Binary files /dev/null and b/demo_input_dir/thighs-0020.png differ diff --git a/hentai-cropper.py b/hentai-cropper.py new file mode 100644 index 0000000..ae21d4a --- /dev/null +++ b/hentai-cropper.py @@ -0,0 +1,196 @@ +# This application is based on: +# https://github.com/foobar167/junkyard/blob/master/zoom_advanced.py + +# -*- coding: utf-8 -*- +# Advanced zoom example. Like in Google Maps. +# It zooms only a tile, but not the whole image. So the zoomed tile occupies +# constant memory and not cram it with a huge resized image for the large zooms. + +import tkinter as tk +from tkinter import ttk +from PIL import Image, ImageTk +import os +import argparse +# sudo apt-get install python3-pil.imagetk + +in_default = r'D:\ML\hentai_ai\dataset_thighs' +out_default = r'D:\ML\hentai_ai\dataset_thighs_cropped' + +parser = argparse.ArgumentParser() +parser.add_argument('-i', '--input', type=str, default=in_default, help="input directory") +parser.add_argument('-o', '--output', type=str, default=out_default, help="output directory") + + +class AutoScrollbar(ttk.Scrollbar): + def set(self, lo, hi): + self.grid_remove() + + def pack(self, **kw): + raise tk.TclError('Cannot use pack with this widget') + + def place(self, **kw): + raise tk.TclError('Cannot use place with this widget') + + +def load_paths(in_path, out_path): + in_list = [] + out_list = [] + for fname in os.listdir(in_path): + in_list.append(os.path.join(in_path, fname)) + out_list.append(os.path.join(out_path, fname.split('.')[0] + "-crop.png")) + return in_list, out_list + + +class ZoomAdvanced(ttk.Frame): + # Advanced zoom of the image + def __init__(self, mainframe, input, output): + # Initialize the main Frame + ttk.Frame.__init__(self, master=mainframe) + # Vertical and horizontal scrollbars for canvas + vbar = AutoScrollbar(self.master, orient='vertical') + hbar = AutoScrollbar(self.master, orient='horizontal') + vbar.grid(row=0, column=1, sticky='ns') + hbar.grid(row=1, column=0, sticky='we') + # Create canvas and put image on it + self.canvas = tk.Canvas(self.master, highlightthickness=0, + xscrollcommand=hbar.set, yscrollcommand=vbar.set) + self.canvas.grid(row=0, column=0, sticky='nswe') + self.canvas.update() # wait till canvas is created + vbar.configure(command=self.scroll_y) # bind scrollbars to the canvas + hbar.configure(command=self.scroll_x) + # Make the canvas expandable + self.master.rowconfigure(0, weight=1) + self.master.columnconfigure(0, weight=1) + # Bind events to the Canvas + self.canvas.bind('', self.show_image) # canvas is resized + self.canvas.bind('', self.move_from) + self.canvas.bind('', self.move_to) + self.canvas.bind('', self.wheel) # with Windows and MacOS, but not Linux + self.canvas.bind('', self.wheel) # only with Linux, wheel scroll down + self.canvas.bind('', self.wheel) # only with Linux, wheel scroll up + self.canvas.bind_all('', self.save_img) + + self.in_paths, self.out_paths = load_paths(input, output) + self.counter = 0 + self.image = None + self.destination = None + self.width = 0 + self.height = 0 + self.imscale = 1.0 + self.delta = 1.1 + self.container = None + self.img = None + # open first image + self.load_img() + self.show_image() + + def load_img(self): + while os.path.exists(self.out_paths[self.counter]): + self.counter += 1 + self.image = Image.open(self.in_paths[self.counter]) + self.destination = self.out_paths[self.counter] + print(str(os.path.basename(self.in_paths[self.counter]))) + self.master.title(os.path.basename(self.in_paths[self.counter])) + self.width, self.height = self.image.size + self.imscale = 1.0 # scale for the canvas image + # Put image into container rectangle and use it to set proper coordinates to the image + self.container = self.canvas.create_rectangle(0, 0, self.width, self.height, width=0) + self.img = None + + def save_img(self, event): + print("Saving cropped image...") + self.img.save(self.destination) + self.counter += 1 + if self.counter < len(self.in_paths): + print("Loading new image...") + self.load_img() + self.show_image() + else: + print("Exiting...") + self.master.destroy() + + def scroll_y(self, *args, **kwargs): + # Scroll canvas vertically and redraw the image + self.canvas.yview(*args, **kwargs) # scroll vertically + self.show_image() # redraw the image + + def scroll_x(self, *args, **kwargs): + # Scroll canvas horizontally and redraw the image + self.canvas.xview(*args, **kwargs) # scroll horizontally + self.show_image() # redraw the image + + def move_from(self, event): + # Remember previous coordinates for scrolling with the mouse + self.canvas.scan_mark(event.x, event.y) + + def move_to(self, event): + # Drag (move) canvas to the new position + self.canvas.scan_dragto(event.x, event.y, gain=1) + self.show_image() # redraw the image + + def wheel(self, event): + # Zoom with mouse wheel + x = self.canvas.canvasx(event.x) + y = self.canvas.canvasy(event.y) + bbox = self.canvas.bbox(self.container) # get image area + if bbox[0] < x < bbox[2] and bbox[1] < y < bbox[3]: + pass # Ok! Inside the image + else: + return # zoom only inside image area + scale = 1.0 + # Respond to Linux (event.num) or Windows (event.delta) wheel event + if event.num == 5 or event.delta == -120: # scroll down + i = min(self.width, self.height) + if int(i * self.imscale) < 30: + return # image is less than 30 pixels + self.imscale /= self.delta + scale /= self.delta + if event.num == 4 or event.delta == 120: # scroll up + i = min(self.canvas.winfo_width(), self.canvas.winfo_height()) + if i < self.imscale: + return # 1 pixel is bigger than the visible area + self.imscale *= self.delta + scale *= self.delta + self.canvas.scale('all', x, y, scale, scale) # rescale all canvas objects + self.show_image() + + def show_image(self, event=None): + # Show image on the Canvas + bbox1 = self.canvas.bbox(self.container) # get image area + # Remove 1 pixel shift at the sides of the bbox1 + bbox1 = (bbox1[0] + 1, bbox1[1] + 1, bbox1[2] - 1, bbox1[3] - 1) + bbox2 = (self.canvas.canvasx(0), # get visible area of the canvas + self.canvas.canvasy(0), + self.canvas.canvasx(self.canvas.winfo_width()), + self.canvas.canvasy(self.canvas.winfo_height())) + bbox = [min(bbox1[0], bbox2[0]), min(bbox1[1], bbox2[1]), # get scroll region box + max(bbox1[2], bbox2[2]), max(bbox1[3], bbox2[3])] + if bbox[0] == bbox2[0] and bbox[2] == bbox2[2]: # whole image in the visible area + bbox[0] = bbox1[0] + bbox[2] = bbox1[2] + if bbox[1] == bbox2[1] and bbox[3] == bbox2[3]: # whole image in the visible area + bbox[1] = bbox1[1] + bbox[3] = bbox1[3] + self.canvas.configure(scrollregion=bbox) # set scroll region + x1 = max(bbox2[0] - bbox1[0], 0) # get coordinates (x1,y1,x2,y2) of the image tile + y1 = max(bbox2[1] - bbox1[1], 0) + x2 = min(bbox2[2], bbox1[2]) - bbox1[0] + y2 = min(bbox2[3], bbox1[3]) - bbox1[1] + if int(x2 - x1) > 0 and int(y2 - y1) > 0: # show image if it in the visible area + x = min(int(x2 / self.imscale), self.width) # sometimes it is larger on 1 pixel... + y = min(int(y2 / self.imscale), self.height) # ...and sometimes not + image = self.image.crop((int(x1 / self.imscale), int(y1 / self.imscale), x, y)) + imagetk = ImageTk.PhotoImage(image.resize((int(x2 - x1), int(y2 - y1)))) + imageid = self.canvas.create_image(max(bbox2[0], bbox1[0]), max(bbox2[1], bbox1[1]), + anchor='nw', image=imagetk) + self.canvas.lower(imageid) # set image into background + self.canvas.imagetk = imagetk # keep an extra reference to prevent garbage-collection + self.img = image.resize((int(x2 - x1), int(y2 - y1))) + + +root = tk.Tk() +root.geometry("500x500") +root.resizable(width=False, height=False) +args = parser.parse_args() +app = ZoomAdvanced(root, args.input, args.output) +root.mainloop()