LeafCat79 commited on
Commit
0fe8502
verified
1 Parent(s): 7541208

Reject non-studio cutout attempts

Browse files
Files changed (2) hide show
  1. README.md +2 -2
  2. app.py +28 -1
README.md CHANGED
@@ -67,7 +67,7 @@ If a requested asset has no deterministic hook, images are still generated for r
67
 
68
  ## Contract-driven generation and validation
69
 
70
- Filenames and IDs do not decide whether an image is a scene or sprite. Dimensions, transparency, composition, camera, quantity, subject count, and silhouette requirements come from the manifest. Transparent single-subject outputs receive alpha extraction, occupancy normalization, subject-count checks, and a retained-scene check that rejects environmental foreground spread around an isolated subject. Opaque outputs are checked for unwanted transparency. Seamless requests receive an opposite-edge similarity check. Other compositions are not incorrectly rejected for containing multiple subjects.
71
 
72
  The image model can still violate these instructions, so every result requires visual review. Single-subject outputs that fail automated checks are regenerated with a fresh seed rather than cropped into a guessed subject. The review UI can regenerate one output or a complete multi-output asset set.
73
 
@@ -89,7 +89,7 @@ segmind/SSD-1B + latent-consistency/lcm-lora-ssd-1b
89
 
90
  SSD-1B is an Apache-2.0 distilled SDXL model. The LCM adapter enables low-step generation. The weights run inside the Space's ZeroGPU allocation, so the app does not consume Hugging Face Inference Provider credits and does not require a paid image API.
91
 
92
- Sprites and backgrounds are generated directly from their written prompts. No procedurally drawn sprite, palette, silhouette, camera guide, or background layout is passed into the production model. Sprite prompts use a portrait canvas and positive single-subject composition language; the negative prompt separately rejects sheets, lineups, repeated subjects, multiple views, and surrounding environments. After transparency extraction, sprites with zero or multiple significant foreground components, retained scene-like alpha, implausible silhouettes, or inadequate scale are regenerated with a new seed up to `PRIMARY_SPRITE_ATTEMPTS` times. If every attempt fails, the deployed Space returns an explicit model-generation error rather than returning a contact sheet or environment-contaminated cutout. Background negative prompts reject characters and generic particle overlays.
93
 
94
  SSD-1B's CLIP text encoder has a 77-token context window. Production prompts therefore use a conservative word budget, place the camera and single-subject contract first, and compact the free-form description. This prevents those critical constraints from being silently truncated behind verbose style text.
95
 
 
67
 
68
  ## Contract-driven generation and validation
69
 
70
+ Filenames and IDs do not decide whether an image is a scene or sprite. Dimensions, transparency, composition, camera, quantity, subject count, and silhouette requirements come from the manifest. Transparent single-subject outputs must first arrive from the model on a plain light studio field; scene-like model frames are rejected before alpha extraction. Passing outputs then receive alpha extraction, occupancy normalization, subject-count checks, and a retained-scene check that rejects environmental foreground spread around an isolated subject. Opaque outputs are checked for unwanted transparency. Seamless requests receive an opposite-edge similarity check. Other compositions are not incorrectly rejected for containing multiple subjects.
71
 
72
  The image model can still violate these instructions, so every result requires visual review. Single-subject outputs that fail automated checks are regenerated with a fresh seed rather than cropped into a guessed subject. The review UI can regenerate one output or a complete multi-output asset set.
73
 
 
89
 
90
  SSD-1B is an Apache-2.0 distilled SDXL model. The LCM adapter enables low-step generation. The weights run inside the Space's ZeroGPU allocation, so the app does not consume Hugging Face Inference Provider credits and does not require a paid image API.
91
 
92
+ Sprites and backgrounds are generated directly from their written prompts. No procedurally drawn sprite, palette, silhouette, camera guide, or background layout is passed into the production model. Sprite prompts use a portrait canvas and positive single-subject composition language; the negative prompt separately rejects sheets, lineups, repeated subjects, multiple views, and surrounding environments. Before alpha extraction, cutout attempts whose boundary is not predominantly light and neutral are rejected because they did not honor the requested studio field. After transparency extraction, sprites with zero or multiple significant foreground components, retained scene-like alpha, implausible silhouettes, or inadequate scale are regenerated with a new seed up to `PRIMARY_SPRITE_ATTEMPTS` times. If every attempt fails, the deployed Space returns an explicit model-generation error rather than returning a contact sheet or environment-contaminated cutout. Background negative prompts reject characters and generic particle overlays.
93
 
