tejani commited on
Commit
8566f9e
·
verified ·
1 Parent(s): be0aad2

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -39
app.py CHANGED
@@ -4,40 +4,59 @@ import numpy as np
4
  from PIL import Image
5
  import noise # Requires `pynoise` package: `pip install noise`
6
 
7
- # Advanced Normal Map generation
8
- def generate_normal_map(image, strength=1.0, blur_size=5, use_bilateral=False):
9
- img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
10
- # Noise reduction: Bilateral filter (edge-preserving) or Gaussian blur
 
11
  if use_bilateral:
12
- img = cv2.bilateralFilter(img, 9, 75, 75)
13
  else:
14
- img = cv2.GaussianBlur(img, (blur_size, blur_size), 0)
15
- # Compute gradients with Scharr (better than Sobel for fine details)
16
- sobel_x = cv2.Scharr(img, cv2.CV_64F, 1, 0)
17
- sobel_y = cv2.Scharr(img, cv2.CV_64F, 0, 1)
18
- # Normalize gradients with strength adjustment
19
- sobel_x = cv2.normalize(sobel_x, None, -strength, strength, cv2.NORM_MINMAX)
20
- sobel_y = cv2.normalize(sobel_y, None, -strength, strength, cv2.NORM_MINMAX)
21
- # Compute normal vectors
22
- normal_map = np.zeros((img.shape[0], img.shape[1], 3), dtype=np.float32)
23
- normal_map[..., 0] = sobel_x # X (Red)
24
- normal_map[..., 1] = sobel_y # Y (Green)
25
- normal_map[..., 2] = 1.0 # Z (Blue)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  norm = np.linalg.norm(normal_map, axis=2, keepdims=True)
27
  normal_map = np.divide(normal_map, norm, out=np.zeros_like(normal_map), where=norm != 0)
28
- # Convert to RGB
29
  normal_map = (normal_map + 1) * 127.5
30
  normal_map = np.clip(normal_map, 0, 255).astype(np.uint8)
31
  return Image.fromarray(normal_map)
32
 
33
- # Advanced Displacement Map generation
34
- def generate_displacement_map(image, contrast=1.0, add_noise=False, noise_scale=0.1):
35
  img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
36
- # Enhance contrast with histogram equalization
37
- img = cv2.equalizeHist(img)
 
38
  # Adjust contrast
39
  img = cv2.convertScaleAbs(img, alpha=contrast, beta=0)
40
- # Optional: Add Perlin noise for realism
 
 
 
 
41
  if add_noise:
42
  height, width = img.shape
43
  noise_map = np.zeros((height, width), dtype=np.float32)
@@ -47,28 +66,33 @@ def generate_displacement_map(image, contrast=1.0, add_noise=False, noise_scale=
47
  img = cv2.add(img, noise_map.astype(np.uint8))
48
  return Image.fromarray(img)
49
 
50
- # Advanced Roughness Map generation
51
- def generate_roughness_map(image, invert=True, sharpness=1.0, detail_boost=0.5):
52
  img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
53
- # Edge-preserving smoothing
54
- img = cv2.bilateralFilter(img, 9, 75, 75)
 
 
 
55
  # Optional inversion
56
  if invert:
57
  img = 255 - img
58
- # Sharpen the image
59
  blurred = cv2.GaussianBlur(img, (5, 5), 0)
60
  img = cv2.addWeighted(img, 1.0 + sharpness, blurred, -sharpness, 0)
61
- # Boost fine details with unsharp masking
62
  img = cv2.addWeighted(img, 1.0 + detail_boost, blurred, -detail_boost, 0)
63
  return Image.fromarray(img)
64
 
65
- # Process function with all parameters
66
- def process_image(input_image, normal_strength=1.0, normal_blur=5, normal_bilateral=False,
67
- disp_contrast=1.0, disp_noise=False, disp_noise_scale=0.1,
68
- rough_invert=True, rough_sharpness=1.0, rough_detail=0.5):
69
- normal_map = generate_normal_map(input_image, strength=normal_strength, blur_size=normal_blur, use_bilateral=normal_bilateral)
70
- displacement_map = generate_displacement_map(input_image, contrast=disp_contrast, add_noise=disp_noise, noise_scale=disp_noise_scale)
71
- roughness_map = generate_roughness_map(input_image, invert=rough_invert, sharpness=rough_sharpness, detail_boost=rough_detail)
 
 
 
72
  return normal_map, displacement_map, roughness_map
73
 
74
  # Gradio Interface with advanced controls
@@ -78,16 +102,19 @@ interface = gr.Interface(
78
  gr.Image(type="pil", label="Upload Image"),
79
  # Normal Map Controls
80
  gr.Slider(minimum=0.1, maximum=5.0, step=0.1, value=1.0, label="Normal Map Strength"),
81
- gr.Slider(minimum=3, maximum=15, step=2, value=5, label="Normal Map Blur Size (if not bilateral)"),
82
  gr.Checkbox(value=False, label="Use Bilateral Filter for Normal Map"),
 
83
  # Displacement Map Controls
84
  gr.Slider(minimum=0.5, maximum=2.0, step=0.1, value=1.0, label="Displacement Map Contrast"),
85
  gr.Checkbox(value=False, label="Add Noise to Displacement Map"),
86
  gr.Slider(minimum=0.05, maximum=0.5, step=0.05, value=0.1, label="Displacement Noise Scale"),
 
87
  # Roughness Map Controls
88
  gr.Checkbox(value=True, label="Invert Roughness Map"),
89
  gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label="Roughness Sharpness"),
90
- gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0.5, label="Roughness Detail Boost")
 
