snehilchatterjee commited on
Commit
8a1af8c
·
verified ·
1 Parent(s): c6ea043

Upload 10 files

Browse files
app.py ADDED
@@ -0,0 +1,401 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import warnings
3
+ import gradio as gr
4
+ import cv2
5
+ import torchvision
6
+ from torch import nn
7
+ from torchvision.models import mobilenet_v3_small
8
+ import numpy as np
9
+ from PIL import Image
10
+ from torchvision import transforms
11
+
12
+
13
+
14
+ device = "cuda" if torch.cuda.is_available() else "cpu"
15
+ warnings.filterwarnings("ignore")
16
+
17
+
18
+ def flip_text(x):
19
+ return x[::-1]
20
+
21
+
22
+ def method2_prep(image):
23
+ transforms = torchvision.transforms.Compose([
24
+ torchvision.transforms.Resize((256, 256)),
25
+ torchvision.transforms.CenterCrop((224, 224))
26
+ ])
27
+ t_lower = 50
28
+ t_upper = 150
29
+
30
+ height, width = image.shape[:2]
31
+
32
+ x = (width - 1920) // 2
33
+ y = (height - 1080) // 2
34
+
35
+ image = image[y:y+1080, x:x+1920]
36
+
37
+ img = torch.from_numpy(cv2.Canny(image, t_lower, t_upper)[np.newaxis, ...])
38
+ img = torch.vstack((img, img, img))
39
+
40
+ return transforms(img.type(torch.float32))
41
+
42
+
43
+
44
+
45
+ def model2_inf(x):
46
+ print("Method 2")
47
+
48
+ image = method2_prep(x).unsqueeze(dim=0)
49
+ model = mobilenet_v3_small(weights='DEFAULT')
50
+ model.classifier[3] = nn.Linear(in_features=1024, out_features=2, bias=True)
51
+
52
+ image_np = image[0].permute(1, 2, 0).cpu().numpy()
53
+ image_np = (image_np * 255).astype(np.uint8) # Ensure the image is of type uint8
54
+
55
+ model.load_state_dict(torch.load('./weights/method2(0.960).pt'))
56
+ #print("\nModel weights loaded successfully")
57
+
58
+ model.eval() # Set the model to evaluation mode
59
+
60
+ with torch.inference_mode():
61
+ model = model.to(device)
62
+ image = image.to(device)
63
+ output = torch.softmax(model(image), dim=1).detach().cpu()
64
+ prediction = torch.argmax(output, dim=1).item()
65
+ del model
66
+ torch.cuda.empty_cache()
67
+ if prediction == 0:
68
+ return "The image is not pixelated", None
69
+ else:
70
+ return "The image is pixelated", translate_image(Image.fromarray(x), False, 'TinySRGAN', 'False')
71
+
72
+ class _conv(nn.Conv2d):
73
+ def __init__(self, in_channels, out_channels, kernel_size, stride, padding, bias):
74
+ super(_conv, self).__init__(in_channels = in_channels, out_channels = out_channels,
75
+ kernel_size = kernel_size, stride = stride, padding = (kernel_size) // 2, bias = True)
76
+
77
+ self.weight.data = torch.normal(torch.zeros((out_channels, in_channels, kernel_size, kernel_size)), 0.02)
78
+ self.bias.data = torch.zeros((out_channels))
79
+
80
+ for p in self.parameters():
81
+ p.requires_grad = True
82
+
83
+
84
+ class conv(nn.Module):
85
+ def __init__(self, in_channel, out_channel, kernel_size, BN = False, act = None, stride = 1, bias = True):
86
+ super(conv, self).__init__()
87
+ m = []
88
+ m.append(_conv(in_channels = in_channel, out_channels = out_channel,
89
+ kernel_size = kernel_size, stride = stride, padding = (kernel_size) // 2, bias = True))
90
+
91
+ if BN:
92
+ m.append(nn.BatchNorm2d(num_features = out_channel))
93
+
94
+ if act is not None:
95
+ m.append(act)
96
+
97
+ self.body = nn.Sequential(*m)
98
+
99
+ def forward(self, x):
100
+ out = self.body(x)
101
+ return out
102
+
103
+ class ResBlock(nn.Module):
104
+ def __init__(self, channels, kernel_size, act = nn.ReLU(inplace = True), bias = True):
105
+ super(ResBlock, self).__init__()
106
+ m = []
107
+ m.append(conv(channels, channels, kernel_size, BN = True, act = act))
108
+ m.append(conv(channels, channels, kernel_size, BN = True, act = None))
109
+ self.body = nn.Sequential(*m)
110
+
111
+ def forward(self, x):
112
+ res = self.body(x)
113
+ res += x
114
+ return res
115
+
116
+ class BasicBlock(nn.Module):
117
+ def __init__(self, in_channels, out_channels, kernel_size, num_res_block, act = nn.ReLU(inplace = True)):
118
+ super(BasicBlock, self).__init__()
119
+ m = []
120
+
121
+ self.conv = conv(in_channels, out_channels, kernel_size, BN = False, act = act)
122
+ for i in range(num_res_block):
123
+ m.append(ResBlock(out_channels, kernel_size, act))
124
+
125
+ m.append(conv(out_channels, out_channels, kernel_size, BN = True, act = None))
126
+
127
+ self.body = nn.Sequential(*m)
128
+
129
+ def forward(self, x):
130
+ res = self.conv(x)
131
+ out = self.body(res)
132
+ out += res
133
+
134
+ return out
135
+
136
+ class Upsampler(nn.Module):
137
+ def __init__(self, channel, kernel_size, scale, act = nn.ReLU(inplace = True)):
138
+ super(Upsampler, self).__init__()
139
+ m = []
140
+ m.append(conv(channel, channel * scale * scale, kernel_size))
141
+ m.append(nn.PixelShuffle(scale))
142
+
143
+ if act is not None:
144
+ m.append(act)
145
+
146
+ self.body = nn.Sequential(*m)
147
+
148
+ def forward(self, x):
149
+ out = self.body(x)
150
+ return out
151
+
152
+ class discrim_block(nn.Module):
153
+ def __init__(self, in_feats, out_feats, kernel_size, act = nn.LeakyReLU(inplace = True)):
154
+ super(discrim_block, self).__init__()
155
+ m = []
156
+ m.append(conv(in_feats, out_feats, kernel_size, BN = True, act = act))
157
+ m.append(conv(out_feats, out_feats, kernel_size, BN = True, act = act, stride = 2))
158
+ self.body = nn.Sequential(*m)
159
+
160
+ def forward(self, x):
161
+ out = self.body(x)
162
+ return out
163
+
164
+
165
+ class TinySRGAN(nn.Module):
166
+
167
+ def __init__(self, img_feat = 3, n_feats = 32, kernel_size = 3, num_block = 6, act = nn.PReLU(), scale=4):
168
+ super(TinySRGAN, self).__init__()
169
+
170
+ self.conv01 = conv(in_channel = img_feat, out_channel = n_feats, kernel_size = 9, BN = False, act = act)
171
+
172
+ resblocks = [ResBlock(channels = n_feats, kernel_size = 3, act = act) for _ in range(num_block)]
173
+ self.body = nn.Sequential(*resblocks)
174
+
175
+ self.conv02 = conv(in_channel = n_feats, out_channel = n_feats, kernel_size = 3, BN = True, act = None)
176
+
177
+ if(scale == 4):
178
+ upsample_blocks = [Upsampler(channel = n_feats, kernel_size = 3, scale = 2, act = act) for _ in range(2)]
179
+ else:
180
+ upsample_blocks = [Upsampler(channel = n_feats, kernel_size = 3, scale = scale, act = act)]
181
+
182
+ self.tail = nn.Sequential(*upsample_blocks)
183
+
184
+ self.last_conv = conv(in_channel = n_feats, out_channel = img_feat, kernel_size = 3, BN = False, act = nn.Tanh())
185
+
186
+ def forward(self, x):
187
+
188
+ x = self.conv01(x)
189
+ _skip_connection = x
190
+
191
+ x = self.body(x)
192
+ x = self.conv02(x)
193
+ feat = x + _skip_connection
194
+
195
+ x = self.tail(feat)
196
+ x = self.last_conv(x)
197
+
198
+ return x, feat
199
+
200
+
201
+ def build_generator():
202
+
203
+ class ResidualBlock(nn.Module):
204
+ def __init__(self, in_channels, out_channels, expansion=6, stride=1, alpha=1.0):
205
+ super(ResidualBlock, self).__init__()
206
+ self.expansion = expansion
207
+ self.stride = stride
208
+ self.in_channels = in_channels
209
+ self.out_channels = int(out_channels * alpha)
210
+ self.pointwise_conv_filters = self._make_divisible(self.out_channels, 8)
211
+ self.conv1 = nn.Conv2d(in_channels, in_channels * expansion, kernel_size=1, stride=1, padding=0, bias=True)
212
+ self.bn1 = nn.BatchNorm2d(in_channels * expansion)
213
+ self.conv2 = nn.Conv2d(in_channels * expansion, in_channels * expansion, kernel_size=3, stride=stride, padding=1, groups=in_channels * expansion, bias=True)
214
+ self.bn2 = nn.BatchNorm2d(in_channels * expansion)
215
+ self.conv3 = nn.Conv2d(in_channels * expansion, self.pointwise_conv_filters, kernel_size=1, stride=1, padding=0, bias=True)
216
+ self.bn3 = nn.BatchNorm2d(self.pointwise_conv_filters)
217
+ self.relu = nn.ReLU(inplace=True)
218
+ self.skip_add = (stride == 1 and in_channels == self.pointwise_conv_filters)
219
+
220
+ def forward(self, x):
221
+ identity = x
222
+
223
+ out = self.conv1(x)
224
+ out = self.bn1(out)
225
+ out = self.relu(out)
226
+
227
+ out = self.conv2(out)
228
+ out = self.bn2(out)
229
+ out = self.relu(out)
230
+
231
+ out = self.conv3(out)
232
+ out = self.bn3(out)
233
+
234
+ if self.skip_add:
235
+ out = out + identity
236
+
237
+ return out
238
+
239
+ @staticmethod
240
+ def _make_divisible(v, divisor, min_value=None):
241
+ if min_value is None:
242
+ min_value = divisor
243
+ new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
244
+ if new_v < 0.9 * v:
245
+ new_v += divisor
246
+ return new_v
247
+
248
+ class Generator(nn.Module):
249
+ def __init__(self, in_channels, num_residual_blocks, gf):
250
+ super(Generator, self).__init__()
251
+ self.num_residual_blocks = num_residual_blocks
252
+ self.gf = gf
253
+
254
+ self.conv1 = nn.Conv2d(in_channels, gf, kernel_size=3, stride=1, padding=1)
255
+ self.bn1 = nn.BatchNorm2d(gf)
256
+ self.prelu1 = nn.PReLU()
257
+
258
+ self.residual_blocks = self.make_layer(ResidualBlock, gf, num_residual_blocks)
259
+
260
+ self.conv2 = nn.Conv2d(gf, gf, kernel_size=3, stride=1, padding=1)
261
+ self.bn2 = nn.BatchNorm2d(gf)
262
+
263
+ self.upsample1 = nn.Sequential(
264
+ nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
265
+ nn.Conv2d(gf, gf, kernel_size=3, stride=1, padding=1),
266
+ nn.PReLU()
267
+ )
268
+
269
+ self.upsample2 = nn.Sequential(
270
+ nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True),
271
+ nn.Conv2d(gf, gf, kernel_size=3, stride=1, padding=1),
272
+ nn.PReLU()
273
+ )
274
+
275
+ self.conv3 = nn.Conv2d(gf, 3, kernel_size=3, stride=1, padding=1)
276
+ self.tanh = nn.Tanh()
277
+
278
+ def make_layer(self, block, out_channels, blocks):
279
+ layers = []
280
+ for _ in range(blocks):
281
+ layers.append(block(out_channels, out_channels))
282
+ return nn.Sequential(*layers)
283
+
284
+ def forward(self, x):
285
+ out1 = self.prelu1(self.bn1(self.conv1(x)))
286
+ out = self.residual_blocks(out1)
287
+ out = self.bn2(self.conv2(out))
288
+ out = out + out1
289
+ out = self.upsample1(out)
290
+ out = self.upsample2(out)
291
+ out = self.tanh(self.conv3(out))
292
+ return out
293
+
294
+ return Generator(3, 6, 32)
295
+
296
+
297
+ def numpify(imgs):
298
+ all_images = []
299
+ for img in imgs:
300
+ img = img.permute(1,2,0).to('cpu') ### MIGHT CRASH HERE
301
+ all_images.append(img)
302
+ return np.stack(all_images, axis=0)
303
+
304
+ transform = transforms.Compose([
305
+ transforms.ToTensor()
306
+ ])
307
+
308
+
309
+ # Function to translate the image
310
+ def translate_image(image, sharpen, model_name, save):
311
+ print('Translating!')
312
+
313
+ desired_width = 480
314
+
315
+ original_width, original_height = image.size
316
+ desired_height = int((original_height / original_width) * desired_width)
317
+
318
+ resized_image = image.resize((desired_width, desired_height))
319
+
320
+ if(model_name=='MobileSR'):
321
+
322
+ model=build_generator().to(device)
323
+ model.load_state_dict(torch.load('./weights/mobile_sr.pt'))
324
+
325
+ low_res = transform(resized_image)
326
+ low_res = low_res.unsqueeze(dim=0).to(device)
327
+ model.eval()
328
+ with torch.no_grad():
329
+ sr = model(low_res)
330
+
331
+ fake_imgs = numpify(sr)
332
+
333
+ sr_img = Image.fromarray((((fake_imgs[0] + 1) / 2) * 255).astype(np.uint8))
334
+
335
+ elif(model_name=='MiniSRGAN'):
336
+ model = MiniSRGAN().to(device)
337
+ model.load_state_dict(torch.load('./weights/miniSRGAN.pt'))
338
+ model.eval()
339
+
340
+ inputs = np.array(resized_image)
341
+ inputs = (inputs / 127.5) - 1.0
342
+ inputs = torch.tensor(inputs.transpose(2, 0, 1).astype(np.float32)).to(device)
343
+
344
+ with torch.no_grad():
345
+ output, _ = model(torch.unsqueeze(inputs,dim=0))
346
+ output = output[0].cpu().numpy()
347
+ output = np.clip(output, -1.0, 1.0)
348
+ output = (output + 1.0) / 2.0
349
+ output = output.transpose(1, 2, 0)
350
+ sr_img = Image.fromarray((output * 255.0).astype(np.uint8))
351
+
352
+ elif(model_name=='TinySRGAN'):
353
+ model = TinySRGAN().to(device)
354
+ model.load_state_dict(torch.load('./weights/tinySRGAN.pt'))
355
+
356
+ inputs = np.array(resized_image)
357
+ inputs = (inputs / 127.5) - 1.0
358
+ inputs = torch.tensor(inputs.transpose(2, 0, 1).astype(np.float32)).to(device)
359
+ model.eval()
360
+
361
+ with torch.no_grad():
362
+ output, _ = model(torch.unsqueeze(inputs,dim=0))
363
+ output = output[0].cpu().numpy()
364
+ output = (output + 1.0) / 2.0
365
+ output = output.transpose(1, 2, 0)
366
+ sr_img = Image.fromarray((output * 255.0).astype(np.uint8))
367
+
368
+ if sharpen:
369
+ sr_img_cv = np.array(sr_img)
370
+ sr_img_cv = cv2.cvtColor(sr_img_cv, cv2.COLOR_RGB2BGR)
371
+
372
+ kernel = np.array([[0, -1, 0], [-1, 5, -1], [0, -1, 0]])
373
+ sharpened_sr_img_cv = cv2.filter2D(sr_img_cv, -1, kernel)
374
+
375
+ sharpened_sr_img = Image.fromarray(cv2.cvtColor(sharpened_sr_img_cv, cv2.COLOR_BGR2RGB))
376
+
377
+ if(save=="True"):
378
+ sharpened_sr_img.save('super_resolved_image.png')
379
+
380
+ return sharpened_sr_img
381
+ else:
382
+
383
+ if(save=="True"):
384
+ sr_img.save('super_resolved_image.png')
385
+
386
+ return sr_img
387
+
388
+
389
+ # Gradio interface
390
+ interface = gr.Interface(
391
+ fn=model2_inf,
392
+ inputs=gr.Image(type="numpy"),
393
+ outputs=[gr.Textbox(label="Result"), gr.Image(label="Processed Image")],
394
+ title="Pixelation Detection App",
395
+ description="Upload an image to check if it is pixelated. If the image is pixelated, the processed image will be displayed.",
396
+ allow_flagging='never'
397
+ )
398
+
399
+ interface.launch()
400
+ # Launch the Gradio app
401
+ interface.launch()
requirements.txt ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ gradio==4.32.2
2
+ torch==2.1.0
3
+ torchvision==0.16.0
4
+ pillow==10.0.1
5
+ numpy==1.26.0
6
+ opencv-python==4.9.0.80
7
+ scikit-learn==1.3.2
8
+ matplotlib==3.8.2
9
+ tqdm==4.66.1
10
+ timm==0.9.12
11
+ super_image==0.1.7
12
+
weights/SRGAN.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:13f8c4779fb4e0d9b6e56e460fe6df81870ac388e6db20926b2aa9f2fd49bb61
3
+ size 6209971
weights/fsrcnn_x4.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:c15150d6787d487f38a68e66be5ec8a964182403af494e6a935fa03eeb56a630
3
+ size 54998
weights/method1(0.668).pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8df654bb1bb5c4dad3a6aa3251236cf2cf86957b62e3363c66b8e3438a41e70d
3
+ size 6214802
weights/method2(0.960).pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:af08d7011d16d43cdf5bacf03dcd12723f26464013571e597a6160dff2081c65
3
+ size 6214802
weights/miniSRGAN.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:36c68e89673cb8858629133f0aa95f21926382cb82d69f19f8b840866226031e
3
+ size 3827430
weights/miniSRResNET.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a00e5ef9b5b029293e1804d358e1697ef81e0a70bb4c52a96274a1498fe8c2a9
3
+ size 3828022
weights/mobile_sr.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:63ccbec678b30e8d1c25523413928dd2d1d9229519ceae107ae9fc80571d89ba
3
+ size 556457
weights/tinySRGAN.pt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:8e873fd2427142c84278466802fc250607713c51c2671f289b48a82d1979b59f
3
+ size 855730