94
  SSD-1B's CLIP text encoder has a 77-token context window. Production prompts therefore use a conservative word budget, place the camera and single-subject contract first, and compact the free-form description. This prevents those critical constraints from being silently truncated behind verbose style text.
95
 
app.py CHANGED
@@ -2016,6 +2016,9 @@ def primary_diffusion_png(spec: AssetSpec, index: int, run_id: int) -> tuple[byt
2016
  width=width,
2017
  height=height,
2018
  ).images[0]
 
 
 
2019
  content = polish_diffusion_asset(image, spec)
2020
  if is_background:
2021
  return content, None
@@ -2145,6 +2148,30 @@ def polish_diffusion_asset(image: Image.Image, spec: AssetSpec) -> bytes:
2145
  return out.getvalue()
2146
 
2147
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2148
  def foreground_component_geometry_from_image(image: Image.Image) -> list[tuple[int, tuple[int, int, int, int]]]:
2149
  """Return alpha-component areas and bounding boxes for an RGBA image, largest first."""
2150
  image = image.convert("RGBA")
@@ -2810,7 +2837,7 @@ def model_configuration_summary() -> str:
2810
  f"neural enforcement: `{enforcement}` 路 primary readiness: `{readiness}`. "
2811
  "Every production image is generated directly from its written prompt by the primary text-to-image model. "
2812
  "The user-defined composition and camera contract is placed first inside a conservative CLIP prompt budget. "
2813
- "Transparent single-subject foregrounds are normalized to the requested canvas, then pass configured subject-count, "
2814
  "retained-scene, silhouette, and scale validation; failures are regenerated with a new seed up to "
2815
  f"{PRIMARY_SPRITE_ATTEMPTS} times. No procedural guide is supplied to the model. The procedural renderer is "
2816
  "development-only and is blocked in the deployed Space when the primary model fails."
 
2016
  width=width,
2017
  height=height,
2018
  ).images[0]
2019
+ if not is_background and has_invalid_cutout_studio_field(image):
2020
+ last_failure_detail = "the last output did not use the required plain light studio field"
2021
+ continue
2022
  content = polish_diffusion_asset(image, spec)
2023
  if is_background:
2024
  return content, None
 
2148
  return out.getvalue()
2149
 
2150
 
2151
+ def has_invalid_cutout_studio_field(image: Image.Image) -> bool:
2152
+ """Reject model scenes before alpha extraction when their outer field is not light and neutral.
2153
+
2154
+ Transparent cutouts are prompted on a plain white studio field. When SSD-1B
2155
+ instead puts foliage or another environment at the image boundary, the old
2156
+ corner-color extraction treated that scenery as the background and preserved
2157
+ the scene's lighter interior. Validate the model image itself so a new model
2158
+ attempt is requested before any transparency or scale post-processing.
2159
+ """
2160
+ sample = image.convert("RGB").resize((64, 64), Image.LANCZOS)
2161
+ band = 5
2162
+ edge_pixels = []
2163
+ for y in range(64):
2164
+ for x in range(64):
2165
+ if x < band or x >= 64 - band or y < band or y >= 64 - band:
2166
+ edge_pixels.append(sample.getpixel((x, y)))
2167
+
2168
+ light_neutral = sum(
2169
+ min(pixel) >= 180 and max(pixel) - min(pixel) <= 70
2170
+ for pixel in edge_pixels
2171
+ )
2172
+ return light_neutral / max(1, len(edge_pixels)) < 0.72
2173
+
2174
+
2175
  def foreground_component_geometry_from_image(image: Image.Image) -> list[tuple[int, tuple[int, int, int, int]]]:
2176
  """Return alpha-component areas and bounding boxes for an RGBA image, largest first."""
2177
  image = image.convert("RGBA")
 
2837
  f"neural enforcement: `{enforcement}` 路 primary readiness: `{readiness}`. "
2838
  "Every production image is generated directly from its written prompt by the primary text-to-image model. "
2839
  "The user-defined composition and camera contract is placed first inside a conservative CLIP prompt budget. "
2840
+ "Transparent single-subject attempts must first honor the light studio-field contract, are normalized to the requested canvas, then pass configured subject-count, "
2841
  "retained-scene, silhouette, and scale validation; failures are regenerated with a new seed up to "
2842
  f"{PRIMARY_SPRITE_ATTEMPTS} times. No procedural guide is supplied to the model. The procedural renderer is "
2843
  "development-only and is blocked in the deployed Space when the primary model fails."