Skip to content

About

Geometry-constrained mirror inpainting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

🪞 Fill My Mirror

arXiv Project Page

Teaser

Table of Contents


Official implementation of Fill My Mirror.

This repository contains the code for generating consistent reflections in mirrors by combining geometry estimation, projection, and dual-mask diffusion-based inpainting.


🛠️ Installation

The following instructions were tested on Linux with Python 3.10.

1. Clone the repository

Clone the repository with submodules to also download the MoGe and MASt3R dependencies.

git clone --recurse-submodules https://github.com/OfekBasson/Fill-My-Mirror.git
cd Fill-My-Mirror

If you already cloned without submodules, run:

git submodule update --init --recursive

2. Create a Conda environment

Create a clean environment to avoid dependency conflicts.

conda create -n fill-my-mirror python=3.10
conda activate fill-my-mirror

3. Install Python dependencies

pip install -r requirements.txt
pip install -e third_party/MoGe
pip install -e .

4. Install Blender

This project requires Blender for scene rendering (and for evaluation on the Blender dataset).

Run the provided installation script:

bash scripts/install_blender.sh

This downloads and extracts Blender to:

external/blender/

5. (Optional) Install MASt3R for evaluation

Required only if you plan to run evaluation with the Reflection Consistency Score (RCS) masking on real images.

MASt3R is not a pip-installable package — install its dependencies directly:

pip install -r third_party/MASt3R/requirements.txt
pip install -r third_party/MASt3R/dust3r/requirements.txt

6. (Optional) Install Depth Anything 3 for alternative geometry

