Spooke commited on
Commit
ac6ff10
1 Parent(s): 3d5e07d

Upload 27 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,7 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ cm.lib filter=lfs diff=lfs merge=lfs -text
37
+ example1.png filter=lfs diff=lfs merge=lfs -text
38
+ mm.lib filter=lfs diff=lfs merge=lfs -text
39
+ mn.lib filter=lfs diff=lfs merge=lfs -text
app.py ADDED
@@ -0,0 +1,197 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from run import process
2
+ import time
3
+ import subprocess
4
+ import os
5
+ import argparse
6
+ import cv2
7
+ import sys
8
+ from PIL import Image
9
+ import torch
10
+ import gradio as gr
11
+
12
+ TESTdevice = "cpu"
13
+ index = 1
14
+
15
+ def mainTest(inputpath, outpath):
16
+ watermark = deep_nude_process(inputpath)
17
+ watermark1 = cv2.cvtColor(watermark, cv2.COLOR_BGRA2RGBA)
18
+ return watermark1
19
+
20
+ def deep_nude_process(inputpath):
21
+ dress = cv2.imread(inputpath)
22
+ h = dress.shape[0]
23
+ w = dress.shape[1]
24
+ dress = cv2.resize(dress, (512, 512), interpolation=cv2.INTER_CUBIC)
25
+ watermark = process(dress)
26
+ watermark = cv2.resize(watermark, (w, h), interpolation=cv2.INTER_CUBIC)
27
+ return watermark
28
+
29
+ def inference(img):
30
+ global index
31
+ bgra = cv2.cvtColor(img, cv2.COLOR_RGBA2BGRA)
32
+ inputpath = f"input_{index}.jpg"
33
+ cv2.imwrite(inputpath, bgra)
34
+
35
+ outputpath = f"out_{index}.jpg"
36
+ index += 1
37
+ print(time.strftime("START!!!!!!!!! %Y-%m-%d %H:%M:%S", time.localtime()))
38
+ output = mainTest(inputpath, outputpath)
39
+ print(time.strftime("Finish!!!!!!!!! %Y-%m-%d %H:%M:%S", time.localtime()))
40
+ return output
41
+
42
+ def load_image_from_file(file_path, new_height=None):
43
+ """
44
+ Load an image from a file and optionally resize it while maintaining the aspect ratio.
45
+
46
+ Args:
47
+ file_path (str): The path to the image file.
48
+ new_height (int, optional): The new height for the image. If None, the image is not resized.
49
+
50
+ Returns:
51
+ Image: The loaded (and optionally resized) image.
52
+ """
53
+ try:
54
+ img = Image.open(file_path)
55
+
56
+ if (new_height is not None):
57
+ # Calculate new width to maintain aspect ratio
58
+ aspect_ratio = img.width / img.height
59
+ new_width = int(new_height * aspect_ratio)
60
+
61
+ # Resize the image
62
+ img = img.resize((new_width, new_height), Image.LANCZOS)
63
+
64
+ return img
65
+ except FileNotFoundError:
66
+ print(f"File not found: {file_path}")
67
+ return None
68
+ except Image.UnidentifiedImageError:
69
+ print(f"Cannot identify image file: {file_path}")
70
+ return None
71
+ except Exception as e:
72
+ print(f"Error loading image from file: {e}")
73
+ return None
74
+
75
+ title = "Undress AI"
76
+ description = "⛔ Input photos of people, similar to the test picture at the bottom, and undress pictures will be produced. You may have to wait 30 seconds for a picture. 🔞 Do not upload personal photos 🔞 There is a queue system. According to the logic of first come, first served, only one picture will be made at a time. Must be able to at least see the outline of a human body ⛔"
77
+
78
+ examples = [
79
+ [load_image_from_file('example9.webp')],
80
+ [load_image_from_file('example2.png')],
81
+ [load_image_from_file('example1.png')],
82
+ [load_image_from_file('example5.webp')],
83
+ [load_image_from_file('example6.webp')],
84
+ [load_image_from_file('example8.webp')],
85
+ ]
86
+
87
+ js='''
88
+ <script>
89
+ window.cur_process_step = "";
90
+ function getEnvInfo() {
91
+ const result = {};
92
+ // Get URL parameters
93
+ const urlParams = new URLSearchParams(window.location.search);
94
+ for (const [key, value] of urlParams) {
95
+ result[key] = value;
96
+ }
97
+ // Get current domain and convert to lowercase
98
+ result["__domain"] = window.location.hostname.toLowerCase();
99
+ // Get iframe parent domain, if any, and convert to lowercase
100
+ try {
101
+ if (window.self !== window.top) {
102
+ result["__iframe_domain"] = document.referrer
103
+ ? new URL(document.referrer).hostname.toLowerCase()
104
+ : "unable to get iframe parent domain";
105
+ }else{
106
+ result["__iframe_domain"] = "";
107
+ }
108
+ } catch (e) {
109
+ result["__iframe_domain"] = "unable to access iframe parent domain";
110
+ }
111
+ return result;
112
+ }
113
+ function isValidEnv(){
114
+ envInfo = getEnvInfo();
115
+ return envInfo["e"] == "1" ||
116
+ envInfo["__domain"].indexOf("nsfwais.io") != -1 ||
117
+ envInfo["__iframe_domain"].indexOf("nsfwais.io") != -1 ||
118
+ envInfo["__domain"].indexOf("127.0.0.1") != -1 ||
119
+ envInfo["__iframe_domain"].indexOf("127.0.0.1") != -1;
120
+ }
121
+ window.postMessageToParent = function(img, event, source, value) {
122
+ // Construct the message object with the provided parameters
123
+ console.log("post start",event, source, value);
124
+ const message = {
125
+ event: event,
126
+ source: source,
127
+ value: value
128
+ };
129
+
130
+ // Post the message to the parent window
131
+ window.parent.postMessage(message, '*');
132
+ console.log("post finish");
133
+ window.cur_process_step = "process";
134
+ return img;
135
+ }
136
+ function uploadImage(image, event, source, value) {
137
+ // Ensure we're in an iframe
138
+ if (window.cur_process_step != "process"){
139
+ return;
140
+ }
141
+ window.cur_process_step = "";
142
+ console.log("uploadImage", image ? image.url : null, event, source, value);
143
+ // Get the first image from the gallery (assuming it's an array)
144
+ let imageUrl = image ? image.url : null;
145
+ if (window.self !== window.top) {
146
+ // Post the message to the parent window
147
+ // Prepare the data to send
148
+ let data = {
149
+ event: event,
150
+ source: source,
151
+ value: imageUrl
152
+ };
153
+ window.parent.postMessage(data, '*');
154
+ } else if (isValidEnv()){
155
+ try{
156
+ sendCustomEventToDataLayer({},event,source,{"image":imageUrl})
157
+ } catch (error) {
158
+ console.error("Error in sendCustomEventToDataLayer:", error);
159
+ }
160
+ }else{
161
+ console.log("Not in an iframe, can't post to parent");
162
+ }
163
+ return;
164
+ }
165
+ window.onDemoLoad = function(x){
166
+ let envInfo = getEnvInfo();
167
+ console.log(envInfo);
168
+ if (isValidEnv()){
169
+ var element = document.getElementById("pitch_desc_html_code");
170
+ if (element) {
171
+ element.parentNode.removeChild(element);
172
+ }
173
+ }
174
+ return "";
175
+ }
176
+ </script>
177
+ '''
178
+
179
+ with gr.Blocks(head=js, theme="Nymbo/Alyx_Theme") as demo:
180
+ width=240
181
+ height=340
182
+
183
+ with gr.Row(equal_height=False):
184
+ with gr.Column(min_width=240): # Adjust scale for proper sizing
185
+ image_input = gr.Image(type="numpy", label="", height=height)
186
+ gr.Examples(examples=examples, inputs=image_input, examples_per_page=10, elem_id="example_img")
187
+ process_button = gr.Button("Run", size="sm")
188
+
189
+ def update_status(img):
190
+ processed_img = inference(img)
191
+ return processed_img
192
+
193
+ image_input.change(fn=lambda x: x, inputs=[image_input], outputs=[gr.State([])], js='''(img) => window.uploadImage(img, "process_finished", "demo_hf_deepnude_gan_card", "")''')
194
+ process_button.click(update_status, inputs=image_input, outputs=image_input, js='''(i) => window.postMessageToParent(i, "process_started", "demo_hf_deepnude_gan_card", "click_nude")''')
195
+ demo.load(fn=lambda x: x, inputs=[gr.State([])], outputs=[gr.State([])], js='''(x) => window.onDemoLoad(x)''')
196
+ demo.queue(max_size=10)
197
+ demo.launch()
checkpoints_not empty.txt ADDED
File without changes
cm.lib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:6fa7ac307a818e99671a9cfa053d23301fe59c38c6337cb994a4b1bce4321856
3
+ size 729785444
example1.png ADDED

