Code and demo dataset added
authorProject Hentai AI <hentai-ai@hentai-ai.org>
Wed, 2 Feb 2022 12:36:46 +0000 (12:36 +0000)
committerProject Hentai AI <hentai-ai@hentai-ai.org>
Wed, 2 Feb 2022 12:36:46 +0000 (12:36 +0000)
22 files changed:
demo_input_dir/thighs-0000.png [new file with mode: 0644]
demo_input_dir/thighs-0001.png [new file with mode: 0644]
demo_input_dir/thighs-0002.png [new file with mode: 0644]
demo_input_dir/thighs-0003.png [new file with mode: 0644]
demo_input_dir/thighs-0004.png [new file with mode: 0644]
demo_input_dir/thighs-0005.png [new file with mode: 0644]
demo_input_dir/thighs-0006.png [new file with mode: 0644]
demo_input_dir/thighs-0007.png [new file with mode: 0644]
demo_input_dir/thighs-0008.png [new file with mode: 0644]
demo_input_dir/thighs-0009.png [new file with mode: 0644]
demo_input_dir/thighs-0010.png [new file with mode: 0644]
demo_input_dir/thighs-0011.png [new file with mode: 0644]
demo_input_dir/thighs-0012.png [new file with mode: 0644]
demo_input_dir/thighs-0013.png [new file with mode: 0644]
demo_input_dir/thighs-0014.png [new file with mode: 0644]
demo_input_dir/thighs-0015.png [new file with mode: 0644]
demo_input_dir/thighs-0016.png [new file with mode: 0644]
demo_input_dir/thighs-0017.png [new file with mode: 0644]
demo_input_dir/thighs-0018.png [new file with mode: 0644]
demo_input_dir/thighs-0019.png [new file with mode: 0644]
demo_input_dir/thighs-0020.png [new file with mode: 0644]
hentai-cropper.py [new file with mode: 0644]

