Install
openclaw skills install @guoxh/smart-photo-editorAI-powered photo editing and restoration skill - smart object removal, background removal, old photo restoration, and basic edits.
openclaw skills install @guoxh/smart-photo-editorAI-powered photo editing and restoration skill for OpenClaw. Unifies Seedream (AI edits), ImageMagick (basic edits), and OpenCV (programmatic fixes) into one intuitive workflow.
All-in-one intelligent photo editing skill - automatically selects the best tool for each image processing task.
✨ Key Advantages:
This skill provides two tiers of functionality:
These features only require ImageMagick and/or OpenCV (both widely available on Linux/macOS):
inpaint.py)These features require the byted-ark-seedream-skill (VolcEngine Ark Agent Plan, managed skill):
replace-scene) — put subject into a new scene via multi-reference fusionNote: The
byted-ark-seedream-skillis an OpenClaw managed skill that requires a VolcEngine Ark account with the Seedream model enabled. Install withopenclaw skills install byted-ark-seedream-skill.
Activates automatically when users mention keywords like:
The skill mixes three classes of tool. Picking the right one for each task is what makes the unified entry-point useful, so the routing is explicit:
Use Seedream first for semantic / generative edits.
For these, Seedream is the value-add. OpenCV/ImageMagick can’t compete on quality, and a deterministic tool can’t “invent” plausible content.
Use deterministic tools first for mechanical edits.
inpaint.py directly)For these, Seedream would be slower, costlier, and less predictable.
Encoded policy (auto mode):
semantic edit / restoration / object removal → Seedream first; deterministic fallback
mechanical edit / resize / crop / compress / color → deterministic tools first
user explicitly asks for AI / natural restoration → Seedream
user explicitly forces a tool with --tool ... → honored verbatim
Per-task defaults (--tool auto):
| Task | Default | Notes |
|---|---|---|
remove-object | Seedream | OpenCV branch only fires when Seedream is unavailable; redirects to inpaint.py for known-geometry cases |
restore | Seedream | Seedream-only operation by design |
remove-background | rembg | ImageMagick fallback for solid-color backgrounds when rembg is missing |
resize / crop / color-adjust | OpenCV/ImageMagick | Deterministic, instant, free |
smart-compress | OpenCV | Content-aware quality + format selection |
perspective-correct | OpenCV | Document/whiteboard correction |
hdr-tonemap | OpenCV | All four modes (auto / bilateral / log / shadows) are deterministic |
replace-scene | Seedream | AI-only; no deterministic fallback (would produce poor results). If Seedream is unavailable, returns error directing user to install the Seedream skill. |
Override with --tool seedream | opencv | imagemagick | rembg.
~/.openclaw/skills/smart-photo-editor/
All Python scripts (scripts/*.py) use a portable #!/usr/bin/env python3 shebang.
You can run them directly:
./scripts/edit.py --help
Or explicitly with your Python of choice (e.g. a virtualenv where you have installed the dependencies below):
python3 scripts/edit.py --help
Make sure the Python interpreter you use has the required dependencies
(OpenCV, Pillow, NumPy). Optional deps (piexif, exif, rembg) add extra
features; the skill will gracefully skip those features if they are missing.
# Sanity check — required deps\python3 -c "import cv2, numpy, PIL; print('core deps ok')"
# Sanity check — full deps (includes optional rembg/piexif/exif)
python3 -c "import cv2, numpy, PIL, piexif, exif, rembg; print('all deps ok')"
| Dependency | Required | Purpose | Installation |
|---|---|---|---|
| byted-ark-seedream-skill | ✅ Required | AI object removal, old photo restoration, image-to-image editing | Requires VolcEngine Ark API access. Follow official setup guide to enable Seedream model access |
| imagemagick | ✅ Required | Basic image editing (resize, crop, format conversion, color adjustments) | sudo apt install imagemagick (Debian/Ubuntu) or brew install imagemagick (macOS) |
| opencv-python-headless | ✅ Required | Wire removal, spot removal, image resizing | pip install opencv-python-headless |
| rembg | ⚠️ Optional | AI-powered background removal (better results for complex scenes) | pip install rembg |
| piexif | ⚠️ Optional | EXIF metadata preservation during edits | pip install piexif |
| exif | ⚠️ Optional | Extended EXIF tag reading | pip install exif |
source ~/.openclaw/venv-clawd/bin/activate
pip install rembg piexif exif
When a reference image (subject or scene image) exceeds 1.5 MB, the skill can upload it to Cloudflare R2 instead of embedding it as a base64 data URI. This avoids hitting Seedream API payload size limits.
R2 is optional. Without configuration, large images fall back to base64 data URI (which may fail for very large files due to CLI argument limits).
To enable R2 upload, deploy your own Cloudflare Worker:
| Variable | Required | Description |
|---|---|---|
SEEDREAM_UPLOAD_TOKEN | ✅ Yes | Bearer token for your R2 upload worker. |
SEEDREAM_UPLOAD_WORKER_URL | ✅ Yes | Your worker URL, e.g. https://your-worker.your-subdomain.workers.dev. |
# Add to your shell profile or ~/.openclaw/.env
export SEEDREAM_UPLOAD_TOKEN="your-token-here"
export SEEDREAM_UPLOAD_WORKER_URL="https://your-worker.your-subdomain.workers.dev"
Without both variables, large images gracefully fall back to the data URI path (works for most cases; may hit CLI arg limits for very large multi-image batches).
For AI editing features (object removal, photo restoration), ensure:
See the official VolcEngine Ark documentation for detailed setup instructions.
Primary Tool: Seedream Image-to-Image
Fallback Tool: OpenCV Inpainting (small scratches/lines)
Usage:
# AI method (recommended) - complex scenes
image_generate \
model="byted-ark-seedream-skill" \
mode="image-to-image" \
image="/path/to/photo.jpg" \
reference_strength=0.85 \
prompt="Remove the [object description] located at [location description]. Restore the seamless texture, keep everything else exactly the same."
OpenCV method — simple lines/minor imperfections:
# Remove horizontal wire
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type wire --y 760 --thickness 10
# Remove diagonal/angled line (supports any angle)
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type line --x1 100 --y1 200 --x2 500 --y2 400 --thickness 3
# Remove rectangular region (watermarks, logos, text)
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type rect --x 50 --y 50 --w 400 --h 80 --feather 5
# Remove multiple sensor dust spots in one command
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type spots --spots "100,150,8;200,300,10;50,400,6"
# Remove multiple lines in one command
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type lines --lines "0,100,800,100,3;100,200,500,400,5"
# Batch processing from JSON config
./scripts/inpaint.py /path/to/photo.jpg /path/to/output.jpg \
--type batch --batch tasks.json
# JSON config example (tasks.json):
# {
# "operations": [
# {"type": "spot", "x": 100, "y": 150, "radius": 8},
# {"type": "spot", "x": 200, "y": 300, "radius": 10},
# {"type": "wire", "y": 500, "thickness": 5},
# {"type": "rect", "x": 50, "y": 50, "w": 200, "h": 50, "feather": 10}
# ]
# }
Algorithm Selection:
ns (Navier-Stokes) - Better for textures and larger regions (default for wire/line)telea (Telea) - Faster, better for small regions (default for spot)
Use --algo ns or --algo telea to override the default selection.Prompt Optimization Examples:
Primary Tool: rembg (AI)
Fallback Tool: ImageMagick (inline – solid color backgrounds)
Usage:
# rembg AI method (complex backgrounds)
rembg i input.jpg output.png
# ImageMagick method (solid color backgrounds)
./scripts/remove_bg.sh input.png output.png 20 "#FFFFFF"
Primary Tool: Seedream Image-to-Image
Usage:
image_generate \
model="byted-ark-seedream-skill" \
mode="image-to-image" \
image="/path/to/old_photo.jpg" \
reference_strength=0.7 \
prompt="Restore this old photo. Remove all scratches, dust spots, and damage. Enhance clarity and contrast. Restore natural, vivid colors while preserving the original photo's character. Do not change the composition or subjects."
Primary Tool: ImageMagick + OpenCV
Common Commands:
# Resize
convert input.jpg -resize 1920x1920\> output.jpg
# Crop
convert input.jpg -crop 800x600+100+50 output.jpg
# Format conversion + compression
convert input.png -quality 85 output.webp
# Color adjustment
convert input.jpg -brightness-contrast 10x5 output.jpg # Brighter, higher contrast
convert input.jpg -modulate 100,130,100 output.jpg # Increase saturation
convert input.jpg -grayscale Rec709Luma output.jpg # Convert to B&W
OpenCV Operations (inpaint.py):
# Denoise (reduce noise in low-light photos)
./scripts/inpaint.py input.jpg output.jpg --type denoise --strength 15
# Sharpen (enhance edges and focus)
./scripts/inpaint.py input.jpg output.jpg --type sharpen --strength 1.5
# Brightness/contrast/gamma adjustment
./scripts/inpaint.py input.jpg output.jpg --type adjust --brightness 15 --contrast 10 --gamma 0.9
Primary Tool: OpenCV (face detection + image processing)
Dependencies: opencv-python-headless (already required)
Portrait retouching provides face-aware enhancements for portrait photography:
# Skin smoothing only
./scripts/portrait.py input.jpg output.jpg --smooth 3
# All enhancements (balanced)
./scripts/portrait.py input.jpg output.jpg --all
# Subtle preset (conservative)
./scripts/portrait.py input.jpg output.jpg --subtle
# Custom combination
./scripts/portrait.py input.jpg output.jpg \
--smooth 2 --enhance-eyes --whiten-teeth 0.3 --brightness 10
# JSON output
./scripts/portrait.py input.jpg output.jpg --all --json
| Parameter | Description |
|---|---|
--smooth | Skin smoothing strength 1-10 |
--denoise | Denoise strength 1-30 |
--red-eye | Remove flash red-eye |
--whiten-teeth | Teeth whitening strength 0.1-0.8 |
--enhance-eyes | Brighten/sharpen eyes |
--brightness | Face brightness -100 to 100 |
--contrast | Face contrast -100 to 100 |
--gamma | Face gamma correction 0.1-3.0 |
--sharpen | Sharpening strength 0.5-3.0 |
--blemish-removal | Remove small blemishes |
--skin-tone | Warm skin tone enhancement |
--all | Apply all enhancements (balanced) |
--subtle | Conservative all enhancements |
--no-auto-detect | Skip face/eye detection |
--no-exif | Do not preserve EXIF |
--json | JSON output mode |
Automatic: All write operations preserve EXIF metadata by default
Tool: scripts/exif_utils.py — standalone EXIF utility
All editing scripts automatically preserve EXIF metadata from input to output.
# Read EXIF from an image
./scripts/exif_utils.py read photo.jpg
# Strip EXIF from an image
./scripts/exif_utils.py strip photo.jpg -o output.jpg
# Copy EXIF from one image to another
./scripts/exif_utils.py copy source.jpg dest.jpg
Supported tags: Make, Model, DateTime, Orientation, Exposure Time, F-Number, ISO, Focal Length, Lens Model, and more.
Primary Tool: OpenCV saliency detection + optional GrabCut refinement
Dependencies: opencv-python-headless (already required)
Automatically detects the most "interesting" region in an image and crops to it. Uses OpenCV's StaticSaliencyFineGrained algorithm by default, with spectral and edge-based fallbacks.
# Auto-crop to salient region with default padding
./scripts/smart_crop.py input.jpg output.jpg
# Crop to specific aspect ratio
./scripts/smart_crop.py input.jpg output.jpg --aspect 16/9
# Crop to 4:3 with 10% margin around subject
./scripts/smart_crop.py input.jpg output.jpg --aspect 4/3 --padding 0.1
# Resize to exact dimensions after smart crop
./scripts/smart_crop.py input.jpg output.jpg --width 800 --height 600
# Use GrabCut refinement for cleaner boundaries
./scripts/smart_crop.py input.jpg output.jpg --grabcut
# Generate debug saliency map overlay
./scripts/smart_crop.py input.jpg output.jpg --debug
| Parameter | Description |
|---|---|
--aspect, -a | Aspect ratio (e.g. 16/9, 4/3, 1/1) |
--width, -w | Target width in pixels |
--height, -H | Target height in pixels |
--padding, -p | Margin around subject (0.0-0.5, default 0.05) |
--threshold, -t | Saliency threshold 0.05-0.95 (default 0.3) |
--algorithm | auto / finegrained / spectral / edge |
--grabcut, -g | Use GrabCut to refine crop boundary |
--debug, -d | Generate debug saliency map overlay |
Primary Tool: OpenCV (auto-detection + warpPerspective)
Auto-detects document/sheet borders using edge detection + contour analysis and corrects perspective distortion. Also supports manual corner specification.
# Auto-detect and correct
./scripts/edit.py --task perspective-correct --image doc.jpg --output flat.jpg
# With manual corners (top-left, top-right, bottom-right, bottom-left)
./scripts/edit.py --task perspective-correct --image doc.jpg --output flat.jpg \
--corners "100,50,600,50,600,800,100,800"
# Batch JSON
./scripts/edit.py --json < tasks.json
| Parameter | Description |
|---|---|
--corners | 4 points as CSV x1,y1,x2,y2,x3,y3,x4,y4 (TL,TR,BR,BL). Omit for auto-detection |
Algorithm: Adaptive threshold → contour detection → largest 4-point quadrilateral → perspective transform.
Primary Tool: OpenCV (content analysis + format-specific encoding)
Content-aware image compression using entropy, edge density, and color variance analysis to auto-select the best format and quality.
# Auto-select best format and quality
./scripts/edit.py --task smart-compress --image photo.jpg --output optimized.jpg
# Target file size (auto binary-searches quality)
./scripts/edit.py --task smart-compress --image photo.jpg --output optimized.jpg --target-kb 200
# Force WebP with specific quality
./scripts/edit.py --task smart-compress --image photo.jpg --output optimized.webp \
--format webp --quality 85
# Batch JSON
./scripts/edit.py --json < tasks.json
| Parameter | Description |
|---|---|
--target-kb | Target output size in KB (enables binary-search for optimal quality) |
--format | Force output: jpeg |
Auto-decision logic:
--target-kb is specifiedPrimary Tool: OpenCV (multi-scale bilateral decomposition + CLAHE)
HDR-style tone mapping to enhance dynamic range on single images. Uses bilateral filter decomposition to separate illumination from detail, compress the illumination layer's dynamic range, then recombine — producing natural-looking highlight/shadow recovery.
# Auto mode (default — picks best method based on image analysis)
./scripts/edit.py --task hdr-tonemap --image photo.jpg --output hdr_enhanced.jpg
# Bilateral mode — detail-preserving compression (best for most photos)
./scripts/edit.py --task hdr-tonemap --image photo.jpg --output hdr_enhanced.jpg --mode bilateral --strength 1.2
# Log mode — fast global compression (good for screenshots/graphics)
./scripts/edit.py --task hdr-tonemap --image photo.jpg --output hdr_enhanced.jpg --mode log --gamma 2.2
# Shadows mode — lighten dark regions (backlit photos)
./scripts/edit.py --task hdr-tonemap --image photo.jpg --output hdr_enhanced.jpg --mode shadows --strength 1.5
# Highlight mode — compress blown highlights
./scripts/edit.py --task hdr-tonemap --image photo.jpg --output hdr_enhanced.jpg --mode highlight --strength 1.2
| Parameter | Description |
|---|---|
--mode | auto / bilateral / log / shadows / highlight (default: auto) |
--strength | Enhancement strength 0.1-2.0 (default: 1.0) |
--gamma | Gamma value for log mode (default: 2.2) |
Algorithm: Bilateral filter decomposition — base (illumination) layer compressed with S-curve; detail layer preserved and boosted; adaptive saturation adjustment.
Primary Tool: Seedream multi-reference image fusion (AI-only, no deterministic fallback)
Place a subject (portrait / pet / product) into a new scene using Seedream's multi-reference image fusion. Wraps 豆包 app's "多图融合" + "换场景" feature.
Requires: the byted-ark-seedream-skill (this task is AI-only; an
OpenCV/ImageMagick fallback would produce poor results and is intentionally
omitted).
Usage:
# 1) Subject + scene image (most common)
./scripts/edit.py --task replace-scene \
--subject photo.jpg --scene cafe.png --output out.jpg
# 2) Subject + text-only scene description
./scripts/edit.py --task replace-scene \
--subject pet.jpg --scene-prompt "阳光下的草地" --output out.jpg
# 3) Product photo into lifestyle scene
./scripts/edit.py --task replace-scene \
--subject product.png --scene lifestyle.jpg --output out.jpg \
--subject-type product
# 4) Custom prompt override (full artistic control)
./scripts/edit.py --task replace-scene \
--subject portrait.jpg --scene beach.jpg --output out.jpg \
--prompt "把人物放在黄昏海边沙滩,长发随风,光线偏暖,景深虚化"
# 5) Subject in center, close-up framing
./scripts/edit.py --task replace-scene \
--subject portrait.jpg --scene studio.jpg --output out.jpg \
--position center --scale close
# 6) Full-body shot, subject on the right
./scripts/edit.py --task replace-scene \
--subject portrait.jpg --scene beach.jpg --output out.jpg \
--position right --scale full
# 7) JSON batch with position/scale
./scripts/edit.py --json < tasks.json
Argument table:
| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
--subject / -S | path | ✅ | — | Subject image (portrait / pet / product) |
--scene | path | ⚠️ one of | — | Target scene image |
--scene-prompt | string | ⚠️ one of | — | Target scene text description (used if no scene image) |
--subject-type | enum | ❌ | auto | auto / portrait / pet / product. Selects prompt template + reference_strength. |
--prompt / -p | string | ❌ | (from template) | Override the default prompt |
--reference-strength | float | ❌ | 0.85 (portrait/pet) / 0.90 (product) | How strongly Seedream must preserve the subject. Higher = stricter. |
--watermark | flag | ❌ | false | Add Seedream watermark. Default OFF (most uses are product / academic). |
--position | enum | ❌ | center | Horizontal subject placement: left / center / right. Feeds into the scene-prompt as positional hint. |
--scale | enum | ❌ | medium | Subject framing: close (特写) / medium (中景) / full (全身). Feeds into the scene-prompt as framing hint. |
--output-format | enum | ❌ | follow subject | jpeg / png / webp |
--output / -o | path | ❌ | auto | Output path |
Validation rules:
--subject is required.--scene / --scene-prompt is required (both → error).--scene-prompt is given, it must be at least 3 characters.Subject-type auto-detection:
When --subject-type auto is passed (default), the skill uses two heuristics:
pet/cat/dog/... → pet; portrait/selfie/face/... → portrait; product/item/bottle/... → productproduct (typical product shot on flat backdrop)If neither heuristic matches, falls back to portrait (most common case).
For certainty, always pass --subject-type explicitly.
JSON batch format:
{
"operations": [
{"task": "replace-scene", "subject": "p1.jpg", "scene": "office.jpg",
"output": "p1_office.jpg", "subject-type": "portrait"},
{"task": "replace-scene", "subject": "p2.jpg", "scene-prompt": "雪山日落",
"output": "p2_mountain.jpg", "subject-type": "portrait"},
{"task": "replace-scene", "subject": "shoe.png", "scene": "running_track.jpg",
"output": "shoe_track.jpg", "subject-type": "product", "reference-strength": 0.9}
]
}
JSON batch key naming: JSON keys use underscores (Python identifier
convention): scene_prompt, subject_type, reference_strength, etc. The
CLI flags use dashes (--scene-prompt, --subject-type). The skill
automatically normalizes dashed JSON keys to underscored ones, so both
work; use whichever is more natural for your tooling.
Output:
The result JSON envelope includes a generation_time_s field (extracted from
Seedream's own metadata) for quota tracking.
| Parameter | Type | Default | Required | Description |
|---|---|---|---|---|
task | string | - | ✅ | Task type: remove-object / remove-background / restore / resize / crop / color-adjust / perspective-correct / smart-compress / hdr-tonemap / replace-scene |
image | string | - | ✅ | Input image path |
prompt | string | "" | ❌ | Object description/location (required for remove-object) |
tool | string | "auto" | ❌ | Force specific tool: auto / seedream / imagemagick / opencv / rembg |
output_format | string | "jpeg" | ❌ | Output format: jpeg / png / webp |
quality | integer | 95 | ❌ | Output quality (0-100) |
User request → Analyze task type
↓
Object removal? → Seedream (default) → Failed? → OpenCV fallback
↓
Background removal? → Detect background → Solid? ImageMagick : rembg
↓
Old photo restoration? → Seedream (reference_strength=0.7)
↓
Basic editing? → ImageMagick
Task: Remove the black power cable at the bottom of the image
Parameters:
task: remove-object
image: mountain.jpg
prompt: "Remove the thin black horizontal power cable at the bottom 20% of the image. Restore the mountain texture seamlessly, keep everything else exactly the same."
tool: seedream
Task: Restore this old photo
Parameters:
task: restore
image: old_photo.jpg
prompt: "Remove scratches and dust spots, enhance clarity, restore natural colors"
Task: Remove background from portrait photo
Parameters:
task: remove-background
image: portrait.jpg
tool: auto
# Apply all portrait enhancements
./scripts/portrait.py input.jpg output.jpg --all
# Subtle skin smoothing and eye enhancement
./scripts/portrait.py input.jpg output.jpg --smooth 2 --enhance-eyes
scripts/inpaint.py directly (--type spot/wire/rect) or pass --tool opencv to get the inpaint.py guidance message.--tool opencv → op_remove_object returns an actionable redirect listing common inpaint.py invocations.smart-photo-editor/
├── SKILL.md # This file
├── README.md # Quick start guide
├── scripts/
│ ├── edit.py # ⭐ Unified CLI entry point (all operations)
│ ├── inpaint.py # OpenCV wire/spot/line/rect/denoise/sharpen/adjust
│ ├── portrait.py # Portrait retouching (skin, eyes, teeth, etc.)
│ ├── smart_crop.py # Smart auto-crop based on saliency detection
│ ├── exif_utils.py # EXIF read/strip/copy utility
│ └── remove_bg.sh # Background removal wrapper
└── examples/ # Before/after comparison examples
edit.py)The recommended entry point for all photo editing operations.
# Object removal (AI)
./scripts/edit.py --task remove-object --image photo.jpg \
--prompt "Remove the person in the center" --output out.jpg
# Old photo restoration
./scripts/edit.py --task restore --image old_photo.jpg --output restored.jpg
# Background removal
./scripts/edit.py --task remove-background --image portrait.png --output no_bg.png
# Resize
./scripts/edit.py --task resize --image photo.jpg --output small.jpg --width 800
# Crop
./scripts/edit.py --task crop --image photo.jpg --output crop.jpg \
--x 100 --y 100 --width 400 --height 300
# Color adjustment
./scripts/edit.py --task color-adjust --image photo.jpg --output bright.jpg \
--brightness 20 --saturation 30
# Batch mode (JSON)
./scripts/edit.py --json < batch_tasks.json
| Parameter | Type | Default | Description |
|---|---|---|---|
--task | string | required | Operation: remove-object, restore, remove-background, resize, crop, color-adjust, perspective-correct, smart-compress, hdr-tonemap |
--image / -i | string | required | Input image path |
--output / -o | string | auto | Output path (default: {input}.{task}{ext}) |
--prompt / -p | string | - | Description for AI operations |
--tool / -t | string | auto | Force tool: auto, seedream, opencv, imagemagick, rembg |
--width / -w | int | - | Target width (resize/crop) |
--height / -H | int | - | Target height (resize/crop) |
--max-dim | int | - | Max dimension, maintains aspect (resize) |
--x, --y | int | - | Offset for crop |
--brightness | float | - | Brightness: -100 to 100 |
--contrast | float | - | Contrast: -100 to 100 |
--saturation | float | - | Saturation: -1 to 1 |
--grayscale | flag | false | Convert to grayscale |
--corners | string | - | Perspective corners: x1,y1,x2,y2,x3,y3,x4,y4 (TL,TR,BR,BL) |
--target-kb | int | - | Target file size in KB (smart-compress quality search) |
--format | string | - | Output format: jpeg | png | webp |
--mode | string | auto | HDR tonemap mode: auto / bilateral / log / shadows / highlight |
--strength | float | 1.0 | Enhancement strength 0.1-2.0 (hdr-tonemap) |
--gamma | float | 2.2 | Gamma value for log mode (hdr-tonemap) |
--quality | int | auto | Output quality 1-100 (jpeg/webp; ignored when --target-kb is set) |
--position | string | - | Horizontal placement for replace-scene: left / center / right |
--scale | string | - | Framing for replace-scene: close / medium / full |
--subject / -S | string | - | Subject image path (required for replace-scene) |
--scene | string | - | Scene image path (one of --scene or --scene-prompt for replace-scene) |
--scene-prompt | string | - | Scene text description (one of --scene or --scene-prompt for replace-scene) |
--subject-type | string | auto | Subject type for replace-scene: auto / portrait / pet / product |
--reference-strength | float | 0.85 | How strongly Seedream preserves the subject |
--watermark | flag | false | Add Seedream watermark (default OFF) |
--json | flag | false | Emit JSON result envelope on stdout. Combine with --batch (or piped stdin) for JSON batch input. |
--batch / -b | string | - | JSON file for batch operations |
{
"operations": [
{"task": "remove-object", "image": "a.jpg", "prompt": "Remove the person", "output": "a_out.jpg"},
{"task": "restore", "image": "b.jpg", "output": "b_out.jpg"},
{"task": "resize", "image": "c.jpg", "output": "c_small.jpg", "width": 800}
]
}
New replace-scene parameters
--position {left,center,right} — controls horizontal placement of the subject in the generated scene. Feeds into the scene-prompt as a positional hint so Seedream places the subject accordingly.--scale {close,medium,full} — controls subject framing (特写/中景/全身). Feeds into the scene-prompt as a framing hint.R2 large-file upload for Seedream reference images
SEEDREAM_UPLOAD_TOKEN and SEEDREAM_UPLOAD_WORKER_URL env vars.New feature: replace-scene task
Adds a new AI-driven task that places a subject (portrait / pet / product) into
a new scene using Seedream's multi-reference image fusion. Wraps 豆包 app's
"多图融合" + "换场景" feature.
--subject (alias of --image for this task) + mutually-exclusive
--scene (image) or --scene-prompt (text) input pair.--subject-type {auto,portrait,pet,product} selects a per-type prompt
template and reference_strength. auto uses filename keyword + corner
solidity heuristics.--watermark defaults to OFF (most uses are product / academic)._call_seedream(reference_images=...) parameter — passes a JSON array
of data URIs to Seedream (which accepts up to 14 reference images).info.generation_time_s extracted from Seedream's metadata for
quota tracking.Bug fixes (incidental, surfaced by v1.4.0 testing)
process_batch now normalizes dashed JSON keys (scene-prompt →
scene_prompt, target-kb → target_kb, subject-type → subject_type,
no-maintain-aspect → no_maintain_aspect) before unpacking into
process(**op). Previously these were silently dropped into the trailing
**kwargs and the real parameter received its default — a very confusing
failure mode (especially for target-kb where the result was a wildly
different file size than requested).process() now translates no_maintain_aspect=True (from JSON batch) to
maintain_aspect=False (the inverted semantics the op_resize function
expects), mirroring the same translation main() does for the CLI.Docs
replace-scene.ImageMagick argument fix
op_resize / op_crop / op_color_adjust / op_remove_background (ImageMagick fallback): all ImageMagick CLI arguments are now passed as separate list elements instead of single space-joined strings. Previously ImageMagick would reject commands like -resize 800x800> because the flag and value were concatenated into one string.HDR bilateral saturation fix
_tonemap_bilateral no longer performs a pseudo-HSV operation directly on BGR channels (which corrupted colors). Now uses proper cv2.cvtColor(BGR→HSV) → boost saturation → cv2.cvtColor(HSV→BGR).Background removal fallback fix
remove_bg.sh ImageMagick fallback: corrected matte floodfill coordinates (was passing RGB values as coordinates; now uses 0,0). Removed erroneous -alpha extract which turned output into a pure alpha mask.edit.py ImageMagick fallback: replaced -trim (which merely cropped edges) with -transparent <detected-bg-color> so the result is actually a transparent-background image.Runtime robustness
op_remove_background now probes both $PATH and the team venv (venv-clawd/bin/rembg) for rembg, matching Laoguo's actual deployment environment._call_seedream guards against shutil.copyfile(local, output_path) when source and destination are the same file (would truncate to zero bytes)._save_with_quality now derives the actual output format from the file extension, preventing OpenCV warnings when --format and --output disagree (e.g. --output foo.webp --format png).CLI
--no-maintain-aspect flag for resize task to allow non-proportional stretching.Tool selection policy
op_remove_object no longer keyword-sniffs the prompt for "wire / cable / line / spot / dust / scratch" and silently routes to a stub. --tool auto now picks Seedream when available; the OpenCV branch surfaces an actionable redirect to scripts/inpaint.py for known-geometry cases.inpaint.py invocations (--type spot, --type wire, --type rect) so users have a clear next step instead of a guess.Bug fixes
op_resize / op_crop / op_color_adjust no longer raise TypeError: got an unexpected keyword argument 'mode'. The CLI's --mode flag is now only forwarded for hdr-tonemap. (Was reported as "numpy 2.x compat issue"; root cause was kwargs leakage.)smart-compress --target-kb no longer crashes with No such file or directory: foo.q55.tmp. The binary-search probe file now uses the format's real extension (.jpg/.png/.webp) so OpenCV can pick a codec.--quality is now an actual CLI flag, declared in argparse and forwarded into op_smart_compress (was documented but unrecognized).--json on a single-operation invocation now emits a JSON envelope on stdout instead of blocking on stdin. Batch input is still accepted via --batch FILE or piped stdin.compatibility frontmatter key moved under metadata.compatibility (was rejected by the OpenClaw skill validator as an unknown top-level key)._tonemap_shadows annotation corrected from np.float32 to np.ndarray.Seedream bridge rewrite
The previous integration referenced a non-existent bin/generate.sh and a non-existent Python module. _call_seedream now invokes node scripts/generate.js with --prompt, --mode image-to-image, --reference_images <data-URI JSON array>, --reference_strength, and --optimize false, parses the JSON envelope from stdout, locates the first download_success image, and stages its local_path to the caller's output_path. Local file paths are encoded as data:image/<type>;base64,<...> data URIs because Seedream's validator only accepts HTTP URLs or data URIs. Verified end-to-end with a real ARK API call (200×200 input → 2048×2048 generated output, ~30 s).
Docs
~/.openclaw/venv-clawd/bin/python); running them under system Python will spuriously report piexif/exif/rembg as missing.--quality and --json table entries clarified.