Required only if you plan to use a depth-anything/* geometry model (e.g. depth-anything/DA3-LARGE-1.1).

pip install xformers "torch>=2" torchvision
pip install git+https://github.com/ByteDance-Seed/Depth-Anything-3.git

Note: Depth Anything 3 does not yet support multi-mirror scenes. Use MoGe-V2 (Ruicheng/moge-2-vitl-normal) for images with more than one mirror.


🚀 Quick Start

Run the example script:

scripts/run_example.sh

Or run directly with your own image and mask:

python -m fill_my_mirror --image /path/to/image.png --mask /path/to/mask.png

Or use a sample from the HuggingFace dataset by index:

python -m fill_my_mirror --hf-index 0

⚙️ Command Line Arguments

Input (required — choose one)

Option A — local files (--image and --mask must be provided together):

Argument Description
--image /path/to/image.png Path to the input image
--mask /path/to/mask.png Path to the binary mask of the mirror region

Option B — HuggingFace dataset sample:

Argument Description
--hf-index INDEX Index of a sample from the dataset (0 to dataset size − 1). Used with the real-images dataset by default, with the Blender dataset when --use-blender-data is set, or with the MirrorBench V2 dataset when --use-mirrorbench-data is set. The sample's prompt is used as the prompt unless --prompt is also given.

Optional arguments

Argument Default Description
--config configs/config.yaml Path to a YAML configuration file
--blender_path (from config) Path to the Blender executable. Overrides the config file value.
--prompt (from config or dataset) Text prompt for the diffusion model. Overrides the config file value and any prompt from the HuggingFace sample.
--prompt-2 — Optional second text prompt
--output_path (from config) Path to save the final output image. Overrides the config file value.
--height 1024 Desired output height
--width 1024 Desired output width. Automatically adjusted to fit the input aspect ratio if needed.
--strength 1.0 Inpainting strength
--num-inference-steps 30 Number of diffusion inference steps
--guidance-scale 30.0 Guidance scale for the diffusion model
--num-images-per-prompt 1 Number of images to generate per prompt
--max-sequence-length 512 Maximum text sequence length
--seed 0 Random seed for reproducibility
--use-blender-data False Load a sample from the Blender HuggingFace dataset. Requires --hf-index. When set, geometry is read directly from the dataset (no MoGe inference).
--use-mirrorbench-data False Load a sample from the MirrorBench V2 (SynMirrorV2) dataset. Requires --hf-index. See MirrorBench V2 setup.
--n 6.0 Power n for the alpha^n interpolation
--t-prime 750.0 First timestep threshold for mask interpolation

💡 Example Commands

The file paths below are illustrative — replace them with the actual paths to your image and mask files.

Basic example with local files:

python -m fill_my_mirror \
  --image /path/to/image.png \
  --mask /path/to/mask.png \
  --prompt "A standing mirror reflects a bed with a dotted cover in a cozy bedroom."

Example using a HuggingFace dataset sample (no local files needed):

python -m fill_my_mirror --hf-index 5

Example with a custom output path:

python -m fill_my_mirror \
  --image /path/to/image.png \
  --mask /path/to/mask.png \
  --output_path outputs/result.png

Example with a custom prompt:

python -m fill_my_mirror \
  --image /path/to/image.png \
  --mask /path/to/mask.png \
  --prompt "Generate a realistic mirror reflection consistent with the scene geometry and lighting."

🔁 Batch Inference

Run the pipeline on every sample in the HuggingFace dataset with scripts/run_batch.py. Results are saved as {output_dir}/seed_{seed}/{index}.png, ready for use with the batch evaluation command.

python scripts/run_batch.py --dataset real --output-dir outputs/batch_real/

Arguments

Required:

Argument Choices Description
--dataset real, blender, mirrorbench_v2 Which dataset to use
--output-dir Root output directory. Results saved to {output_dir}/seed_{seed}/{index}.png

Optional:

Argument Default Description
--config configs/config.yaml Path to a YAML configuration file
--start-index 0 First dataset index to process (inclusive)
--end-index (full dataset) Last dataset index to process (exclusive)
--skip-existing False Skip indices whose output file already exists (useful for resuming)
--blender-path (from config) Path to the Blender executable. Overrides the config file value

All standard pipeline arguments (--prompt, --strength, --num-inference-steps, --guidance-scale, --seed, --n, --t-prime, etc.) are accepted and forwarded to the pipeline unchanged — see Command Line Arguments for their descriptions and defaults.


📊 Evaluation

Metrics are reported for two regions of the mirror and the full image:

MetricRegionDescription
clip_similarityFull imageCLIP ViT-B/32 image–text cosine similarity
psnr_full_mirrorFull mirror maskPSNR restricted to mirror pixels
ssim_full_mirrorSSIM restricted to mirror pixels
lpips_full_mirrorLPIPS restricted to mirror pixels
psnr_constrainedConstrained pixels onlyPSNR restricted to geometrically-determined pixels
ssim_constrainedSSIM restricted to geometrically-determined pixels
lpips_constrainedLPIPS restricted to geometrically-determined pixels

Running Evaluation

Evaluate a single locally provided image (no dataset required):

python scripts/evaluate.py local \
  --generated /path/to/generated.png \
  --gt /path/to/gt_image.png \
  --mask /path/to/mask.png \
  --save-dir eval/sample_0/ \
  --prompt "A standing mirror reflects a bed with a dotted cover in a cozy bedroom."

local arguments — required:

Argument Description
--generated Path to the generated/inpainted image
--gt Path to the ground-truth image
--mask Path to the binary mirror mask
--save-dir Directory to save the metrics CSV

local arguments — optional:

Argument Default Description
--prompt — Text prompt for CLIP similarity
--rcs-dilation 5 Dilation radius for the RCS mask
--config configs/config.yaml Path to a YAML configuration file

Evaluate a batch of results against the real-images HuggingFace dataset:

python scripts/evaluate.py batch \
  --results-dir outputs/my_run/ \
  --dataset real \
  --output-dir outputs/eval/real/

Evaluate against the Blender dataset:

python scripts/evaluate.py batch \
  --results-dir outputs/blender_run/ \
  --dataset blender \
  --output-dir outputs/eval/blender/

batch arguments — required:

Argument Choices Description
--results-dir Directory containing result PNGs named {index}.png
--dataset real, blender, mirrorbench_v2 Which dataset to load ground truth from
--output-dir Directory to save per-sample and aggregate CSVs

batch arguments — optional:

Argument Default Description
--prompt — Override CLIP prompt for all samples
--rcs-dilation 5 Dilation radius for the RCS mask
--blender-path (from config) Path to the Blender executable (needed for --dataset blender)
--config configs/config.yaml Path to a YAML configuration file

Constrained Pixels Mask

The constrained mask isolates mirror pixels whose appearance is geometrically determined by the visible scene — enabling a more faithful evaluation of reflection correctness than metrics over the full mirror region.

Real images (HF dataset or local) — computed via the Reflection Consistency Score (RCS): MASt3R finds dense correspondences between the scene view and a flipped mirror view; matched mirror pixels are dilated and intersected with the mirror mask.

Blender dataset — derived from ground-truth 3D geometry: the projection pipeline is run with GT point cloud and intrinsics; pixels covered by the projection are the constrained region.


📦 Dataset

Two datasets are provided:

Contains 50 real-world mirror scenes with the following columns per sample:

Column Type Description
id int32 Sample index
image image Input image (mirror region is black)
mask image Binary mask of the mirror region
gt_image image Ground-truth image (mirror filled)
prompt string Text description of the scene

Contains 15 rendered Blender scenes with mirrors, including ground-truth mirror masks, geometry, and manually assigned prompts.

Column Type Description
id int32 Sample index
image image Rendered scene image
mask image Ground-truth binary mask of the mirror region
gt_image image Ground-truth image (mirror filled)
prompt string Manually assigned text description of the scene
points float32 (800×800×3) 3D point cloud of the scene geometry
depth float32 (800×800) Depth map of the scene
intrinsics float32 (3×3) Camera intrinsics matrix

A large-scale synthetic benchmark from MirrorVerse (CVPR'25) containing 207K rendered scenes. The HDF5 files are distributed as tar archives on HuggingFace and must be downloaded and extracted before use. The split CSV (test.csv) is downloaded automatically.

Setup:

Run the provided download script to fetch and extract all archives:

python scripts/download_mirrorbench_v2.py

To download and extract a single batch only:

python scripts/download_mirrorbench_v2.py --batch 1

Note: batch indices start at 1 (there is no batch_0.tar); valid values are 1-35.

After extraction the directory should look like:

data/mirrorbench_v2/
    hf-objaverse-v4/
        000-010/
            8014aa16057a495795f7bf8a02a3ebe0/
                0.hdf5  1.hdf5  2.hdf5
        ...
    abo_v4/
        ...

Geometry is derived from the HDF5 depth map and camera intrinsics — no MoGe inference is run.

Run a single sample:

python -m fill_my_mirror --use-mirrorbench-data --hf-index 0

Run batch inference:

python scripts/run_batch.py --dataset mirrorbench_v2 --output-dir outputs/batch_mirrorbench/

📁 Default Configuration

The default configuration is stored in configs/config.yaml:

prompt: "Complete the mirror reflection realistically and consistently with the scene geometry."
default_output_path: "outputs/result.png"
blender_path: "external/blender/blender-4.4.3-linux-x64/blender"
geometry_model_name: "Ruicheng/moge-2-vitl-normal"
inpainting_model_name: "black-forest-labs/FLUX.1-Fill-dev"
mast3r_model_name: "naver/MASt3R_ViTLarge_BaseDecoder_512_catmlpdpt_metric"

Alternative Geometry Models

geometry_model_name selects the geometry estimator used for real images (Blender samples always use ground-truth geometry).

Model ID Notes
Ruicheng/moge-2-vitl-normal Default; MoGe-V2 monocular geometry estimator
depth-anything/DA3-LARGE-1.1 Depth Anything 3; any depth-anything/* variant is accepted

To switch, edit configs/config.yaml:

geometry_model_name: "depth-anything/DA3-LARGE-1.1"

Note: Depth Anything 3 does not yet support multi-mirror scenes. Use MoGe-V2 for images with more than one mirror.

Alternative Inpainting Models

inpainting_model_name selects the dual-mask backend.

Model ID Backend class Notes
black-forest-labs/FLUX.1-Fill-dev DualMaskInterpolatedFluxFillPipeline Default; native inpainting backend built on FluxFillPipeline
black-forest-labs/FLUX.2-klein-base-9B DualMaskFlux2KleinInpaintPipeline Reference-guided inpainting; passes the original scene as image and the projected mirror view as image_reference

To switch, edit configs/config.yaml:

inpainting_model_name: "black-forest-labs/FLUX.1-Fill-dev"

Both backends use the same dual-mask noise interpolation parameters n and t_prime. When an argument is unsupported by the selected backend, Fill My Mirror logs a warning and silently ignores it.


📝 Citation

If you use this code in your research, please cite:

@article{fillmymirror2026,
  title   = {Fill My Mirror: Geometry-Constrained Mirror Inpainting},
  author  = {Basson, Ofek and Vainer, Shimon and Hel-Or, Yacov and Fried, Ohad},
  journal = {arXiv preprint arXiv:2609.03740},
  year    = {2026},
}

About

Geometry-constrained mirror inpainting

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages