MynooMuz commited on
Commit
65a3cf4
·
1 Parent(s): 0475f02

feat: add 2x upscale with high quality smoothing

Browse files
Files changed (1) hide show
  1. app.py +23 -18
app.py CHANGED
@@ -7,65 +7,68 @@ import zipfile
7
  import tempfile
8
  import shutil
9
 
10
- def process_image(img, strength):
11
- # Görseli gri tonlamaya çevir ve normalize et
 
 
 
 
 
12
  img_cv = np.array(img.convert('L'))
13
  img_cv = img_cv.astype(np.float32) / 255.0
14
 
15
- # Sobel filtresi ile X ve Y yönlerindeki gradyanları (eğimleri) hesapla
16
  sobelx = cv2.Sobel(img_cv, cv2.CV_64F, 1, 0, ksize=3)
17
  sobely = cv2.Sobel(img_cv, cv2.CV_64F, 0, 1, ksize=3)
18
 
19
- # Normal vektörü bileşenlerini hesapla (-dz/dx, -dz/dy, 1)
20
  nx = -sobelx * strength
21
  ny = -sobely * strength
22
  nz = np.ones_like(img_cv)
23
 
24
- # Vektörleri normalize et (uzunluklarını 1 yap)
25
  length = np.sqrt(nx**2 + ny**2 + nz**2)
26
  nx /= length
27
  ny /= length
28
  nz /= length
29
 
30
- # [-1, 1] aralığını RGB için [0, 255] aralığına çevir
31
  nx = (nx + 1) / 2 * 255
32
  ny = (ny + 1) / 2 * 255
33
  nz = (nz + 1) / 2 * 255
34
 
35
- # R=X, G=Y, B=Z olacak şekilde birleştir
36
  normal_map = np.stack((nx, ny, nz), axis=-1).astype(np.uint8)
37
  return Image.fromarray(normal_map)
38
 
39
- def process_single(image, strength):
40
  if image is None:
41
  return None
42
- return process_image(image, strength)
43
 
44
- def process_files(file_objs, strength):
45
  if not file_objs:
46
  return None
47
 
48
- # Geçici bir klasör ve ZIP dosyası oluştur
49
  temp_dir = tempfile.mkdtemp()
50
  zip_filename = "normal_maps.zip"
51
  zip_path = os.path.join(tempfile.gettempdir(), zip_filename)
52
 
53
  with zipfile.ZipFile(zip_path, 'w') as zipf:
54
  for file_obj in file_objs:
55
- # Gradio dosya yollarını liste olarak verir
56
  file_path = file_obj.name if hasattr(file_obj, 'name') else file_obj
57
  file_name = os.path.basename(file_path)
58
 
59
  if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.webp')):
60
  try:
61
  img = Image.open(file_path)
62
- normal_map = process_image(img, strength)
63
 
64
  base_name, ext = os.path.splitext(file_name)
65
  out_name = f"{base_name}_normalmap{ext}"
66
 
67
  out_path = os.path.join(temp_dir, out_name)
68
- # Orijinal uzantıya göre kaydetmeye çalış, hata olursa PNG yap
69
  try:
70
  normal_map.save(out_path)
71
  except:
@@ -75,9 +78,9 @@ def process_files(file_objs, strength):
75
 
76
  zipf.write(out_path, arcname=out_name)
77
  except Exception as e:
78
- print(f"Hata ({file_path}): {e}")
79
 
80
- # Geçici klasörü temizle
81
  shutil.rmtree(temp_dir)
82
  return zip_path
83
 
@@ -93,11 +96,12 @@ with gr.Blocks(title="Normal Map Generator", theme=gr.themes.Soft()) as demo:
93
  with gr.Column():
94
  img_input = gr.Image(type="pil", label="Input Image")
95
  strength_slider_1 = gr.Slider(minimum=0.1, maximum=10.0, value=2.0, step=0.1, label="Normal Map Strength")
 
96
  btn_single = gr.Button("Generate", variant="primary")
97
  with gr.Column():
98
  img_output = gr.Image(type="pil", label="Normal Map Result", format="png")
99
 
100
- btn_single.click(fn=process_single, inputs=[img_input, strength_slider_1], outputs=img_output)
101
 
102
  # FOLDER/BATCH TAB
103
  with gr.Tab("Folder (Batch Processing)"):
@@ -107,11 +111,12 @@ with gr.Blocks(title="Normal Map Generator", theme=gr.themes.Soft()) as demo:
107
  # file_count="directory" allows folder upload
108
  folder_input = gr.File(file_count="directory", label="Upload Folder / Files")
109
  strength_slider_2 = gr.Slider(minimum=0.1, maximum=10.0, value=2.0, step=0.1, label="Normal Map Strength")
 
110
  btn_folder = gr.Button("Generate Batch and Download", variant="primary")
111
  with gr.Column():
112
  file_output = gr.File(label="Download ZIP File")
