peterkros commited on
Commit
9df91a5
1 Parent(s): ff0b8db

Upload 12 files

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ 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
+ test_img/test_clip_upscaled_copy.mp4 filter=lfs diff=lfs merge=lfs -text
37
+ test_img/test_clip_upscaled.mp4 filter=lfs diff=lfs merge=lfs -text
anime_upscaler.py ADDED
@@ -0,0 +1,125 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import frame_esrgan
2
+ import cv2
3
+ from tqdm import tqdm
4
+ import os
5
+ import argparse
6
+ import shutil
7
+ import image_slicer
8
+ from image_slicer import join
9
+ import numpy as np
10
+ from PIL import Image
11
+ import matplotlib.pyplot as plt
12
+ import matplotlib.image as mpimg
13
+ import subprocess
14
+
15
+
16
+ parser = argparse.ArgumentParser()
17
+ parser.add_argument('-m', '--model_path', type=str, help='REQUIRED: specify path of the model being used')
18
+ parser.add_argument('-i', '--input', type=str, help='REQUIRED: specify path of the image you want to upscale')
19
+ parser.add_argument('-o', '--output', type=str, help='REQUIRED: specify path where you want to save image')
20
+ parser.add_argument('-s', '--slice', nargs='?', type=int, const=4, help='OPTIONAL: specify weather to split frames, recommended to use to help with VRAM unless you got a fucken quadro or something' )
21
+ parser.add_argument('-a', '--audio', action='store_true', help='OPTIONAL: specify weather you want to copy audio from source as well')
22
+ parser.add_argument('-c', '--clear_temp', action='store_true', help='OPTIONAL: specify weather you want to clear temporary folder with upscaled frames after you are finished with final video')
23
+ args = parser.parse_args()
24
+
25
+ def extract_frames(vid_path, save=''):
26
+ vid = cv2.VideoCapture(vid_path)
27
+ images = []
28
+ count = 0
29
+ success, image = vid.read()
30
+ while success:
31
+ if not save:
32
+ images.append(image)
33
+ else:
34
+ print('saving frame {}...'.format(count))
35
+ cv2.imwrite(save.format(count), image)
36
+ print('done saving frame {}...'.format(count))
37
+ success, image = vid.read()
38
+ count += 1
39
+ return images
40
+
41
+ def get_fps(vid_path):
42
+ vid = cv2.VideoCapture(vid_path)
43
+ return vid.get(cv2.CAP_PROP_FPS)
44
+
45
+ def create_temp_folder(vid_path):
46
+ if os.path.exists('tmp'):
47
+ folder_name = vid_path.split('/')[-1].split('.')[0]
48
+ os.mkdir('tmp/{}'.format(folder_name))
49
+ else:
50
+ os.mkdir('tmp')
51
+ create_temp_folder(vid_path)
52
+
53
+ def get_dir(path):
54
+ if not os.path.exists(path):
55
+ os.mkdir(path)
56
+ return path
57
+
58
+ def setup_frames(vid_path, slice=None):
59
+ folder_name = vid_path.split('/')[-1].split('.')[0]
60
+ images = extract_frames(vid_path)
61
+ create_temp_folder(vid_path)
62
+ os.mkdir('tmp/{}/original'.format(folder_name))
63
+ slices = []
64
+ for i in tqdm(range(len(images))):
65
+ cv2.imwrite('tmp/{}/original'.format(folder_name)+'/frame_{}.png'.format(i), images[i])
66
+ os.mkdir('tmp/{}/upscaled'.format(folder_name))
67
+
68
+ def upscale(vid_path, slice=None):
69
+ folder_name = vid_path.split('/')[-1].split('.')[0]
70
+ print('extracting frames...')
71
+ setup_frames(vid_path)
72
+ print('upscaling...')
73
+ for i in tqdm(os.listdir('tmp/{}/original'.format(folder_name))):
74
+ if slice:
75
+ out = frame_esrgan.upscale_slice(args.model_path, 'tmp/{}/original/{}'.format(folder_name, i), slice)
76
+ else:
77
+ out = frame_esrgan.upscale(args.model_path, 'tmp/{}/original/{}'.format(folder_name, i))
78
+ cv2.imwrite('tmp/{}/upscaled/{}'.format(folder_name, i), out)
79
+
80
+ def combine_frames(video_path, new_video_path):
81
+ folder_name = video_path.split('/')[-1].split('.')[0]
82
+ images = [img for img in os.listdir('tmp/{}/upscaled'.format(folder_name))]
83
+ height, width, layers = cv2.imread('tmp/{}/upscaled/frame_0.png'.format(folder_name)).shape
84
+ fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
85
+ fps = get_fps(video_path)
86
+ video = cv2.VideoWriter(new_video_path, fourcc, fps, (width, height))
87
+ for i in tqdm(range(len(images))):
88
+ video.write(cv2.imread('tmp/{}/upscaled/frame_{}.png'.format(folder_name, i)))
89
+ cv2.destroyAllWindows()
90
+ video.release()
91
+
92
+ def copy_audio(original_video_path, new_video_path, new_name=''):
93
+ #ffmpeg -i input_0.mp4 -i input_1.mp4 -c copy -map 0:v:0 -map 1:a:0 -shortest out.mp4
94
+ tmp_name = new_video_path.split('.')[0] + '_tmp.' + new_video_path.split('.')[-1]
95
+ subprocess.run([
96
+ 'ffmpeg',
97
+ '-i',
98
+ new_video_path,
99
+ '-i',
100
+ original_video_path,
101
+ '-c',
102
+ 'copy',
103
+ '-map',
104
+ '0:v:0',
105
+ '-map',
106
+ '1:a:0',
107
+ '-shortest',
108
+ tmp_name
109
+ ])
110
+
111
+ os.replace(tmp_name, new_video_path)
112
+
113
+
114
+ if __name__ == '__main__':
115
+ if args.model_path and args.input and args.output:
116
+ try:
117
+ upscale(args.input, slice=args.slice)
118
+ combine_frames(args.input, args.output)
119
+ if args.audio:
120
+ copy_audio(args.input, args.output)
121
+ if args.clear_temp:
122
+ shutil.rmtree('tmp')
123
+ except Exception as e:
124
+ print(e)
125
+ shutil.rmtree('tmp')
app.py ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+
3
+ def greet(name):
4
+ return "Hello " + name + "!!"
5
+
6
+ iface = gr.Interface(fn=greet, inputs="text", outputs="text")
7
+ iface.launch()
frame_esrgan.py ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import torch
2
+ import torchvision
3
+ from basicsr.archs.rrdbnet_arch import RRDBNet
4
+ from realesrgan import RealESRGANer
5
+ import cv2
6
+ import argparse
7
+ import matplotlib.pyplot as plt
8
+ import matplotlib.image as mpimg
9
+ import image_slicer
10
+ from image_slicer import join
11
+ from PIL import Image
12
+ import numpy as np
13
+ from tqdm import tqdm
14
+
15
+ def convert_from_image_to_cv2(img: Image) -> np.ndarray:
16
+ # return np.asarray(img)
17
+ return cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
18
+
19
+ def upscale(model_path, im_path):
20
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=6, num_grow_ch=32, scale=4)
21
+ upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=False)
22
+ img = cv2.imread(im_path, cv2.IMREAD_UNCHANGED)
23
+ output, _ = upsampler.enhance(img, outscale=4)
24
+ return output
25
+
26
+ def upscale_slice(model_path, image, slice):
27
+ width, height = Image.open(image).size
28
+ tiles = image_slicer.slice(image, slice, save=False)
29
+ model = RRDBNet(num_in_ch=3, num_out_ch=3, num_feat=64, num_block=6, num_grow_ch=32, scale=4)
30
+ upsampler = RealESRGANer(scale=4, model_path=model_path, model=model, tile=0, tile_pad=10, pre_pad=0, half=False)
31
+ for tile in tiles:
32
+ output, _ = upsampler.enhance(np.array(tile.image), outscale=4)
33
+ tile.image = Image.fromarray(output)
34
+ tile.coords = (tile.coords[0]*4, tile.coords[1]*4)
35
+ return convert_from_image_to_cv2(join(tiles, width=width*4, height=height*4))
36
+
37
+ if __name__ == '__main__':
38
+ parser = argparse.ArgumentParser()
39
+ parser.add_argument('-m', '--model_path', type=str, help='REQUIRED: specify path of the model being used')
40
+ parser.add_argument('-i', '--input', type=str, help='REQUIRED: specify path of the image you want to upscale')
41
+ parser.add_argument('-o', '--output', type=str, help='REQUIRED: specify path where you want to save image')
42
+ parser.add_argument('-v', '--visualize', action='store_true', help='OPTIONAL: add this to see how image looks before and after upscale')
43
+ parser.add_argument('-s', '--slice', nargs='?', type=int, const=4, help='OPTIONAL: specify weather to split frames, recommended to use to help with VRAM unless you got a fucken quadro or something')
44
+ parser.add_argument('-r', '--resize', nargs='?', type=str, const='1920x1080', help="OPTIONAL: specify whether to resize image to a specific resolution. Specify with widthxheight, for example 1920x1080")
45
+ args = parser.parse_args()
46
+
47
+
48
+ if args.model_path and args.input and args.output:
49
+ if args.slice:
50
+ output = upscale_slice(args.model_path, args.input, args.slice)
51
+ else:
52
+ output = upscale(args.model_path, args.input)
53
+ if args.visualize:
54
+ plt.imshow(mpimg.imread(args.input))
55
+ plt.show()
56
+ plt.imshow(output)
57
+ plt.show()
58
+ if args.resize:
59
+ size = tuple(int(i) for i in args.resize.split('x'))
60
+ output = cv2.resize(output, size)
61
+ cv2.imwrite(args.output, output)
62
+ else:
63
+ print('Error: Missing arguments, check -h, --help for details')
64
+
65
+
66
+ # tiles = image_slicer.slice('tmp/{}/original/{}'.format(folder_name, i), slice, save=False)
67
+ # print(tiles)
68
+ # for tile in tiles:
69
+ # up = frame_esrgan.upscale_slice(args.model_path, np.array(tile.image))
70
+ # tile.image = Image.fromarray(up, 'RGB')
71
+ # out = join(tiles)
72
+ # out.save('tmp/{}/upscaled/{}'.format(folder_name, i.replace('jpg', 'png')))
readme.md ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # anime upscaler
2
+
3
+ My usage of [Real-ESRGAN](https://github.com/xinntao/Real-ESRGAN) to upscale anime.
4
+
5
+ # Some results:
6
+
7
+ ## Picture
8
+
9
+ Before | After
10
+ :-------------------------:|:-------------------------:
11
+ ![](test_img/random_test_frame.jpg) | ![](test_img/random_test_frame_out.jpg)
12
+
13
+ ## Video
14
+
15
+ ### Before
16
+
17
+ https://user-images.githubusercontent.com/56494763/148880280-fb6488c1-e87c-47e4-81ec-aecc3654c9d6.mp4
18
+
19
+ ### After
20
+
21
+ https://user-images.githubusercontent.com/56494763/148880247-a99d3bd5-eb7e-4371-8de2-68d55cab801e.mp4
22
+
23
+ # How To Use
24
+
25
+ ## Download anime model:
26
+
27
+ https://github.com/xinntao/Real-ESRGAN/blob/master/docs/anime_model.md
28
+
29
+ ## For a single image:
30
+
31
+ `python3 frame_esrgan.py -m /path/to/RealESRGAN_x4plus_anime_6B.pth -i path/to/img -o path/to/img.png`
32
+
33
+ If memory usage is too high and you need to split frames and stitch back together use the `-s, --split` argument. Default number of splits is 4, but you can make as many as you want.
34
+
35
+ If you want to change the final size, one can now add the `-r` or the `--resize` argument, followed by a string indicating the desired resolution, for example we would add `-r 1920x1080` to resize the output to that size.
36
+
37
+ Please note that the output of a single image must be a PNG due to alpha channel. Will be fixed in the future hopefully
38
+
39
+ ## For a video:
40
+
41
+ `python3 anime_upscaler.py -m /path/to/RealESRGAN_x4plus_anime_6B.pth -i path/to/video -o path/to/desired/output -s -a`
42
+
43
+ If you do not want audio, remove the `-a` at the end
requirements.txt ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ basicsr==1.4.2
2
+ image_slicer==2.1.1
3
+ matplotlib==3.5.1
4
+ moviepy==1.0.3
5
+ opencv_python==4.8.1.78
6
+ Pillow==10.1.0
7
+ realesrgan==0.3.0
8
+ torchvision==0.15.2
9
+ tqdm==4.66.1
test_img/glpa_01_cut_1.mp4 ADDED
Binary file (308 kB). View file
 
test_img/random_test_frame.jpg ADDED
test_img/random_test_frame_out.jpg ADDED
test_img/test_clip.mp3 ADDED
Binary file (100 kB). View file
 
test_img/test_clip.mp4 ADDED
Binary file (569 kB). View file
 
test_img/test_clip_upscaled.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:1a9bdd8fe9aeef53b68add9a027e390faf92f0823dc0c26099bbca451c24ce6f
3
+ size 15765842
test_img/test_clip_upscaled_copy.mp4 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:3c0c0f1875fdd41ea351f8a29b363260987916c5a8fbda0ce4bb3c86436b8f51
3
+ size 15849639