Marcel0123 commited on
Commit
67fcd2f
Β·
verified Β·
1 Parent(s): 98ce8b0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +45 -38
app.py CHANGED
@@ -1,9 +1,8 @@
1
- # app.py (CPU-optimized v3)
2
- # Neurale netwerken als tekenaars β€” ControlNet (scribble) demo voor CPU
3
- # Wijzigingen:
4
- # - Verwijderd: Image(..., tool="sketch") β†’ niet ondersteund in jouw Gradio-versie
5
- # - Gebruikt gr.Sketchpad (retourneert RGBA-numpy), met robuuste conversie
6
- # - CPU optimalisaties: 512px, DPMSolver, 12 steps, attention_slicing, single-queue
7
 
8
  import os, random, numpy as np
9
  from typing import Optional
@@ -16,12 +15,14 @@ from diffusers import (
16
  DPMSolverMultistepScheduler,
17
  )
18
 
 
19
  MODEL_BASE = os.environ.get("SD_BASE_MODEL", "runwayml/stable-diffusion-v1-5")
20
  MODEL_CN = os.environ.get("CN_SCRIBBLE_MODEL", "lllyasviel/sd-controlnet-scribble")
21
 
22
- DEVICE = "cpu" # geforceerd CPU
23
  DTYPE = torch.float32
24
- TARGET_SIZE = 512 # lager = sneller op CPU
 
25
 
26
  pipe: Optional[StableDiffusionControlNetPipeline] = None
27
 
@@ -33,9 +34,8 @@ def _lazy_load_pipeline():
33
  pipe = StableDiffusionControlNetPipeline.from_pretrained(
34
  MODEL_BASE, controlnet=controlnet, torch_dtype=DTYPE, safety_checker=None
35
  )
36
- # Snellere scheduler (minder stappen nodig)
37
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
38
- # CPU-optimalisaties
39
  pipe = pipe.to(DEVICE)
40
  pipe.enable_attention_slicing()
41
  return pipe
@@ -45,11 +45,9 @@ def to_rgba(img):
45
  if img is None:
46
  return None
47
  if isinstance(img, np.ndarray):
48
- # Sketchpad geeft HxWx4 (RGBA) of HxWx3 terug
49
  if img.dtype != np.uint8:
50
  img = img.astype(np.uint8)
51
- pil = Image.fromarray(img)
52
- return pil.convert("RGBA")
53
  if isinstance(img, Image.Image):
54
  return img.convert("RGBA")
55
  try:
@@ -58,28 +56,29 @@ def to_rgba(img):
58
  return None
59
 
60
  def rgba_to_scribble(img) -> Image.Image:
61
- """Zet RGBA schets om naar zwart-op-wit scribble, vierkant 512x512."""
62
  img = to_rgba(img)
63
  if img is None:
64
  return None
65
  # transparant β†’ wit
66
- bg = Image.new("RGBA", img.size, (255,255,255,255))
67
  img = Image.alpha_composite(bg, img)
68
  # grijs + drempel
69
  arr = np.array(img.convert("L"))
70
- thr = max(25, int(arr.mean()*0.9))
71
  lines = arr < thr
72
- out = np.full((*arr.shape,3), 255, dtype=np.uint8)
73
- out[lines] = (0,0,0)
74
  scribble = Image.fromarray(out, "RGB")
75
  # vierkant + resize
76
  m = max(scribble.width, scribble.height)