Git LFS Details

  • SHA256: 3fc62389e20b9fd17ae2ef67d31a2976b1864c0bbc342889a1a96407e281ea29
  • Pointer size: 132 Bytes
  • Size of remote file: 2.87 MB
example10.webp ADDED
example2.png ADDED
example3.png ADDED
example4.png ADDED
example5.webp ADDED
example6.webp ADDED
example7.jpeg ADDED
example8.webp ADDED
example9.webp ADDED
gan.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from PIL import Image
2
+ import numpy as np
3
+ import cv2
4
+ import torchvision.transforms as transforms
5
+ import torch
6
+ import io
7
+ import os
8
+ import functools
9
+
10
+ class DataLoader():
11
+
12
+ def __init__(self, opt, cv_img):
13
+ super(DataLoader, self).__init__()
14
+
15
+ self.dataset = Dataset()
16
+ self.dataset.initialize(opt, cv_img)
17
+
18
+ self.dataloader = torch.utils.data.DataLoader(
19
+ self.dataset,
20
+ batch_size=opt.batchSize,
21
+ shuffle=not opt.serial_batches,
22
+ num_workers=int(opt.nThreads))
23
+
24
+ def load_data(self):
25
+ return self.dataloader
26
+
27
+ def __len__(self):
28
+ return 1
29
+
30
+ class Dataset(torch.utils.data.Dataset):
31
+ def __init__(self):
32
+ super(Dataset, self).__init__()
33
+
34
+ def initialize(self, opt, cv_img):
35
+ self.opt = opt
36
+ self.root = opt.dataroot
37
+
38
+ self.A = Image.fromarray(cv2.cvtColor(cv_img, cv2.COLOR_BGR2RGB))
39
+ self.dataset_size = 1
40
+
41
+ def __getitem__(self, index):
42
+
43
+ transform_A = get_transform(self.opt)
44
+ A_tensor = transform_A(self.A.convert('RGB'))
45
+
46
+ B_tensor = inst_tensor = feat_tensor = 0
47
+
48
+ input_dict = {'label': A_tensor, 'inst': inst_tensor, 'image': B_tensor,
49
+ 'feat': feat_tensor, 'path': ""}
50
+
51
+ return input_dict
52
+
53
+ def __len__(self):
54
+ return 1
55
+
56
+ class DeepModel(torch.nn.Module):
57
+
58
+ def initialize(self, opt):
59
+
60
+ torch.cuda.empty_cache()
61
+
62
+ self.opt = opt
63
+
64
+ self.gpu_ids = [] #FIX CPU
65
+
66
+ self.netG = self.__define_G(opt.input_nc, opt.output_nc, opt.ngf, opt.netG,
67
+ opt.n_downsample_global, opt.n_blocks_global, opt.n_local_enhancers,
68
+ opt.n_blocks_local, opt.norm, self.gpu_ids)
69
+
70
+ # load networks
71
+ self.__load_network(self.netG)
72
+
73
+
74
+
75
+ def inference(self, label, inst):
76
+
77
+ # Encode Inputs
78
+ input_label, inst_map, _, _ = self.__encode_input(label, inst, infer=True)
79
+
80
+ # Fake Generation
81
+ input_concat = input_label
82
+
83
+ with torch.no_grad():
84
+ fake_image = self.netG.forward(input_concat)
85
+
86
+ return fake_image
87
+
88
+ # helper loading function that can be used by subclasses
89
+ def __load_network(self, network):
90
+
91
+ save_path = os.path.join(self.opt.checkpoints_dir)
92
+
93
+ network.load_state_dict(torch.load(save_path))
94
+
95
+ def __encode_input(self, label_map, inst_map=None, real_image=None, feat_map=None, infer=False):
96
+ if (len(self.gpu_ids) > 0):
97
+ input_label = label_map.data.cuda() #GPU
98
+ else:
99
+ input_label = label_map.data #CPU
100
+
101
+ return input_label, inst_map, real_image, feat_map
102
+
103
+ def __weights_init(self, m):
104
+ classname = m.__class__.__name__
105
+ if classname.find('Conv') != -1:
106
+ m.weight.data.normal_(0.0, 0.02)
107
+ elif classname.find('BatchNorm2d') != -1:
108
+ m.weight.data.normal_(1.0, 0.02)
109
+ m.bias.data.fill_(0)
110
+
111
+ def __define_G(self, input_nc, output_nc, ngf, netG, n_downsample_global=3, n_blocks_global=9, n_local_enhancers=1,
112
+ n_blocks_local=3, norm='instance', gpu_ids=[]):
113
+ norm_layer = self.__get_norm_layer(norm_type=norm)
114
+ netG = GlobalGenerator(input_nc, output_nc, ngf, n_downsample_global, n_blocks_global, norm_layer)
115
+
116
+ if len(gpu_ids) > 0:
117
+ netG.cuda(gpu_ids[0])
118
+ netG.apply(self.__weights_init)
119
+ return netG
120
+
121
+ def __get_norm_layer(self, norm_type='instance'):
122
+ norm_layer = functools.partial(torch.nn.InstanceNorm2d, affine=False)
123
+ return norm_layer
124
+
125
+ ##############################################################################
126
+ # Generator
127
+ ##############################################################################
128
+ class GlobalGenerator(torch.nn.Module):
129
+ def __init__(self, input_nc, output_nc, ngf=64, n_downsampling=3, n_blocks=9, norm_layer=torch.nn.BatchNorm2d,
130
+ padding_type='reflect'):
131
+ assert(n_blocks >= 0)
132
+ super(GlobalGenerator, self).__init__()
133
+ activation = torch.nn.ReLU(True)
134
+
135
+ model = [torch.nn.ReflectionPad2d(3), torch.nn.Conv2d(input_nc, ngf, kernel_size=7, padding=0), norm_layer(ngf), activation]
136
+ ### downsample
137
+ for i in range(n_downsampling):
138
+ mult = 2**i
139
+ model += [torch.nn.Conv2d(ngf * mult, ngf * mult * 2, kernel_size=3, stride=2, padding=1),
140
+ norm_layer(ngf * mult * 2), activation]
141
+
142
+ ### resnet blocks
143
+ mult = 2**n_downsampling
144
+ for i in range(n_blocks):
145
+ model += [ResnetBlock(ngf * mult, padding_type=padding_type, activation=activation, norm_layer=norm_layer)]
146
+
147
+ ### upsample
148
+ for i in range(n_downsampling):
149
+ mult = 2**(n_downsampling - i)
150
+ model += [torch.nn.ConvTranspose2d(ngf * mult, int(ngf * mult / 2), kernel_size=3, stride=2, padding=1, output_padding=1),
151
+ norm_layer(int(ngf * mult / 2)), activation]
152
+ model += [torch.nn.ReflectionPad2d(3), torch.nn.Conv2d(ngf, output_nc, kernel_size=7, padding=0), torch.nn.Tanh()]
153
+ self.model = torch.nn.Sequential(*model)
154
+
155
+ def forward(self, input):
156
+ return self.model(input)
157
+
158
+ # Define a resnet block
159
+ class ResnetBlock(torch.nn.Module):
160
+ def __init__(self, dim, padding_type, norm_layer, activation=torch.nn.ReLU(True), use_dropout=False):
161
+ super(ResnetBlock, self).__init__()
162
+ self.conv_block = self.__build_conv_block(dim, padding_type, norm_layer, activation, use_dropout)
163
+
164
+ def __build_conv_block(self, dim, padding_type, norm_layer, activation, use_dropout):
165
+ conv_block = []
166
+ p = 0
167
+ if padding_type == 'reflect':
168
+ conv_block += [torch.nn.ReflectionPad2d(1)]
169
+ elif padding_type == 'replicate':
170
+ conv_block += [torch.nn.ReplicationPad2d(1)]
171
+ elif padding_type == 'zero':
172
+ p = 1
173
+ else:
174
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
175
+
176
+ conv_block += [torch.nn.Conv2d(dim, dim, kernel_size=3, padding=p),
177
+ norm_layer(dim),
178
+ activation]
179
+ if use_dropout:
180
+ conv_block += [torch.nn.Dropout(0.5)]
181
+
182
+ p = 0
183
+ if padding_type == 'reflect':
184
+ conv_block += [torch.nn.ReflectionPad2d(1)]
185
+ elif padding_type == 'replicate':
186
+ conv_block += [torch.nn.ReplicationPad2d(1)]
187
+ elif padding_type == 'zero':
188
+ p = 1
189
+ else:
190
+ raise NotImplementedError('padding [%s] is not implemented' % padding_type)
191
+ conv_block += [torch.nn.Conv2d(dim, dim, kernel_size=3, padding=p),
192
+ norm_layer(dim)]
193
+
194
+ return torch.nn.Sequential(*conv_block)
195
+
196
+ def forward(self, x):
197
+ out = x + self.conv_block(x)
198
+ return out
199
+
200
+ # Data utils:
201
+ def get_transform(opt, method=Image.BICUBIC, normalize=True):
202
+ transform_list = []
203
+
204
+ base = float(2 ** opt.n_downsample_global)
205
+ if opt.netG == 'local':
206
+ base *= (2 ** opt.n_local_enhancers)
207
+ transform_list.append(transforms.Lambda(lambda img: __make_power_2(img, base, method)))
208
+
209
+ transform_list += [transforms.ToTensor()]
210
+
211
+ if normalize:
212
+ transform_list += [transforms.Normalize((0.5, 0.5, 0.5),
213
+ (0.5, 0.5, 0.5))]
214
+ return transforms.Compose(transform_list)
215
+
216
+ def __make_power_2(img, base, method=Image.BICUBIC):
217
+ ow, oh = img.size
218
+ h = int(round(oh / base) * base)
219
+ w = int(round(ow / base) * base)
220
+ if (h == oh) and (w == ow):
221
+ return img
222
+ return img.resize((w, h), method)
223
+
224
+ # Converts a Tensor into a Numpy array
225
+ # |imtype|: the desired type of the converted numpy array
226
+ def tensor2im(image_tensor, imtype=np.uint8, normalize=True):
227
+ if isinstance(image_tensor, list):
228
+ image_numpy = []
229
+ for i in range(len(image_tensor)):
230
+ image_numpy.append(tensor2im(image_tensor[i], imtype, normalize))
231
+ return image_numpy
232
+ image_numpy = image_tensor.cpu().float().numpy()
233
+ if normalize:
234
+ image_numpy = (np.transpose(image_numpy, (1, 2, 0)) + 1) / 2.0 * 255.0
235
+ else:
236
+ image_numpy = np.transpose(image_numpy, (1, 2, 0)) * 255.0
237
+ image_numpy = np.clip(image_numpy, 0, 255)
238
+ if image_numpy.shape[2] == 1 or image_numpy.shape[2] > 3:
239
+ image_numpy = image_numpy[:,:,0]
240
+ return image_numpy.astype(imtype)
input.jpg ADDED
input.png ADDED
input_not empty.txt ADDED
File without changes
mm.lib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:e38d34f7b3d500352592f7fbe0b361e6d8b2b87ab2dfcbaab62326effc79174a
3
+ size 729785444
mn.lib ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5f3610f4c641187e7e0ef868859fbe9aaa8aa0ef17b37bea6a3b92562af95df0
3
+ size 729785444
opencv_transform___init__.py ADDED
File without changes
opencv_transform_annotation.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ #Object annotation class:
3
+ class BodyPart:
4
+
5
+ def __init__(self, name, xmin, ymin, xmax, ymax, x, y, w, h):
6
+ self.name = name
7
+ #Bounding Box:
8
+ self.xmin = xmin
9
+ self.ymin = ymin
10
+ self.xmax = xmax
11
+ self.ymax = ymax
12
+ #Center:
13
+ self.x = x
14
+ self.y = y
15
+ #Dimensione:
16
+ self.w = w
17
+ self.h = h
opencv_transform_dress_to_correct.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import math
3
+ import numpy as np
4
+ import os
5
+
6
+ # create_correct ===============================================================
7
+ # return:
8
+ # (<Boolean> True/False), depending on the transformation process
9
+ def create_correct(cv_dress):
10
+
11
+ #Production dir:
12
+ return correct_color(cv_dress, 5)
13
+
14
+ # correct_color ==============================================================================
15
+ # return:
16
+ # <RGB> image corrected
17
+ def correct_color(img, percent):
18
+
19
+ assert img.shape[2] == 3
20
+ assert percent > 0 and percent < 100
21
+
22
+ half_percent = percent / 200.0
23
+
24
+ channels = cv2.split(img)
25
+
26
+ out_channels = []
27
+ for channel in channels:
28
+ assert len(channel.shape) == 2
29
+ # find the low and high precentile values (based on the input percentile)
30
+ height, width = channel.shape
31
+ vec_size = width * height
32
+ flat = channel.reshape(vec_size)
33
+
34
+ assert len(flat.shape) == 1
35
+
36
+ flat = np.sort(flat)
37
+
38
+ n_cols = flat.shape[0]
39
+
40
+ low_val = flat[math.floor(n_cols * half_percent)]
41
+ high_val = flat[math.ceil( n_cols * (1.0 - half_percent))]
42
+
43
+ # saturate below the low percentile and above the high percentile
44
+ thresholded = apply_threshold(channel, low_val, high_val)
45
+ # scale the channel
46
+ normalized = cv2.normalize(thresholded, thresholded.copy(), 0, 255, cv2.NORM_MINMAX)
47
+ out_channels.append(normalized)
48
+
49
+ return cv2.merge(out_channels)
50
+
51
+ #Color correction utils
52
+ def apply_threshold(matrix, low_value, high_value):
53
+ low_mask = matrix < low_value
54
+ matrix = apply_mask(matrix, low_mask, low_value)
55
+
56
+ high_mask = matrix > high_value
57
+ matrix = apply_mask(matrix, high_mask, high_value)
58
+
59
+ return matrix
60
+
61
+ #Color correction utils
62
+ def apply_mask(matrix, mask, fill_value):
63
+ masked = np.ma.array(matrix, mask=mask, fill_value=fill_value)
64
+ return masked.filled()
opencv_transform_mask_to_maskref.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ import os
4
+
5
+ ###
6
+ #
7
+ # maskdet_to_maskfin
8
+ #
9
+ #
10
+ ###
11
+
12
+ # create_maskref ===============================================================
13
+ # return:
14
+ # maskref image
15
+ def create_maskref(cv_mask, cv_correct):
16
+
17
+ #Create a total green image
18
+ green = np.zeros((512,512,3), np.uint8)
19
+ green[:,:,:] = (0,255,0) # (B, G, R)
20
+
21
+ #Define the green color filter
22
+ f1 = np.asarray([0, 250, 0]) # green color filter
23
+ f2 = np.asarray([10, 255, 10])
24
+
25
+ #From mask, extrapolate only the green mask
26
+ green_mask = cv2.inRange(cv_mask, f1, f2) #green is 0
27
+
28
+ # (OPTIONAL) Apply dilate and open to mask
29
+ kernel = np.ones((5,5),np.uint8) #Try change it?
30
+ green_mask = cv2.dilate(green_mask, kernel, iterations = 1)
31
+ #green_mask = cv2.morphologyEx(green_mask, cv2.MORPH_OPEN, kernel)
32
+
33
+ # Create an inverted mask
34
+ green_mask_inv = cv2.bitwise_not(green_mask)
35
+
36
+ # Cut correct and green image, using the green_mask & green_mask_inv
37
+ res1 = cv2.bitwise_and(cv_correct, cv_correct, mask = green_mask_inv)
38
+ res2 = cv2.bitwise_and(green, green, mask = green_mask)
39
+
40
+ # Compone:
41
+ return cv2.add(res1, res2)
opencv_transform_maskdet_to_maskfin.py ADDED
@@ -0,0 +1,519 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import numpy as np
2
+ import cv2
3
+ import os
4
+ import random
5
+
6
+ #My library:
7
+ from opencv_transform.annotation import BodyPart
8
+
9
+ ###
10
+ #
11
+ # maskdet_to_maskfin
12
+ #
13
+ # steps:
14
+ # 1. Extract annotation
15
+ # 1.a: Filter by color
16
+ # 1.b: Find ellipses
17
+ # 1.c: Filter out ellipses by max size, and max total numbers
18
+ # 1.d: Detect Problems
19
+ # 1.e: Resolve the problems, or discard the transformation
20
+ # 2. With the body list, draw maskfin, using maskref
21
+ #
22
+ ###
23
+
24
+ # create_maskfin ==============================================================================
25
+ # return:
26
+ # (<Boolean> True/False), depending on the transformation process
27
+ def create_maskfin(maskref, maskdet):
28
+
29
+ #Create a total green image, in which draw details ellipses
30
+ details = np.zeros((512,512,3), np.uint8)
31
+ details[:,:,:] = (0,255,0) # (B, G, R)
32
+
33
+ #Extract body part features:
34
+ bodypart_list = extractAnnotations(maskdet);
35
+
36
+ #Check if the list is not empty:
37
+ if bodypart_list:
38
+
39
+ #Draw body part in details image:
40
+ for obj in bodypart_list:
41
+
42
+ if obj.w < obj.h:
43
+ aMax = int(obj.h/2) #asse maggiore
44
+ aMin = int(obj.w/2) #asse minore
45
+ angle = 0 #angle
46
+ else:
47
+ aMax = int(obj.w/2)
48
+ aMin = int(obj.h/2)
49
+ angle = 90
50
+
51
+ x = int(obj.x)
52
+ y = int(obj.y)
53
+
54
+ #Draw ellipse
55
+ if obj.name == "tit":
56
+ cv2.ellipse(details,(x,y),(aMax,aMin),angle,0,360,(0,205,0),-1) #(0,0,0,50)
57
+ elif obj.name == "aur":
58
+ cv2.ellipse(details,(x,y),(aMax,aMin),angle,0,360,(0,0,255),-1) #red
59
+ elif obj.name == "nip":
60
+ cv2.ellipse(details,(x,y),(aMax,aMin),angle,0,360,(255,255,255),-1) #white
61
+ elif obj.name == "belly":
62
+ cv2.ellipse(details,(x,y),(aMax,aMin),angle,0,360,(255,0,255),-1) #purple
63
+ elif obj.name == "vag":
64
+ cv2.ellipse(details,(x,y),(aMax,aMin),angle,0,360,(255,0,0),-1) #blue
65
+ elif obj.name == "hair":
66
+ xmin = x - int(obj.w/2)
67
+ ymin = y - int(obj.h/2)
68
+ xmax = x + int(obj.w/2)
69
+ ymax = y + int(obj.h/2)
70
+ cv2.rectangle(details,(xmin,ymin),(xmax,ymax),(100,100,100),-1)
71
+
72
+ #Define the green color filter
73
+ f1 = np.asarray([0, 250, 0]) # green color filter
74
+ f2 = np.asarray([10, 255, 10])
75
+
76
+ #From maskref, extrapolate only the green mask
77
+ green_mask = cv2.bitwise_not(cv2.inRange(maskref, f1, f2)) #green is 0
78
+
79
+ # Create an inverted mask
80
+ green_mask_inv = cv2.bitwise_not(green_mask)
81
+
82
+ # Cut maskref and detail image, using the green_mask & green_mask_inv
83
+ res1 = cv2.bitwise_and(maskref, maskref, mask = green_mask)
84
+ res2 = cv2.bitwise_and(details, details, mask = green_mask_inv)
85
+
86
+ # Compone:
87
+ maskfin = cv2.add(res1, res2)
88
+ return maskfin
89
+
90
+ # extractAnnotations ==============================================================================
91
+ # input parameter:
92
+ # (<string> maskdet_img): relative path of the single maskdet image (es: testimg1/maskdet/1.png)
93
+ # return:
94
+ # (<BodyPart []> bodypart_list) - for failure/error, return an empty list []
95
+ def extractAnnotations(maskdet):
96
+
97
+ #Load the image
98
+ #image = cv2.imread(maskdet_img)
99
+
100
+ #Find body part
101
+ tits_list = findBodyPart(maskdet, "tit")
102
+ aur_list = findBodyPart(maskdet, "aur")
103
+ vag_list = findBodyPart(maskdet, "vag")
104
+ belly_list = findBodyPart(maskdet, "belly")
105
+
106
+ #Filter out parts basing on dimension (area and aspect ratio):
107
+ aur_list = filterDimParts(aur_list, 100, 1000, 0.5, 3);
108
+ tits_list = filterDimParts(tits_list, 1000, 60000, 0.2, 3);
109
+ vag_list = filterDimParts(vag_list, 10, 1000, 0.2, 3);
110
+ belly_list = filterDimParts(belly_list, 10, 1000, 0.2, 3);
111
+
112
+ #Filter couple (if parts are > 2, choose only 2)
113
+ aur_list = filterCouple(aur_list);
114
+ tits_list = filterCouple(tits_list);
115
+
116
+ #Detect a missing problem:
117
+ missing_problem = detectTitAurMissingProblem(tits_list, aur_list) #return a Number (code of the problem)
118
+
119
+ #Check if problem is SOLVEABLE:
120
+ if (missing_problem in [3,6,7,8]):
121
+ resolveTitAurMissingProblems(tits_list, aur_list, missing_problem)
122
+
123
+ #Infer the nips:
124
+ nip_list = inferNip(aur_list)
125
+
126
+ #Infer the hair:
127
+ hair_list = inferHair(vag_list)
128
+
129
+ #Return a combined list:
130
+ return tits_list + aur_list + nip_list + vag_list + hair_list + belly_list
131
+
132
+ # findBodyPart ==============================================================================
133
+ # input parameters:
134
+ # (<RGB>image, <string>part_name)
135
+ # return
136
+ # (<BodyPart[]>list)
137
+ def findBodyPart(image, part_name):
138
+
139
+ bodypart_list = [] #empty BodyPart list
140
+
141
+ #Get the correct color filter:
142
+ if part_name == "tit":
143
+ #Use combined color filter
144
+ f1 = np.asarray([0, 0, 0]) # tit color filter
145
+ f2 = np.asarray([10, 10, 10])
146
+ f3 = np.asarray([0, 0, 250]) # aur color filter
147
+ f4 = np.asarray([0, 0, 255])
148
+ color_mask1 = cv2.inRange(image, f1, f2)
149
+ color_mask2 = cv2.inRange(image, f3, f4)
150
+ color_mask = cv2.bitwise_or(color_mask1, color_mask2) #combine
151
+
152
+ elif part_name == "aur":
153
+ f1 = np.asarray([0, 0, 250]) # aur color filter
154
+ f2 = np.asarray([0, 0, 255])
155
+ color_mask = cv2.inRange(image, f1, f2)
156
+
157
+ elif part_name == "vag":
158
+ f1 = np.asarray([250, 0, 0]) # vag filter
159
+ f2 = np.asarray([255, 0, 0])
160
+ color_mask = cv2.inRange(image, f1, f2)
161
+
162
+ elif part_name == "belly":
163
+ f1 = np.asarray([250, 0, 250]) # belly filter
164
+ f2 = np.asarray([255, 0, 255])
165
+ color_mask = cv2.inRange(image, f1, f2)
166
+
167
+ #find contours:
168
+ contours, hierarchy = cv2.findContours(color_mask,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
169
+
170
+ #for every contour:
171
+ for cnt in contours:
172
+
173
+ if len(cnt)>5: #at least 5 points to fit ellipse
174
+
175
+ #(x, y), (MA, ma), angle = cv2.fitEllipse(cnt)
176
+ ellipse = cv2.fitEllipse(cnt)
177
+
178
+ #Fit Result:
179
+ x = ellipse[0][0] #center x
180
+ y = ellipse[0][1] #center y
181
+ angle = ellipse[2] #angle
182
+ aMin = ellipse[1][0]; #asse minore
183
+ aMax = ellipse[1][1]; #asse maggiore
184
+
185
+ #Detect direction:
186
+ if angle == 0:
187
+ h = aMax
188
+ w = aMin
189
+ else:
190
+ h = aMin
191
+ w = aMax
192
+
193
+ #Normalize the belly size:
194
+ if part_name == "belly":
195
+ if w<15:
196
+ w *= 2
197
+ if h<15:
198
+ h *= 2
199
+
200
+ #Normalize the vag size:
201
+ if part_name == "vag":
202
+ if w<15:
203
+ w *= 2
204
+ if h<15:
205
+ h *= 2
206
+
207
+ #Calculate Bounding Box:
208
+ xmin = int(x - (w/2))
209
+ xmax = int(x + (w/2))
210
+ ymin = int(y - (h/2))
211
+ ymax = int(y + (h/2))
212
+
213
+ bodypart_list.append(BodyPart(part_name, xmin, ymin, xmax, ymax, x, y, w, h ))
214
+
215
+ return bodypart_list
216
+
217
+ # filterDimParts ==============================================================================
218
+ # input parameters:
219
+ # (<BodyPart[]>list, <num> minimum area of part, <num> max area, <num> min aspect ratio, <num> max aspect ratio)
220
+ def filterDimParts(bp_list, min_area, max_area, min_ar, max_ar):
221
+
222
+ b_filt = []
223
+
224
+ for obj in bp_list:
225
+
226
+ a = obj.w*obj.h #Object AREA
227
+
228
+ if ((a > min_area)and(a < max_area)):
229
+
230
+ ar = obj.w/obj.h #Object ASPECT RATIO
231
+
232
+ if ((ar>min_ar)and(ar<max_ar)):
233
+
234
+ b_filt.append(obj)
235
+
236
+ return b_filt
237
+
238
+ # filterCouple ==============================================================================
239
+ # input parameters:
240
+ # (<BodyPart[]>list)
241
+ def filterCouple(bp_list):
242
+
243
+ #Remove exceed parts
244
+ if (len(bp_list)>2):
245
+
246
+ #trovare coppia (a,b) che minimizza bp_list[a].y-bp_list[b].y
247
+ min_a = 0
248
+ min_b = 1
249
+ min_diff = abs(bp_list[min_a].y-bp_list[min_b].y)
250
+
251
+ for a in range(0,len(bp_list)):
252
+ for b in range(0,len(bp_list)):
253
+ #TODO: avoid repetition (1,0) (0,1)
254
+ if a != b:
255
+ diff = abs(bp_list[a].y-bp_list[b].y)
256
+ if diff<min_diff:
257
+ min_diff = diff
258
+ min_a = a
259
+ min_b = b
260
+ b_filt = []
261
+
262
+ b_filt.append(bp_list[min_a])
263
+ b_filt.append(bp_list[min_b])
264
+
265
+ return b_filt
266
+ else:
267
+ #No change
268
+ return bp_list
269
+
270
+
271
+
272
+ # detectTitAurMissingProblem ==============================================================================
273
+ # input parameters:
274
+ # (<BodyPart[]> tits list, <BodyPart[]> aur list)
275
+ # return
276
+ # (<num> problem code)
277
+ # TIT | AUR | code | SOLVE? |
278
+ # 0 | 0 | 1 | NO |
279
+ # 0 | 1 | 2 | NO |
280
+ # 0 | 2 | 3 | YES |
281
+ # 1 | 0 | 4 | NO |
282
+ # 1 | 1 | 5 | NO |
283
+ # 1 | 2 | 6 | YES |
284
+ # 2 | 0 | 7 | YES |
285
+ # 2 | 1 | 8 | YES |
286
+ def detectTitAurMissingProblem(tits_list, aur_list):
287
+
288
+ t_len = len(tits_list)
289
+ a_len = len(aur_list)
290
+
291
+ if (t_len == 0):
292
+ if (a_len == 0):
293
+ return 1
294
+ elif (a_len == 1):
295
+ return 2
296
+ elif (a_len == 2):
297
+ return 3
298
+ else:
299
+ return -1
300
+ elif (t_len == 1):
301
+ if (a_len == 0):
302
+ return 4
303
+ elif (a_len == 1):
304
+ return 5
305
+ elif (a_len == 2):
306
+ return 6
307
+ else:
308
+ return -1
309
+ elif (t_len == 2):
310
+ if (a_len == 0):
311
+ return 7
312
+ elif (a_len == 1):
313
+ return 8
314
+ else:
315
+ return -1
316
+ else:
317
+ return -1
318
+
319
+ # resolveTitAurMissingProblems ==============================================================================
320
+ # input parameters:
321
+ # (<BodyPart[]> tits list, <BodyPart[]> aur list, problem code)
322
+ # return
323
+ # none
324
+ def resolveTitAurMissingProblems(tits_list, aur_list, problem_code):
325
+
326
+ if problem_code == 3:
327
+
328
+ random_tit_factor = random.randint(2, 5) #TOTEST
329
+
330
+ #Add the first tit:
331
+ new_w = aur_list[0].w * random_tit_factor #TOTEST
332
+ new_x = aur_list[0].x
333
+ new_y = aur_list[0].y
334
+
335
+ xmin = int(new_x - (new_w/2))
336
+ xmax = int(new_x + (new_w/2))
337
+ ymin = int(new_y - (new_w/2))
338
+ ymax = int(new_y + (new_w/2))
339
+
340
+ tits_list.append(BodyPart("tit", xmin, ymin, xmax, ymax, new_x, new_y, new_w, new_w ))
341
+
342
+ #Add the second tit:
343
+ new_w = aur_list[1].w * random_tit_factor #TOTEST
344
+ new_x = aur_list[1].x
345
+ new_y = aur_list[1].y
346
+
347
+ xmin = int(new_x - (new_w/2))
348
+ xmax = int(new_x + (new_w/2))
349
+ ymin = int(new_y - (new_w/2))
350
+ ymax = int(new_y + (new_w/2))
351
+
352
+ tits_list.append(BodyPart("tit", xmin, ymin, xmax, ymax, new_x, new_y, new_w, new_w ))
353
+
354
+ elif problem_code == 6:
355
+
356
+ #Find wich aur is full:
357
+ d1 = abs(tits_list[0].x - aur_list[0].x)
358
+ d2 = abs(tits_list[0].x - aur_list[1].x)
359
+
360
+ if d1 > d2:
361
+ #aur[0] is empty
362
+ new_x = aur_list[0].x
363
+ new_y = aur_list[0].y
364
+ else:
365
+ #aur[1] is empty
366
+ new_x = aur_list[1].x
367
+ new_y = aur_list[1].y
368
+
369
+ #Calculate Bounding Box:
370
+ xmin = int(new_x - (tits_list[0].w/2))
371
+ xmax = int(new_x + (tits_list[0].w/2))
372
+ ymin = int(new_y - (tits_list[0].w/2))
373
+ ymax = int(new_y + (tits_list[0].w/2))
374
+
375
+ tits_list.append(BodyPart("tit", xmin, ymin, xmax, ymax, new_x, new_y, tits_list[0].w, tits_list[0].w ))
376
+
377
+ elif problem_code == 7:
378
+
379
+ #Add the first aur:
380
+ new_w = tits_list[0].w * random.uniform(0.03, 0.1) #TOTEST
381
+ new_x = tits_list[0].x
382
+ new_y = tits_list[0].y
383
+
384
+ xmin = int(new_x - (new_w/2))
385
+ xmax = int(new_x + (new_w/2))
386
+ ymin = int(new_y - (new_w/2))
387
+ ymax = int(new_y + (new_w/2))
388
+
389
+ aur_list.append(BodyPart("aur", xmin, ymin, xmax, ymax, new_x, new_y, new_w, new_w ))
390
+
391
+ #Add the second aur:
392
+ new_w = tits_list[1].w * random.uniform(0.03, 0.1) #TOTEST
393
+ new_x = tits_list[1].x
394
+ new_y = tits_list[1].y
395
+
396
+ xmin = int(new_x - (new_w/2))
397
+ xmax = int(new_x + (new_w/2))
398
+ ymin = int(new_y - (new_w/2))
399
+ ymax = int(new_y + (new_w/2))
400
+
401
+ aur_list.append(BodyPart("aur", xmin, ymin, xmax, ymax, new_x, new_y, new_w, new_w ))
402
+
403
+ elif problem_code == 8:
404
+
405
+ #Find wich tit is full:
406
+ d1 = abs(aur_list[0].x - tits_list[0].x)
407
+ d2 = abs(aur_list[0].x - tits_list[1].x)
408
+
409
+ if d1 > d2:
410
+ #tit[0] is empty
411
+ new_x = tits_list[0].x
412
+ new_y = tits_list[0].y
413
+ else:
414
+ #tit[1] is empty
415
+ new_x = tits_list[1].x
416
+ new_y = tits_list[1].y
417
+
418
+ #Calculate Bounding Box:
419
+ xmin = int(new_x - (aur_list[0].w/2))
420
+ xmax = int(new_x + (aur_list[0].w/2))
421
+ ymin = int(new_y - (aur_list[0].w/2))
422
+ ymax = int(new_y + (aur_list[0].w/2))
423
+ aur_list.append(BodyPart("aur", xmin, ymin, xmax, ymax, new_x, new_y, aur_list[0].w, aur_list[0].w ))
424
+
425
+ # detectTitAurPositionProblem ==============================================================================
426
+ # input parameters:
427
+ # (<BodyPart[]> tits list, <BodyPart[]> aur list)
428
+ # return
429
+ # (<Boolean> True/False)
430
+ def detectTitAurPositionProblem(tits_list, aur_list):
431
+
432
+ diffTitsX = abs(tits_list[0].x - tits_list[1].x)
433
+ if diffTitsX < 40:
434
+ print("diffTitsX")
435
+ #Tits too narrow (orizontally)
436
+ return True
437
+
438
+ diffTitsY = abs(tits_list[0].y - tits_list[1].y)
439
+ if diffTitsY > 120:
440
+ #Tits too distanced (vertically)
441
+ print("diffTitsY")
442
+ return True
443
+
444
+ diffTitsW = abs(tits_list[0].w - tits_list[1].w)
445
+ if ((diffTitsW < 0.1)or(diffTitsW>60)):
446
+ print("diffTitsW")
447
+ #Tits too equals, or too different (width)
448
+ return True
449
+
450
+ #Check if body position is too low (face not covered by watermark)
451
+ if aur_list[0].y > 350: #tits too low
452
+ #Calculate the ratio between y and aurs distance
453
+ rapp = aur_list[0].y/(abs(aur_list[0].x - aur_list[1].x))
454
+ if rapp > 2.8:
455
+ print("aurDown")
456
+ return True
457
+
458
+ return False
459
+
460
+ # inferNip ==============================================================================
461
+ # input parameters:
462
+ # (<BodyPart[]> aur list)
463
+ # return
464
+ # (<BodyPart[]> nip list)
465
+ def inferNip(aur_list):
466
+ nip_list = []
467
+
468
+ for aur in aur_list:
469
+
470
+ #Nip rules:
471
+ # - circle (w == h)
472
+ # - min dim: 5
473
+ # - bigger if aur is bigger
474
+ nip_dim = int(5 + aur.w*random.uniform(0.03, 0.09))
475
+
476
+ #center:
477
+ x = aur.x
478
+ y = aur.y
479
+
480
+ #Calculate Bounding Box:
481
+ xmin = int(x - (nip_dim/2))
482
+ xmax = int(x + (nip_dim/2))
483
+ ymin = int(y - (nip_dim/2))
484
+ ymax = int(y + (nip_dim/2))
485
+
486
+ nip_list.append(BodyPart("nip", xmin, ymin, xmax, ymax, x, y, nip_dim, nip_dim ))
487
+
488
+ return nip_list
489
+
490
+ # inferHair (TOTEST) ==============================================================================
491
+ # input parameters:
492
+ # (<BodyPart[]> vag list)
493
+ # return
494
+ # (<BodyPart[]> hair list)
495
+ def inferHair(vag_list):
496
+ hair_list = []
497
+
498
+ #70% of chanche to add hair
499
+ if random.uniform(0.0, 1.0) > 0.3:
500
+
501
+ for vag in vag_list:
502
+
503
+ #Hair rules:
504
+ hair_w = vag.w*random.uniform(0.4, 1.5)
505
+ hair_h = vag.h*random.uniform(0.4, 1.5)
506
+
507
+ #center:
508
+ x = vag.x
509
+ y = vag.y - (hair_h/2) - (vag.h/2)
510
+
511
+ #Calculate Bounding Box:
512
+ xmin = int(x - (hair_w/2))
513
+ xmax = int(x + (hair_w/2))
514
+ ymin = int(y - (hair_h/2))
515
+ ymax = int(y + (hair_h/2))
516
+
517
+ hair_list.append(BodyPart("hair", xmin, ymin, xmax, ymax, x, y, hair_w, hair_h ))
518
+
519
+ return hair_list
opencv_transform_nude_to_watermark.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+ import numpy as np
3
+ import os
4
+
5
+ # create_watermark ===============================================================
6
+ # return:
7
+ # (<Boolean> True/False), depending on the transformation process
8
+ def create_watermark(nude):
9
+
10
+ # Add alpha channel if missing
11
+ # if nude.shape[2] < 4:
12
+ # nude = np.dstack([nude, np.ones((512, 512), dtype="uint8") * 255])
13
+
14
+ # watermark = cv2.imread("fake.png", cv2.IMREAD_UNCHANGED)
15
+
16
+ # f1 = np.asarray([0, 0, 0, 250]) # red color filter
17
+ # f2 = np.asarray([255, 255, 255, 255])
18
+ # mask = cv2.bitwise_not(cv2.inRange(watermark, f1, f2))
19
+ # mask_inv = cv2.bitwise_not(mask)
20
+
21
+ # res1 = cv2.bitwise_and(nude, nude, mask = mask)
22
+ # # res2 = cv2.bitwise_and(nude, nude, mask = mask)
23
+ # # res2 = cv2.bitwise_and(watermark, watermark, mask = mask_inv)
24
+ # res = res1
25
+
26
+ # alpha = 0.6
27
+ # return cv2.addWeighted(res, alpha, nude, 1 - alpha, 0)
28
+ return nude
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ numpy
2
+ Pillow
3
+ setuptools
4
+ six
5
+ opencv-python
6
+ torch
7
+ torchvision
8
+ wheel
9
+ gradio
run.py ADDED
@@ -0,0 +1,150 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import cv2
2
+
3
+ #Import Neural Network Model
4
+ from gan import DataLoader, DeepModel, tensor2im
5
+
6
+ #OpenCv Transform:
7
+ from opencv_transform.mask_to_maskref import create_maskref
8
+ from opencv_transform.maskdet_to_maskfin import create_maskfin
9
+ from opencv_transform.dress_to_correct import create_correct
10
+ from opencv_transform.nude_to_watermark import create_watermark
11
+
12
+ """
13
+ run.py
14
+
15
+ This script manage the entire transormation.
16
+
17
+ Transformation happens in 6 phases:
18
+ 0: dress -> correct [opencv] dress_to_correct
19
+ 1: correct -> mask: [GAN] correct_to_mask
20
+ 2: mask -> maskref [opencv] mask_to_maskref
21
+ 3: maskref -> maskdet [GAN] maskref_to_maskdet
22
+ 4: maskdet -> maskfin [opencv] maskdet_to_maskfin
23
+ 5: maskfin -> nude [GAN] maskfin_to_nude
24
+ 6: nude -> watermark [opencv] nude_to_watermark
25
+
26
+ """
27
+
28
+ phases = ["dress_to_correct", "correct_to_mask", "mask_to_maskref", "maskref_to_maskdet", "maskdet_to_maskfin", "maskfin_to_nude", "nude_to_watermark"]
29
+
30
+ class Options():
31
+
32
+ #Init options with default values
33
+ def __init__(self):
34
+
35
+ # experiment specifics
36
+ self.norm = 'batch' #instance normalization or batch normalization
37
+ self.use_dropout = False #use dropout for the generator
38
+ self.data_type = 32 #Supported data type i.e. 8, 16, 32 bit
39
+
40
+ # input/output sizes
41
+ self.batchSize = 1 #input batch size
42
+ self.input_nc = 3 # of input image channels
43
+ self.output_nc = 3 # of output image channels
44
+
45
+ # for setting inputs
46
+ self.serial_batches = True #if true, takes images in order to make batches, otherwise takes them randomly
47
+ self.nThreads = 1 ## threads for loading data (???)
48
+ self.max_dataset_size = 1 #Maximum number of samples allowed per dataset. If the dataset directory contains more than max_dataset_size, only a subset is loaded.
49
+
50
+ # for generator
51
+ self.netG = 'global' #selects model to use for netG
52
+ self.ngf = 64 ## of gen filters in first conv layer
53
+ self.n_downsample_global = 4 #number of downsampling layers in netG
54
+ self.n_blocks_global = 9 #number of residual blocks in the global generator network
55
+ self.n_blocks_local = 0 #number of residual blocks in the local enhancer network
56
+ self.n_local_enhancers = 0 #number of local enhancers to use
57
+ self.niter_fix_global = 0 #number of epochs that we only train the outmost local enhancer
58
+
59
+ #Phase specific options
60
+ self.checkpoints_dir = ""
61
+ self.dataroot = ""
62
+
63
+ #Changes options accordlying to actual phase
64
+ def updateOptions(self, phase):
65
+
66
+ if phase == "correct_to_mask":
67
+ self.checkpoints_dir = "checkpoints/cm.lib"
68
+
69
+ elif phase == "maskref_to_maskdet":
70
+ self.checkpoints_dir = "checkpoints/mm.lib"
71
+
72
+ elif phase == "maskfin_to_nude":
73
+ self.checkpoints_dir = "checkpoints/mn.lib"
74
+
75
+ # process(cv_img, mode)
76
+ # return:
77
+ # watermark image
78
+ def process(cv_img):
79
+
80
+ #InMemory cv2 images:
81
+ dress = cv_img
82
+ correct = None
83
+ mask = None
84
+ maskref = None
85
+ maskfin = None
86
+ maskdet = None
87
+ nude = None
88
+ watermark = None
89
+
90
+ for index, phase in enumerate(phases):
91
+
92
+ print("Executing phase: " + phase)
93
+
94
+ #GAN phases:
95
+ if (phase == "correct_to_mask") or (phase == "maskref_to_maskdet") or (phase == "maskfin_to_nude"):
96
+
97
+ #Load global option
98
+ opt = Options()
99
+
100
+ #Load custom phase options:
101
+ opt.updateOptions(phase)
102
+
103
+ #Load Data
104
+ if (phase == "correct_to_mask"):
105
+ data_loader = DataLoader(opt, correct)
106
+ elif (phase == "maskref_to_maskdet"):
107
+ data_loader = DataLoader(opt, maskref)
108
+ elif (phase == "maskfin_to_nude"):
109
+ data_loader = DataLoader(opt, maskfin)
110
+
111
+ dataset = data_loader.load_data()
112
+
113
+ #Create Model
114
+ model = DeepModel()
115
+ model.initialize(opt)
116
+
117
+ #Run for every image:
118
+ for i, data in enumerate(dataset):
119
+
120
+ generated = model.inference(data['label'], data['inst'])
121
+
122
+ im = tensor2im(generated.data[0])
123
+
124
+ #Save Data
125
+ if (phase == "correct_to_mask"):
126
+ mask = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
127
+
128
+ elif (phase == "maskref_to_maskdet"):
129
+ maskdet = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
130
+
131
+ elif (phase == "maskfin_to_nude"):
132
+ nude = cv2.cvtColor(im, cv2.COLOR_RGB2BGR)
133
+
134
+ #Correcting:
135
+ elif (phase == 'dress_to_correct'):
136
+ correct = create_correct(dress)
137
+
138
+ #mask_ref phase (opencv)
139
+ elif (phase == "mask_to_maskref"):
140
+ maskref = create_maskref(mask, correct)
141
+
142
+ #mask_fin phase (opencv)
143
+ elif (phase == "maskdet_to_maskfin"):
144
+ maskfin = create_maskfin(maskref, maskdet)
145
+
146
+ #nude_to_watermark phase (opencv)
147
+ elif (phase == "nude_to_watermark"):
148
+ watermark = create_watermark(nude)
149
+
150
+ return watermark