# Shadow Processor ## Overview The **Polygonal Shadow Processor** computes a realistic drop shadow for an image without requiring a depth map. It leverages a grayscale mask (if provided) or, if absent, the source image’s alpha channel to derive a polygon outline using a basic convex hull algorithm. The hull is then refined by removing the upper portion (using a bounding box strategy) to ensure the shadow appears only beneath the subject (for example, between the wheels and under the car). A grayscale shadow mask is created by filling the refined hull, followed by a Gaussian blur to soften the edges. Finally, the shadow mask is colorized with a specified RGBA color and can be composited with the original image. Geometry variables representing the shadow’s bounding box are also assigned. --- ## Example Usage ```yaml - processor: processor: "shadow" inputs: source: "input/input.png" # Input image (RGBA) mask: "input/mask.png" # (Optional) Grayscale mask image defining the subject silhouette. If omitted, the processor uses the alpha channel of the source. params: color: "rgba(0, 0, 0, 0.9)" # Base shadow color in RGBA; determines maximum opacity. blur_radius: 15.0 # Gaussian blur radius to soften shadow edges. annotate: "false" # If true, draw debug outlines for troubleshooting. assigns: # Computed geometry values for later use. left: "shadow_left" # X-coordinate of the left edge of the shadow region. top: "shadow_top" # Y-coordinate of the top edge of the shadow region. width: "shadow_width" # Width of the shadow region. height: "shadow_height" # Height of the shadow region. right: "shadow_right" # X-coordinate of the right edge (left + width). bottom: "shadow_bottom" # Y-coordinate of the bottom edge (top + height). outputs: composite: "output/shadowed.png" # Output image: original image composited with shadow. shadow: "output/shadow.png" # Output image: standalone shadow layer (RGBA). ``` --- ## Inputs | **Key** | **Required** | **Description** | | -------- | -----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `source` | **Yes** | Filepath to the input image in RGBA format. | | `mask` | **No** | _(Optional)_ Filepath to the grayscale mask image defining the subject silhouette. If omitted, the processor uses the alpha channel of the source image. | --- ## Params | **Key** | **Type** | **Default** | **Description** | | ------------- | --------- | ---------------------- | ---------------------------------------------------------------------------------- | | `color` | `str` | `"rgba(0, 0, 0, 0.9)"` | Base shadow color in RGBA; determines the maximum opacity of the generated shadow. | | `blur_radius` | `float` | `15.0` | Gaussian blur radius applied to the shadow mask to soften its edges. | | `annotate` | `boolean` | `"false"` | If true, annotate the output (e.g., draw polygon outlines) for debugging purposes. | --- ## Outputs | **Key** | **Required** | **Description** | | ----------- | -------------------------- | ------------------------------------------------------------------ | | `composite` | (if both outputs provided) | Filepath to the output PNG image composited with the source image. | | `shadow` | (if both outputs provided) | Filepath to the standalone output shadow layer (RGBA). | --- ## Processing Details 1. **Input Loading:** - Load the source image (converted to RGBA) and, if provided, the mask image (converted to grayscale). If no mask is supplied, extract the alpha channel from the source image to serve as the mask. 2. **Mask-to-Polygon Conversion:** - Convert the grayscale mask to a binary image using a threshold. - Extract edge points from the binary mask and compute a basic convex hull of these points to obtain a polygon outlining the subject. 3. **Refining the Convex Hull:** - Compute the bounding box of the mask (or convex hull). - Remove or clear the upper portion of the convex hull (for example, by setting a cutoff at a fixed percentage of the bounding box height) to ensure the shadow does not extend above the subject (e.g., above the car). 4. **Shadow Mask Creation:** - Create a blank grayscale image (mode "L") with the same dimensions as the source image. - Fill the refined polygon (from step 3) on this canvas to produce a preliminary shadow mask. - Apply a Gaussian blur (using the specified `blur_radius`) to soften the shadow edges. 5. **Clearing the Subject from the Shadow:** - Use the original mask to remove the shadow that appears within the subject. This ensures that the shadow is only present outside or beneath the object. 6. **Colorizing the Shadow:** - Generate a final RGBA shadow image by taking the RGB values directly from the shadow `color` parameter. - For each pixel, compute the alpha channel as the product of the normalized shadow color’s alpha and the normalized value from the blurred shadow mask. 7. **Output Composition:** - If compositing is desired, alpha-composite the colorized shadow onto the source image to create the final composite output. - Save both the standalone shadow layer and the composite image to their respective output filepaths. 8. **Assigning Geometry Variables:** - Calculate the bounding box of the final shadow mask. - Assign the coordinates (left, top, right, bottom) and dimensions (width, height) to the variables specified in the `assigns:` block. 9. **Annotation (Optional):** - If `annotate` is true, draw debugging outlines (e.g., the convex hull, bounding box, or original polygon) on the composite image to assist in troubleshooting.