diff --git a/README.md b/README.md
index 3f5c1df..607fb64 100644
--- a/README.md
+++ b/README.md
@@ -1,41 +1,39 @@
# DeepCreamPy
-*Decensoring Hentai with Deep Neural Networks.*
+*Plausibly Reconstruct Anime-style Artworks with Deep Neural Networks.*
[](https://github.com/Deepshift/DeepCreamPy/releases/latest)
[](https://github.com/Deepshift/DeepCreamPy/releases/latest)
[](https://github.com/Deepshift/DeepCreamPy/releases)
[](https://github.com/Deepshift/DeepCreamPy/issues)
-A deep learning-based tool to automatically replace censored artwork in hentai with plausible reconstructions.
+A deep learning-based tool to automatically replace parts of artworks with plausible reconstructions.
-Before DeepCreamPy can be used, the user must color censored regions in their hentai green with an image editing program (e.g. GIMP, Photoshop). DeepCreamPy takes the green colored images as input, and a neural network automatically fills in the censored regions.
+Before using DeepCreamPy, the user must mark regions in the artwork using green color with an image editing program (e.g., GIMP, Photoshop). DeepCreamPy takes the images with green colored regions as input, and a neural network automatically fills in the highlighted regions.
You can download the latest release for Windows 64-bit [here](https://github.com/Deepshift/DeepCreamPy/releases/latest).
For users interested in compiling DeepCreamPy themselves, DeepCreamPy can run on Windows, Mac, and Linux.
-Please before you open a new issue check [closed issues](https://github.com/Deepshift/DeepCreamPy/issues?q=is%3Aissue+is%3Aclosed) and check the [table of contents](https://github.com/Deepshift/DeepCreamPy#table-of-contents).
+Before opening a new issue, please check [closed issues](https://github.com/Deepshift/DeepCreamPy/issues?q=is%3Aissue+is%3Aclosed) and refer to the [table of contents](https://github.com/Deepshift/DeepCreamPy#table-of-contents).
## Features
-- Decensoring images of any size
-- Decensoring of ANY shaped censor (e.g. black lines, pink hearts, etc.)
-- Decensoring of mosaic decensors
-- Limited support for decensoring black and white/monochrome images
-- Generate multiple variations of decensors from the same image
+- Reconstructing images of any size
+- Reconstruction of ANY shaped censor (e.g. black lines, pink hearts, etc.)
+- Decensoring of mosaic censors
+- Limited support for black-and-white/monochrome images
+- Generate multiple variations of reconstructions from the same image
## Limitations
-The decensorship is for color hentai images that have minor to moderate censorship of the human reproductive organs. If an organ is completely censored out, decensoring will be ineffective.
+The reconstruction is mainly for anime-style human-like figures that have minor to moderate redactions. If an organ (e.g. arms, legs) is completely deleted, reconstruction will fail.
It does NOT work with:
-- Hentai with screentones (e.g. printed hentai)
-- Real life pornographic material
-- Censorship of nipples
-- Censorship of lower orifice of the alimentary canal
-- Animated gifs/videos
+- Screentones (e.g. printed material)
+- Real life photos
+- Animated gifs and videos
## Table of Contents
Setup:
@@ -43,22 +41,24 @@ Setup:
* [Running code yourself](docs/INSTALLATION.md)
Usage:
-* [Decensoring tutorial](docs/USAGE.md)
+* [Tutorial](docs/USAGE.md)
* [Troubleshooting for installing](docs/TROUBLESHOOTING.md)
-* [Troubleshooting for poor quality decensors](docs/TROUBLESHOOTING_DECENSORS.md)
+* [Troubleshooting for poor quality outputs](docs/TROUBLESHOOTING_DECENSORS.md)
Miscellaneous:
* [FAQ](docs/FAQ.md)
## To do
-- Resolve all Tensorflow compatibility problems
-- Finish the user interface
-- Add error log
+- Moving to PyTorch or newer versions of TensorFlow
+- Improving UI
+- Error logging
## Contributions
-If you want to make a pull request to DeepCreamPy, you must first sign our [Contributor License Agreement](https://github.com/deeppomf/contributing/blob/master/sign-cla.md#sign-the-cla) (the "CLA"). Then I can accept your pull requests.
+We welcome contributions as long as they comply with the [GNU Affero General Public License v3.0](LICENSE.md). Be advised of GitHub's [inbound=outbound](https://docs.github.com/en/site-policy/github-terms/github-terms-of-service#6-contributions-under-repository-license) rule.
-Special thanks to ccppoo, IAmTheRedSpy, 0xb8, deniszh, Smethan, harjitmoe, itsVale, StartleStars, and SoftArmpit for their contributions!
+Previously, contributors had to sign a [Contributor License Agreement](https://github.com/deeppomf/contributing/blob/master/sign-cla.md#sign-the-cla) (the "CLA"). This requirement is currently no longer in place.
+
+This project was initially created by **deeppomf** and all credit goes to them. Special thanks to ccppoo, IAmTheRedSpy, 0xb8, deniszh, Smethan, harjitmoe, itsVale, StartleStars, SoftArmpit and everyone else for their contributions!
## License
Source code and official releases/binaries are distributed under the [GNU Affero General Public License v3.0](LICENSE.md).
diff --git a/cleardcp.py b/cleardcp.py
new file mode 100644
index 0000000..b52ede4
--- /dev/null
+++ b/cleardcp.py
@@ -0,0 +1,30 @@
+# cleardcp.py
+# This script removes all files from `decensor_input', `decensor_input_original' and `decensor_output' directories.
+# Originally written by github.com/DioKyrie
+#
+
+import os
+from typing import Union
+
+def clear_folder(folder_path: Union[str, bytes]) -> None:
+ try:
+ for filename in os.listdir(folder_path):
+ file_path = os.path.join(folder_path, filename)
+ if os.path.isfile(file_path):
+ os.remove(file_path)
+ elif os.path.isdir(file_path):
+ clear_folder(file_path)
+ print(f"Content of '{folder_path}' cleared successfully.")
+ except Exception as e:
+ print(f"Error clearing content of '{folder_path}': {e}")
+
+
+def main():
+ folders_to_clear = ["decensor_input", "decensor_input_original", "decensor_output"]
+ for folder in folders_to_clear:
+ folder_path = os.path.join(os.path.dirname(__file__), folder)
+ clear_folder(folder_path)
+
+
+if __name__ == "__main__":
+ main()
diff --git a/config.py b/config.py
index 7e10789..2bfe16b 100755
--- a/config.py
+++ b/config.py
@@ -24,6 +24,7 @@ def get_args():
parser.add_argument('--decensor_input_path', default='./decensor_input/', help='input images with censored regions colored green to be decensored by decensor.py path')
parser.add_argument('--decensor_input_original_path', default='./decensor_input_original/', help='input images with no modifications to be decensored by decensor.py path')
parser.add_argument('--decensor_output_path', default='./decensor_output/', help='output images generated from running decensor.py path')
+ parser.add_argument('--clean-up-input-dirs', dest='clean_up_input_dirs', action='store_true', default=False, help='whether to delete all image files in the input directories when decensoring is done')
#Decensor settings
parser.add_argument('--mask_color_red', default=0, help='red channel of mask color in decensoring')
diff --git a/decensor.py b/decensor.py
index 50c1dca..7699f76 100755
--- a/decensor.py
+++ b/decensor.py
@@ -49,6 +49,7 @@ def __init__(self, parentThread = None, text_edit = None, text_cursor = None, ui
self.decensor_input_path = args.decensor_input_path
self.decensor_input_original_path = args.decensor_input_original_path
self.decensor_output_path = args.decensor_output_path
+ self.clean_up_input_dirs = args.clean_up_input_dirs
self.signals = IgnoreAll() # Signals class will be given by progressWindow
@@ -76,11 +77,15 @@ def run(self):
elif self.warm_up:
print("elif not self.warm_up:")
self.decensor_all_images_in_folder()
+ self.do_post_jobs()
def stop(self):
# in case of stopping decensor, terminate not to run if self while MainWindow is closed
self.terminate()
+ def set_clean_up_input_dirs(self, value):
+ self.clean_up_input_dirs = value
+
def find_mask(self, colored):
# self.signals.update_progress_LABEL.emit("find_mask()", "finding mask...")
mask = np.ones(colored.shape, np.uint8)
@@ -373,6 +378,36 @@ def decensor_image_variation(self, ori, colored, variant_number, file_name):
print("Decensored image. Returning it.")
return output_img
+ def clean_input_directories(self):
+ """Removes .png, .jpg, and .jpeg files from input directories."""
+
+ allowed_extensions = {".png", ".jpg", ".jpeg"}
+
+ self.signals.insertText_progressCursor.emit("Cleaning {}...".format(self.decensor_input_path))
+
+ for file_name in os.listdir(self.decensor_input_path):
+ file_path = os.path.join(self.decensor_input_path, file_name)
+ if os.path.isfile(file_path) and os.path.splitext(file_name)[1].lower() in allowed_extensions:
+ os.remove(file_path)
+
+ if self.is_mosaic:
+ self.signals.insertText_progressCursor.emit(
+ "Cleaning {}...".format(self.decensor_input_original_path)
+ )
+ for file_name in os.listdir(self.decensor_input_original_path):
+ file_path = os.path.join(self.decensor_input_original_path,
+ file_name)
+ if os.path.isfile(file_path) and os.path.splitext(file_name)[1].lower() in allowed_extensions:
+ os.remove(file_path)
+
+ self.signals.insertText_progressCursor.emit("Done!")
+
+ def do_post_jobs(self):
+ if self.clean_up_input_dirs:
+ self.clean_input_directories()
+
+
+
if __name__ == '__main__':
decensor = Decensor()
decensor.decensor_all_images_in_folder()
diff --git a/docs/INSTALLATION_BINARY.md b/docs/INSTALLATION_BINARY.md
index 15dcd94..3f10037 100644
--- a/docs/INSTALLATION_BINARY.md
+++ b/docs/INSTALLATION_BINARY.md
@@ -1,6 +1,6 @@
# Installing the Binary
-1. If you haven't already, download the latest release [here](https://github.com/gguilt/DeepCreamPy/releases/latest) or find all previous releases [here](https://github.com/gguilt/DeepCreamPy/releases).
+1. If you haven't already, download the latest release [here](https://github.com/Deepshift/DeepCreamPy/releases/latest) or find all previous releases [here](https://github.com/Deepshift/DeepCreamPy/releases).
2. Install Visual C++ Redistributable for Visual Studio 2015 Update 3 from [here](https://www.microsoft.com/en-us/download/details.aspx?id=53587).
diff --git a/main.py b/main.py
index dc2419d..11697d3 100644
--- a/main.py
+++ b/main.py
@@ -5,7 +5,7 @@
# The greater the number of variations, the longer decensoring process will be.
import sys, time
-from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QGridLayout, QGroupBox, QDesktopWidget, QApplication
+from PySide2.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QGridLayout, QGroupBox, QDesktopWidget, QApplication, QCheckBox
from PySide2.QtWidgets import QAction, qApp, QApplication, QMessageBox, QRadioButton, QPushButton, QTextEdit, QLabel
from PySide2.QtWidgets import QSizePolicy,QMainWindow, QStatusBar, QProgressBar
from PySide2.QtCore import Qt, QObject
@@ -23,8 +23,8 @@ def __init__(self):
super().__init__()
self.signals = Signals()
self.initUI()
- self.setSignals()
self.decensor = Decensor(self)
+ self.setSignals()
self.load_model()
def initUI(self):
@@ -94,14 +94,19 @@ def initUI(self):
self.statusBar.addWidget(self.statusLabel, 1)
self.statusBar.addWidget(self.progressBar, 2)
+ self.cleanInputDirectoryCheckbox = QCheckBox(
+ 'Clean up input directories after decensoring'
+ )
+
#put all groups into grid
# addWidget(row, column, rowSpan, columnSpan)
grid_layout.addWidget(self.tutorialLabel, 0, 0, 1, 2)
grid_layout.addWidget(self.censorTypeGroupBox, 1, 0, 1, 1)
grid_layout.addWidget(self.variationsGroupBox, 1, 1, 1, 1)
- grid_layout.addWidget(self.decensorButton, 2, 0, 1, 2)
- grid_layout.addWidget(self.progressMessage, 3, 0, 1, 2)
- grid_layout.addWidget(self.statusBar, 4, 0, 1, 2)
+ grid_layout.addWidget(self.cleanInputDirectoryCheckbox, 2, 0, 1, 2)
+ grid_layout.addWidget(self.decensorButton, 3, 0, 1, 2)
+ grid_layout.addWidget(self.progressMessage, 4, 0, 1, 2)
+ grid_layout.addWidget(self.statusBar, 5, 0, 1, 2)
#window size settings
self.resize(900, 600)
@@ -128,6 +133,9 @@ def setSignals(self):
self.signals.insertText_progressCursor.connect(self.progressMessage.append)
self.signals.clear_progressMessage.connect(self.progressMessage.clear)
self.signals.appendText_progressMessage.connect(self.progressMessage.append)
+ self.signals.update_clean_up_input_dirs_flag.connect(
+ self.decensor.set_clean_up_input_dirs
+ )
def decensorClicked(self):
self.decensorButton.setEnabled(False)
@@ -158,6 +166,9 @@ def decensorClicked(self):
variations = int(vb.text())
self.decensor.variations = variations
+ self.signals.update_clean_up_input_dirs_flag.emit(
+ self.cleanInputDirectoryCheckbox.isChecked()
+ )
self.decensorButton.setEnabled(False)
self.decensor.start()
diff --git a/requirements-gpu.txt b/requirements-gpu.txt
index 57ad15b..a1fd815 100644
--- a/requirements-gpu.txt
+++ b/requirements-gpu.txt
@@ -8,15 +8,15 @@ Keras-Applications==1.0.8
Keras-Preprocessing==1.1.0
Markdown==3.1.1
numpy==1.17.0
-opencv-python==4.1.0.25
+opencv-python==4.3.0.38
Pillow==6.2.2
protobuf==3.9.1
PySide2==5.13.0
scipy==1.3.0
shiboken2==5.13.0
six==1.12.0
-tensorboard==1.14.0
-tensorflow-estimator==1.14.0
+tensorboard==1.15.0
+tensorflow-estimator==1.15.1
tensorflow-gpu==1.15.2
termcolor==1.1.0
Werkzeug==0.15.5
diff --git a/signals.py b/signals.py
index 55cbda7..ca9e5d4 100644
--- a/signals.py
+++ b/signals.py
@@ -40,3 +40,5 @@ class Signals(QtCore.QObject):
# str : value to change
# direct connect to self.progressMessage.append(str)
appendText_progressMessage = QtCore.Signal(str)
+
+ update_clean_up_input_dirs_flag = QtCore.Signal(bool)