77
- sq = Image.new("RGB", (m,m), (255,255,255))
78
- sq.paste(scribble, ((m-scribble.width)//2, (m-scribble.height)//2))
79
  return sq.resize((TARGET_SIZE, TARGET_SIZE), Image.BICUBIC)
80
 
81
- def run(drawing, prompt, negative_prompt, guidance_scale=7.0,
82
- controlnet_conditioning_scale=1.0, num_inference_steps=12, seed=-1):
 
83
  if drawing is None:
84
  raise gr.Error("Teken eerst iets of gebruik de voorbeeld-schets.")
85
  cn_image = rgba_to_scribble(drawing)
@@ -89,12 +88,14 @@ def run(drawing, prompt, negative_prompt, guidance_scale=7.0,
89
  if not prompt or not str(prompt).strip():
90
  prompt = "clean pencil sketch, coherent completion, subtle shading, high quality"
91
  if seed is None or int(seed) < 0:
92
- seed = random.randint(0, 2**31-1)
93
  gen = torch.Generator(device=DEVICE).manual_seed(int(seed))
94
 
95
  p = _lazy_load_pipeline()
96
- full_prompt = ("black pencil sketch, clean lines, coherent shape completion, subtle shading, "
97
- "consistent with the input scribble, " + prompt)
 
 
98
  result = p(
99
  prompt=full_prompt,
100
  negative_prompt=negative_prompt or "text, watermark, extra limbs, low quality, distorted face, nsfw",
@@ -106,14 +107,18 @@ def run(drawing, prompt, negative_prompt, guidance_scale=7.0,
106
  )
107
  image = result.images[0]
108
  pad = 12
109
- combo = Image.new("RGB", (cn_image.width*2+pad, cn_image.height), (245,245,245))
110
- combo.paste(cn_image, (0,0)); combo.paste(image, (cn_image.width+pad, 0))
 
111
  return image, cn_image, combo, f"Seed: {seed}, steps: {num_inference_steps}"
112
 
113
  def make_example_scribble() -> Image.Image:
 
114
  w, h = 360, 360
115
- img = Image.new("RGBA", (w,h), (0,0,0,0)); d = ImageDraw.Draw(img)
116
- d.line([(100,300),(90,230),(110,170),(160,140),(200,140),(260,170),(280,230),(260,300),(180,320),(100,300)],
 
 
117
  fill=(0,0,0,255), width=12)
118
  d.line([(200,140),(210,110)], fill=(0,0,0,255), width=10)
119
  d.line([(210,110),(250,120),(265,150)], fill=(0,0,0,255), width=9)
@@ -121,8 +126,9 @@ def make_example_scribble() -> Image.Image:
121
 
122
  CSS = ".gradio-container{max-width:1100px} #combo img{border-radius:10px}"
123
 
124
- with gr.Blocks(title="πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU v3)", css=CSS, theme=gr.themes.Soft()) as demo:
125
  gr.Markdown("## πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU)\nTeken links of klik **Voorbeeld-schets**; AI vult aan met Stable Diffusion + ControlNet (scribble).")
 
126
  with gr.Row():
127
  with gr.Column():
128
  canvas = gr.Sketchpad(label="Schets (teken in zwart op transparant/wit)", height=420)
@@ -131,20 +137,21 @@ with gr.Blocks(title="πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU v3)", css=CSS
131
  with gr.Accordion("Geavanceerd", open=False):
132
  guidance_scale = gr.Slider(5.0, 10.0, value=7.0, step=0.5, label="Guidance scale")
133
  cn_strength = gr.Slider(0.6, 1.6, value=1.0, step=0.05, label="ControlNet conditioning scale")
134
- steps = gr.Slider(6, 25, value=12, step=1, label="Aantal diffusion-steps")
135
  seed = gr.Number(value=-1, precision=0, label="Seed (-1 = random)")
136
  with gr.Row():
137
  run_btn = gr.Button("Vervolledig ✨", variant="primary")
138
  example_btn = gr.Button("Voorbeeld-schets", variant="secondary")
 
139
  with gr.Column():
140
- out_img = gr.Image(label="Vervolledigde tekening", interactive=False)
141
- cn_prev = gr.Image(label="Scribble (input voor AI)", interactive=False)
142
- combo = gr.Image(label="Vergelijking (links: input, rechts: AI)", elem_id="combo")
143
- meta = gr.Markdown()
144
 
145
  def fill_and_run(p, n, gs, cs, st, sd):
146
  img = make_example_scribble()
147
- a,b,c,d = run(img, p, n, gs, cs, st, sd)
148
  return img, a, b, c, d
149
 
150
  run_btn.click(run, inputs=[canvas, prompt, negative_prompt, guidance_scale, cn_strength, steps, seed],
@@ -152,7 +159,7 @@ with gr.Blocks(title="πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU v3)", css=CSS
152
  example_btn.click(fill_and_run, inputs=[prompt, negative_prompt, guidance_scale, cn_strength, steps, seed],
153
  outputs=[canvas, out_img, cn_prev, combo, meta])
154
 
155
- # Belangrijk op CPU: geen parallelle jobs
156
- demo.queue(concurrency_count=1, max_size=8)
157
  if __name__ == "__main__":
158
  demo.launch()
 
1
+ # app.py (v4, CPU-optimized + brede Gradio-compat)
2
+ # Neurale netwerken als tekenaars β€” Stable Diffusion + ControlNet (scribble)
3
+ # - Werkt op CPU (langzamer dan GPU, maar demowaardig)
4
+ # - Gebruikt gr.Sketchpad (compatibel met oudere Gradio-versies)
5
+ # - Geen queue-parameters (demo.queue() zonder args)
 
6
 
7
  import os, random, numpy as np
8
  from typing import Optional
 
15
  DPMSolverMultistepScheduler,
16
  )
17
 
18
+ # Modellen (kun je via Space Secrets/Opsional env-vars overriden)
19
  MODEL_BASE = os.environ.get("SD_BASE_MODEL", "runwayml/stable-diffusion-v1-5")
20
  MODEL_CN = os.environ.get("CN_SCRIBBLE_MODEL", "lllyasviel/sd-controlnet-scribble")
21
 
22
+ DEVICE = "cpu" # geforceerd CPU
23
  DTYPE = torch.float32
24
+ TARGET_SIZE = 512 # lager = sneller op CPU
25
+ DEFAULT_STEPS = 12 # CPU-vriendelijk
26
 
27
  pipe: Optional[StableDiffusionControlNetPipeline] = None
28
 
 
34
  pipe = StableDiffusionControlNetPipeline.from_pretrained(
35
  MODEL_BASE, controlnet=controlnet, torch_dtype=DTYPE, safety_checker=None
36
  )
37
+ # Snellere scheduler β†’ minder stappen nodig
38
  pipe.scheduler = DPMSolverMultistepScheduler.from_config(pipe.scheduler.config)
 
39
  pipe = pipe.to(DEVICE)
40
  pipe.enable_attention_slicing()
41
  return pipe
 
45
  if img is None:
46
  return None
47
  if isinstance(img, np.ndarray):
 
48
  if img.dtype != np.uint8:
49
  img = img.astype(np.uint8)
50
+ return Image.fromarray(img).convert("RGBA")
 
51
  if isinstance(img, Image.Image):
52
  return img.convert("RGBA")
53
  try:
 
56
  return None
57
 
58
  def rgba_to_scribble(img) -> Image.Image:
59
+ """Zet RGBA schets om naar zwart-op-wit, vierkant en resized (TARGET_SIZE)."""
60
  img = to_rgba(img)
61
  if img is None:
62
  return None
63
  # transparant β†’ wit
64
+ bg = Image.new("RGBA", img.size, (255, 255, 255, 255))
65
  img = Image.alpha_composite(bg, img)
66
  # grijs + drempel
67
  arr = np.array(img.convert("L"))
68
+ thr = max(25, int(arr.mean() * 0.9))
69
  lines = arr < thr
70
+ out = np.full((*arr.shape, 3), 255, dtype=np.uint8)
71
+ out[lines] = (0, 0, 0)
72
  scribble = Image.fromarray(out, "RGB")
73
  # vierkant + resize
74
  m = max(scribble.width, scribble.height)
75
+ sq = Image.new("RGB", (m, m), (255, 255, 255))
76
+ sq.paste(scribble, ((m - scribble.width) // 2, (m - scribble.height) // 2))
77
  return sq.resize((TARGET_SIZE, TARGET_SIZE), Image.BICUBIC)
78
 
79
+ def run(drawing, prompt, negative_prompt,
80
+ guidance_scale=7.0, controlnet_conditioning_scale=1.0,
81
+ num_inference_steps=DEFAULT_STEPS, seed=-1):
82
  if drawing is None:
83
  raise gr.Error("Teken eerst iets of gebruik de voorbeeld-schets.")
84
  cn_image = rgba_to_scribble(drawing)
 
88
  if not prompt or not str(prompt).strip():
89
  prompt = "clean pencil sketch, coherent completion, subtle shading, high quality"
90
  if seed is None or int(seed) < 0:
91
+ seed = random.randint(0, 2**31 - 1)
92
  gen = torch.Generator(device=DEVICE).manual_seed(int(seed))
93
 
94
  p = _lazy_load_pipeline()
95
+ full_prompt = (
96
+ "black pencil sketch, clean lines, coherent shape completion, subtle shading, "
97
+ "consistent with the input scribble, " + prompt
98
+ )
99
  result = p(
100
  prompt=full_prompt,
101
  negative_prompt=negative_prompt or "text, watermark, extra limbs, low quality, distorted face, nsfw",
 
107
  )
108
  image = result.images[0]
109
  pad = 12
110
+ combo = Image.new("RGB", (cn_image.width * 2 + pad, cn_image.height), (245, 245, 245))
111
+ combo.paste(cn_image, (0, 0))
112
+ combo.paste(image, (cn_image.width + pad, 0))
113
  return image, cn_image, combo, f"Seed: {seed}, steps: {num_inference_steps}"
114
 
115
  def make_example_scribble() -> Image.Image:
116
+ """Kleine voorbeeldschets (appelvorm) voor snelle test."""
117
  w, h = 360, 360
118
+ img = Image.new("RGBA", (w, h), (0, 0, 0, 0))
119
+ d = ImageDraw.Draw(img)
120
+ d.line([(100,300),(90,230),(110,170),(160,140),(200,140),
121
+ (260,170),(280,230),(260,300),(180,320),(100,300)],
122
  fill=(0,0,0,255), width=12)
123
  d.line([(200,140),(210,110)], fill=(0,0,0,255), width=10)
124
  d.line([(210,110),(250,120),(265,150)], fill=(0,0,0,255), width=9)
 
126
 
127
  CSS = ".gradio-container{max-width:1100px} #combo img{border-radius:10px}"
128
 
129
+ with gr.Blocks(title="πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU v4)", css=CSS) as demo:
130
  gr.Markdown("## πŸ–ŒοΈ Neurale netwerken als tekenaars (CPU)\nTeken links of klik **Voorbeeld-schets**; AI vult aan met Stable Diffusion + ControlNet (scribble).")
131
+
132
  with gr.Row():
133
  with gr.Column():
134
  canvas = gr.Sketchpad(label="Schets (teken in zwart op transparant/wit)", height=420)
 
137
  with gr.Accordion("Geavanceerd", open=False):
138
  guidance_scale = gr.Slider(5.0, 10.0, value=7.0, step=0.5, label="Guidance scale")
139
  cn_strength = gr.Slider(0.6, 1.6, value=1.0, step=0.05, label="ControlNet conditioning scale")
140
+ steps = gr.Slider(6, 25, value=DEFAULT_STEPS, step=1, label="Aantal diffusion-steps")
141
  seed = gr.Number(value=-1, precision=0, label="Seed (-1 = random)")
142
  with gr.Row():
143
  run_btn = gr.Button("Vervolledig ✨", variant="primary")
144
  example_btn = gr.Button("Voorbeeld-schets", variant="secondary")
145
+
146
  with gr.Column():
147
+ out_img = gr.Image(label="Vervolledigde tekening", interactive=False)
148
+ cn_prev = gr.Image(label="Scribble (input voor AI)", interactive=False)
149
+ combo = gr.Image(label="Vergelijking (links: input, rechts: AI)", elem_id="combo")
150
+ meta = gr.Markdown()
151
 
152
  def fill_and_run(p, n, gs, cs, st, sd):
153
  img = make_example_scribble()
154
+ a, b, c, d = run(img, p, n, gs, cs, st, sd)
155
  return img, a, b, c, d
156
 
157
  run_btn.click(run, inputs=[canvas, prompt, negative_prompt, guidance_scale, cn_strength, steps, seed],
 
159
  example_btn.click(fill_and_run, inputs=[prompt, negative_prompt, guidance_scale, cn_strength, steps, seed],
160
  outputs=[canvas, out_img, cn_prev, combo, meta])
161
 
162
+ demo.queue() # zonder parameters: compatibel met oudere Gradio-versies
163
+
164
  if __name__ == "__main__":
165
  demo.launch()