diff --git a/demo_input_dir/thighs-0000.png b/demo_input_dir/thighs-0000.png
new file mode 100644 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
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 (file)
index 0000000..ae21d4a
--- /dev/null
@@ -0,0 +1,196 @@
+# This application is based on:\r
+# https://github.com/foobar167/junkyard/blob/master/zoom_advanced.py\r
+\r
+# -*- coding: utf-8 -*-\r
+# Advanced zoom example. Like in Google Maps.\r
+# It zooms only a tile, but not the whole image. So the zoomed tile occupies\r
+# constant memory and not cram it with a huge resized image for the large zooms.\r
+\r
+import tkinter as tk\r
+from tkinter import ttk\r
+from PIL import Image, ImageTk\r
+import os\r
+import argparse\r
+# sudo apt-get install python3-pil.imagetk\r
+\r
+in_default = r'D:\ML\hentai_ai\dataset_thighs'\r
+out_default = r'D:\ML\hentai_ai\dataset_thighs_cropped'\r
+\r
+parser = argparse.ArgumentParser()\r
+parser.add_argument('-i', '--input', type=str, default=in_default, help="input directory")\r
+parser.add_argument('-o', '--output', type=str, default=out_default, help="output directory")\r
+\r
+\r
+class AutoScrollbar(ttk.Scrollbar):\r
+    def set(self, lo, hi):\r
+        self.grid_remove()\r
+\r
+    def pack(self, **kw):\r
+        raise tk.TclError('Cannot use pack with this widget')\r
+\r
+    def place(self, **kw):\r
+        raise tk.TclError('Cannot use place with this widget')\r
+\r
+\r
+def load_paths(in_path, out_path):\r
+    in_list = []\r
+    out_list = []\r
+    for fname in os.listdir(in_path):\r
+        in_list.append(os.path.join(in_path, fname))\r
+        out_list.append(os.path.join(out_path, fname.split('.')[0] + "-crop.png"))\r
+    return in_list, out_list\r
+\r
+\r
+class ZoomAdvanced(ttk.Frame):\r
+    # Advanced zoom of the image\r
+    def __init__(self, mainframe, input, output):\r
+        # Initialize the main Frame\r
+        ttk.Frame.__init__(self, master=mainframe)\r
+        # Vertical and horizontal scrollbars for canvas\r
+        vbar = AutoScrollbar(self.master, orient='vertical')\r
+        hbar = AutoScrollbar(self.master, orient='horizontal')\r
+        vbar.grid(row=0, column=1, sticky='ns')\r
+        hbar.grid(row=1, column=0, sticky='we')\r
+        # Create canvas and put image on it\r
+        self.canvas = tk.Canvas(self.master, highlightthickness=0,\r
+                                xscrollcommand=hbar.set, yscrollcommand=vbar.set)\r
+        self.canvas.grid(row=0, column=0, sticky='nswe')\r
+        self.canvas.update()  # wait till canvas is created\r
+        vbar.configure(command=self.scroll_y)  # bind scrollbars to the canvas\r
+        hbar.configure(command=self.scroll_x)\r
+        # Make the canvas expandable\r
+        self.master.rowconfigure(0, weight=1)\r
+        self.master.columnconfigure(0, weight=1)\r
+        # Bind events to the Canvas\r
+        self.canvas.bind('<Configure>', self.show_image)  # canvas is resized\r
+        self.canvas.bind('<ButtonPress-1>', self.move_from)\r
+        self.canvas.bind('<B1-Motion>',     self.move_to)\r
+        self.canvas.bind('<MouseWheel>', self.wheel)  # with Windows and MacOS, but not Linux\r
+        self.canvas.bind('<Button-5>',   self.wheel)  # only with Linux, wheel scroll down\r
+        self.canvas.bind('<Button-4>',   self.wheel)  # only with Linux, wheel scroll up\r
+        self.canvas.bind_all('<Return>', self.save_img)\r
+\r
+        self.in_paths, self.out_paths = load_paths(input, output)\r
+        self.counter = 0\r
+        self.image = None\r
+        self.destination = None\r
+        self.width = 0\r
+        self.height = 0\r
+        self.imscale = 1.0\r
+        self.delta = 1.1\r
+        self.container = None\r
+        self.img = None\r
+        # open first image\r
+        self.load_img()\r
+        self.show_image()\r
+\r
+    def load_img(self):\r
+        while os.path.exists(self.out_paths[self.counter]):\r
+            self.counter += 1\r
+        self.image = Image.open(self.in_paths[self.counter])\r
+        self.destination = self.out_paths[self.counter]\r
+        print(str(os.path.basename(self.in_paths[self.counter])))\r
+        self.master.title(os.path.basename(self.in_paths[self.counter]))\r
+        self.width, self.height = self.image.size\r
+        self.imscale = 1.0  # scale for the canvas image\r
+        # Put image into container rectangle and use it to set proper coordinates to the image\r
+        self.container = self.canvas.create_rectangle(0, 0, self.width, self.height, width=0)\r
+        self.img = None\r
+\r
+    def save_img(self, event):\r
+        print("Saving cropped image...")\r
+        self.img.save(self.destination)\r
+        self.counter += 1\r
+        if self.counter < len(self.in_paths):\r
+            print("Loading new image...")\r
+            self.load_img()\r
+            self.show_image()\r
+        else:\r
+            print("Exiting...")\r
+            self.master.destroy()\r
+\r
+    def scroll_y(self, *args, **kwargs):\r
+        # Scroll canvas vertically and redraw the image\r
+        self.canvas.yview(*args, **kwargs)  # scroll vertically\r
+        self.show_image()  # redraw the image\r
+\r
+    def scroll_x(self, *args, **kwargs):\r
+        # Scroll canvas horizontally and redraw the image\r
+        self.canvas.xview(*args, **kwargs)  # scroll horizontally\r
+        self.show_image()  # redraw the image\r
+\r
+    def move_from(self, event):\r
+        # Remember previous coordinates for scrolling with the mouse\r
+        self.canvas.scan_mark(event.x, event.y)\r
+\r
+    def move_to(self, event):\r
+        # Drag (move) canvas to the new position\r
+        self.canvas.scan_dragto(event.x, event.y, gain=1)\r
+        self.show_image()  # redraw the image\r
+\r
+    def wheel(self, event):\r
+        # Zoom with mouse wheel\r
+        x = self.canvas.canvasx(event.x)\r
+        y = self.canvas.canvasy(event.y)\r
+        bbox = self.canvas.bbox(self.container)  # get image area\r
+        if bbox[0] < x < bbox[2] and bbox[1] < y < bbox[3]:\r
+            pass  # Ok! Inside the image\r
+        else:\r
+            return  # zoom only inside image area\r
+        scale = 1.0\r
+        # Respond to Linux (event.num) or Windows (event.delta) wheel event\r
+        if event.num == 5 or event.delta == -120:  # scroll down\r
+            i = min(self.width, self.height)\r
+            if int(i * self.imscale) < 30:\r
+                return  # image is less than 30 pixels\r
+            self.imscale /= self.delta\r
+            scale /= self.delta\r
+        if event.num == 4 or event.delta == 120:  # scroll up\r
+            i = min(self.canvas.winfo_width(), self.canvas.winfo_height())\r
+            if i < self.imscale:\r
+                return  # 1 pixel is bigger than the visible area\r
+            self.imscale *= self.delta\r
+            scale *= self.delta\r
+        self.canvas.scale('all', x, y, scale, scale)  # rescale all canvas objects\r
+        self.show_image()\r
+\r
+    def show_image(self, event=None):\r
+        # Show image on the Canvas\r
+        bbox1 = self.canvas.bbox(self.container)  # get image area\r
+        # Remove 1 pixel shift at the sides of the bbox1\r
+        bbox1 = (bbox1[0] + 1, bbox1[1] + 1, bbox1[2] - 1, bbox1[3] - 1)\r
+        bbox2 = (self.canvas.canvasx(0),  # get visible area of the canvas\r
+                 self.canvas.canvasy(0),\r
+                 self.canvas.canvasx(self.canvas.winfo_width()),\r
+                 self.canvas.canvasy(self.canvas.winfo_height()))\r
+        bbox = [min(bbox1[0], bbox2[0]), min(bbox1[1], bbox2[1]),  # get scroll region box\r
+                max(bbox1[2], bbox2[2]), max(bbox1[3], bbox2[3])]\r
+        if bbox[0] == bbox2[0] and bbox[2] == bbox2[2]:  # whole image in the visible area\r
+            bbox[0] = bbox1[0]\r
+            bbox[2] = bbox1[2]\r
+        if bbox[1] == bbox2[1] and bbox[3] == bbox2[3]:  # whole image in the visible area\r
+            bbox[1] = bbox1[1]\r
+            bbox[3] = bbox1[3]\r
+        self.canvas.configure(scrollregion=bbox)  # set scroll region\r
+        x1 = max(bbox2[0] - bbox1[0], 0)  # get coordinates (x1,y1,x2,y2) of the image tile\r
+        y1 = max(bbox2[1] - bbox1[1], 0)\r
+        x2 = min(bbox2[2], bbox1[2]) - bbox1[0]\r
+        y2 = min(bbox2[3], bbox1[3]) - bbox1[1]\r
+        if int(x2 - x1) > 0 and int(y2 - y1) > 0:  # show image if it in the visible area\r
+            x = min(int(x2 / self.imscale), self.width)   # sometimes it is larger on 1 pixel...\r
+            y = min(int(y2 / self.imscale), self.height)  # ...and sometimes not\r
+            image = self.image.crop((int(x1 / self.imscale), int(y1 / self.imscale), x, y))\r
+            imagetk = ImageTk.PhotoImage(image.resize((int(x2 - x1), int(y2 - y1))))\r
+            imageid = self.canvas.create_image(max(bbox2[0], bbox1[0]), max(bbox2[1], bbox1[1]),\r
+                                               anchor='nw', image=imagetk)\r
+            self.canvas.lower(imageid)  # set image into background\r
+            self.canvas.imagetk = imagetk  # keep an extra reference to prevent garbage-collection\r
+            self.img = image.resize((int(x2 - x1), int(y2 - y1)))\r
+\r
+\r
+root = tk.Tk()\r
+root.geometry("500x500")\r
+root.resizable(width=False, height=False)\r
+args = parser.parse_args()\r
+app = ZoomAdvanced(root, args.input, args.output)\r
+root.mainloop()\r