113
 
114
- btn_folder.click(fn=process_files, inputs=[folder_input, strength_slider_2], outputs=file_output)
115
 
116
  if __name__ == "__main__":
117
  demo.launch()
 
7
  import tempfile
8
  import shutil
9
 
10
+ def process_image(img, strength, upscale=False):
11
+ if upscale:
12
+ # Resize to 2x using LANCZOS for high-quality smoothing
13
+ new_size = (img.width * 2, img.height * 2)
14
+ img = img.resize(new_size, resample=Image.LANCZOS)
15
+
16
+ # Convert to grayscale and normalize
17
  img_cv = np.array(img.convert('L'))
18
  img_cv = img_cv.astype(np.float32) / 255.0
19
 
20
+ # Sobel filters for gradients
21
  sobelx = cv2.Sobel(img_cv, cv2.CV_64F, 1, 0, ksize=3)
22
  sobely = cv2.Sobel(img_cv, cv2.CV_64F, 0, 1, ksize=3)
23
 
24
+ # Normal vector components (-dz/dx, -dz/dy, 1)
25
  nx = -sobelx * strength
26
  ny = -sobely * strength
27
  nz = np.ones_like(img_cv)
28
 
29
+ # Normalize vectors
30
  length = np.sqrt(nx**2 + ny**2 + nz**2)
31
  nx /= length
32
  ny /= length
33
  nz /= length
34
 
35
+ # Convert [-1, 1] to [0, 255] for RGB
36
  nx = (nx + 1) / 2 * 255
37
  ny = (ny + 1) / 2 * 255
38
  nz = (nz + 1) / 2 * 255
39
 
40
+ # Merge to RGB (R=X, G=Y, B=Z)
41
  normal_map = np.stack((nx, ny, nz), axis=-1).astype(np.uint8)
42
  return Image.fromarray(normal_map)
43
 
44
+ def process_single(image, strength, upscale):
45
  if image is None:
46
  return None
47
+ return process_image(image, strength, upscale)
48
 
49
+ def process_files(file_objs, strength, upscale):
50
  if not file_objs:
51
  return None
52
 
53
+ # Create temp directory and ZIP file
54
  temp_dir = tempfile.mkdtemp()
55
  zip_filename = "normal_maps.zip"
56
  zip_path = os.path.join(tempfile.gettempdir(), zip_filename)
57
 
58
  with zipfile.ZipFile(zip_path, 'w') as zipf:
59
  for file_obj in file_objs:
 
60
  file_path = file_obj.name if hasattr(file_obj, 'name') else file_obj
61
  file_name = os.path.basename(file_path)
62
 
63
  if file_name.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.webp')):
64
  try:
65
  img = Image.open(file_path)
66
+ normal_map = process_image(img, strength, upscale)
67
 
68
  base_name, ext = os.path.splitext(file_name)
69
  out_name = f"{base_name}_normalmap{ext}"
70
 
71
  out_path = os.path.join(temp_dir, out_name)
 
72
  try:
73
  normal_map.save(out_path)
74
  except:
 
78
 
79
  zipf.write(out_path, arcname=out_name)
80
  except Exception as e:
81
+ print(f"Error ({file_path}): {e}")
82
 
83
+ # Cleanup temp directory
84
  shutil.rmtree(temp_dir)
85
  return zip_path
86
 
 
96
  with gr.Column():
97
  img_input = gr.Image(type="pil", label="Input Image")
98
  strength_slider_1 = gr.Slider(minimum=0.1, maximum=10.0, value=2.0, step=0.1, label="Normal Map Strength")
99
+ upscale_check_1 = gr.Checkbox(label="Upscale 2x (High Quality Smoothing)", value=False)
100
  btn_single = gr.Button("Generate", variant="primary")
101
  with gr.Column():
102
  img_output = gr.Image(type="pil", label="Normal Map Result", format="png")
103
 
104
+ btn_single.click(fn=process_single, inputs=[img_input, strength_slider_1, upscale_check_1], outputs=img_output)
105
 
106
  # FOLDER/BATCH TAB
107
  with gr.Tab("Folder (Batch Processing)"):
 
111
  # file_count="directory" allows folder upload
112
  folder_input = gr.File(file_count="directory", label="Upload Folder / Files")
113
  strength_slider_2 = gr.Slider(minimum=0.1, maximum=10.0, value=2.0, step=0.1, label="Normal Map Strength")
114
+ upscale_check_2 = gr.Checkbox(label="Upscale 2x (High Quality Smoothing)", value=False)
115
  btn_folder = gr.Button("Generate Batch and Download", variant="primary")
116
  with gr.Column():
117
  file_output = gr.File(label="Download ZIP File")
118
 
119
+ btn_folder.click(fn=process_files, inputs=[folder_input, strength_slider_2, upscale_check_2], outputs=file_output)
120
 
121
  if __name__ == "__main__":
122
  demo.launch()