91
  ],
92
  outputs=[
93
  gr.Image(type="pil", label="Normal Map"),
@@ -95,7 +122,7 @@ interface = gr.Interface(
95
  gr.Image(type="pil", label="Roughness Map")
96
  ],
97
  title="Advanced Material Map Generator",
98
- description="Upload an image to generate highly customizable Normal, Displacement, and Roughness maps."
99
  )
100
 
101
  interface.launch()
 
4
  from PIL import Image
5
  import noise # Requires `pynoise` package: `pip install noise`
6
 
7
+ # Advanced Normal Map with multi-scale gradients and color influence
8
+ def generate_normal_map(image, strength=1.0, blur_size=5, use_bilateral=False, color_influence=0.3):
9
+ img = np.array(image)
10
+ gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
11
+ # Noise reduction
12
  if use_bilateral:
13
+ gray = cv2.bilateralFilter(gray, 9, 75, 75)
14
  else:
15
+ gray = cv2.GaussianBlur(gray, (blur_size, blur_size), 0)
16
+
17
+ # Multi-scale gradient computation using Laplacian pyramid
18
+ levels = 3
19
+ normal_map = np.zeros((gray.shape[0], gray.shape[1], 3), dtype=np.float32)
20
+ for i in range(levels):
21
+ scale = 1 / (2 ** i)
22
+ resized = cv2.resize(gray, None, fx=scale, fy=scale, interpolation=cv2.INTER_AREA)
23
+ sobel_x = cv2.Scharr(resized, cv2.CV_64F, 1, 0)
24
+ sobel_y = cv2.Scharr(resized, cv2.CV_64F, 0, 1)
25
+ sobel_x = cv2.resize(sobel_x, (gray.shape[1], gray.shape[0]), interpolation=cv2.INTER_LINEAR)
26
+ sobel_y = cv2.resize(sobel_y, (gray.shape[1], gray.shape[0]), interpolation=cv2.INTER_LINEAR)
27
+ normal_map[..., 0] += sobel_x * (1.0 / levels)
28
+ normal_map[..., 1] += sobel_y * (1.0 / levels)
29
+
30
+ # Normalize with strength
31
+ normal_map[..., 0] = cv2.normalize(normal_map[..., 0], None, -strength, strength, cv2.NORM_MINMAX)
32
+ normal_map[..., 1] = cv2.normalize(normal_map[..., 1], None, -strength, strength, cv2.NORM_MINMAX)
33
+ normal_map[..., 2] = 1.0
34
+
35
+ # Add color influence (e.g., red affects X, green affects Y)
36
+ color_factor = color_influence * strength
37
+ normal_map[..., 0] += (img[..., 0] / 255.0 - 0.5) * color_factor
38
+ normal_map[..., 1] += (img[..., 1] / 255.0 - 0.5) * color_factor
39
+
40
+ # Normalize to unit vectors
41
  norm = np.linalg.norm(normal_map, axis=2, keepdims=True)
42
  normal_map = np.divide(normal_map, norm, out=np.zeros_like(normal_map), where=norm != 0)
 
43
  normal_map = (normal_map + 1) * 127.5
44
  normal_map = np.clip(normal_map, 0, 255).astype(np.uint8)
45
  return Image.fromarray(normal_map)
46
 
47
+ # Advanced Displacement Map with adaptive thresholding and edge enhancement
48
+ def generate_displacement_map(image, contrast=1.0, add_noise=False, noise_scale=0.1, edge_boost=1.0):
49
  img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
50
+ # Adaptive histogram equalization for better contrast
51
+ clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
52
+ img = clahe.apply(img)
53
  # Adjust contrast
54
  img = cv2.convertScaleAbs(img, alpha=contrast, beta=0)
55
+ # Edge enhancement with Laplacian
56
+ laplacian = cv2.Laplacian(img, cv2.CV_64F)
57
+ img = cv2.addWeighted(img, 1.0, laplacian, edge_boost, 0)
58
+ img = np.clip(img, 0, 255).astype(np.uint8)
59
+ # Optional Perlin noise
60
  if add_noise:
61
  height, width = img.shape
62
  noise_map = np.zeros((height, width), dtype=np.float32)
 
66
  img = cv2.add(img, noise_map.astype(np.uint8))
67
  return Image.fromarray(img)
68
 
69
+ # Advanced Roughness Map with frequency separation and texture analysis
70
+ def generate_roughness_map(image, invert=True, sharpness=1.0, detail_boost=0.5, frequency_weight=0.5):
71
  img = cv2.cvtColor(np.array(image), cv2.COLOR_RGB2GRAY)
72
+ # Frequency separation: Low-frequency (smooth) and high-frequency (detail)
73
+ low_freq = cv2.bilateralFilter(img, 9, 75, 75)
74
+ high_freq = cv2.subtract(img, low_freq)
75
+ # Combine with weight
76
+ img = cv2.addWeighted(low_freq, 1.0 - frequency_weight, high_freq, frequency_weight, 0)
77
  # Optional inversion
78
  if invert:
79
  img = 255 - img
80
+ # Sharpening and detail boost
81
  blurred = cv2.GaussianBlur(img, (5, 5), 0)
82
  img = cv2.addWeighted(img, 1.0 + sharpness, blurred, -sharpness, 0)
 
83
  img = cv2.addWeighted(img, 1.0 + detail_boost, blurred, -detail_boost, 0)
84
  return Image.fromarray(img)
85
 
86
+ # Process function with advanced parameters
87
+ def process_image(input_image, normal_strength=1.0, normal_blur=5, normal_bilateral=False, normal_color=0.3,
88
+ disp_contrast=1.0, disp_noise=False, disp_noise_scale=0.1, disp_edge=1.0,
89
+ rough_invert=True, rough_sharpness=1.0, rough_detail=0.5, rough_freq=0.5):
90
+ normal_map = generate_normal_map(input_image, strength=normal_strength, blur_size=normal_blur,
91
+ use_bilateral=normal_bilateral, color_influence=normal_color)
92
+ displacement_map = generate_displacement_map(input_image, contrast=disp_contrast, add_noise=disp_noise,
93
+ noise_scale=disp_noise_scale, edge_boost=disp_edge)
94
+ roughness_map = generate_roughness_map(input_image, invert=rough_invert, sharpness=rough_sharpness,
95
+ detail_boost=rough_detail, frequency_weight=rough_freq)
96
  return normal_map, displacement_map, roughness_map
97
 
98
  # Gradio Interface with advanced controls
 
102
  gr.Image(type="pil", label="Upload Image"),
103
  # Normal Map Controls
104
  gr.Slider(minimum=0.1, maximum=5.0, step=0.1, value=1.0, label="Normal Map Strength"),
105
+ gr.Slider(minimum=3, maximum=15, step=2, value=5, label="Normal Map Blur Size (odd numbers)"),
106
  gr.Checkbox(value=False, label="Use Bilateral Filter for Normal Map"),
107
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0.3, label="Normal Map Color Influence"),
108
  # Displacement Map Controls
109
  gr.Slider(minimum=0.5, maximum=2.0, step=0.1, value=1.0, label="Displacement Map Contrast"),
110
  gr.Checkbox(value=False, label="Add Noise to Displacement Map"),
111
  gr.Slider(minimum=0.05, maximum=0.5, step=0.05, value=0.1, label="Displacement Noise Scale"),
112
+ gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label="Displacement Edge Boost"),
113
  # Roughness Map Controls
114
  gr.Checkbox(value=True, label="Invert Roughness Map"),
115
  gr.Slider(minimum=0.0, maximum=2.0, step=0.1, value=1.0, label="Roughness Sharpness"),
116
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0.5, label="Roughness Detail Boost"),
117
+ gr.Slider(minimum=0.0, maximum=1.0, step=0.1, value=0.5, label="Roughness Frequency Weight")
118
  ],
119
  outputs=[
120
  gr.Image(type="pil", label="Normal Map"),
 
122
  gr.Image(type="pil", label="Roughness Map")
123
  ],
124
  title="Advanced Material Map Generator",
125
+ description="Upload an image to generate highly accurate Normal, Displacement, and Roughness maps with advanced controls."
126
  )
127
 
128
  interface.launch()