A comprehensive benchmark for evaluating multi-reference image generation models.
OmniRef-Bench is a benchmark suite designed to evaluate the ability of text-to-image generation models to follow multiple heterogeneous reference signals simultaneously. Given a text prompt and a set of reference images (subject, style, background, lighting, pose), the benchmark measures how well a model integrates all control signals into a single coherent output.
The benchmark covers 6 evaluation dimensions:
| Dimension | Method | Tool |
|---|---|---|
| Subject Fidelity | CLIP-I / DINOv2 cosine similarity | Grounded-SAM-2 + CLIP/DINOv2 |
| Background Consistency | CLIP similarity on masked background | Grounded-SAM-2 + CLIP |
| Pose Consistency | Keypoint OKS, PKS, angle similarity | AlphaPose |
| Style Consistency | CSD (CLIP-based style descriptor) | CSD-ViT-L |
| Lighting Consistency | LAB-space multi-metric composite | OpenCV |
| Overall Quality (VLM) | GPT-4o / Gemini multi-dim scoring | MLLM (VLM) |
OmniRef-Bench/
├── data_construct/ # Training/Test set construction pipeline
│ ├── gen_prompt/ # Generate T2I prompts via LLM
│ ├── process_prompt/ # Diversify & process prompts (bg/style/pose/lighting)
│ ├── gen_image/ # Generate target/reference images (Seedream API)
│ └── data_filtering/ # Filter by subject/background/style quality
├── Grounded-SAM-2_patch/ # Subject & background evaluation
│ ├── subject_fidelity_eval.py
│ ├── background_consistency_eval.py
│ ├── pose_consistency_eval.py
│ ├── grounded_sam2_pipeline.py # Segment raw subjects from generated target images
│ ├── crop_subjects.py # Crop raw subjects from generated target images based on masks
│ ├── nlp_helper.py
│ └── utils/
│ └── eval_utils.py
├── CSD_patch/ # Style & lighting evaluation
│ ├── csd_eval_batch.py # Style consistency (CSD-ViT-L)
│ └── lighting_consistency_eval.py
├── AlphaPose_patch/ # Pose skeleton evaluation
│ └── scripts/
│ ├── gen_skeleton.py
│ ├── pose_consistency_eval.py
│ └── consistency_check.py
├── MLLM_eval/ # MLLM-based holistic evaluation
│ ├── mllm_eval.py
│ └── vlm_utils.py
├── metadata/ # information for training and test data
│ ├── data_our_multibanana_mixture_pose.json # test data version 1
│ ├── data_our_multibanana_skeleton.json # test data version 2
│ └── train_data.json
├── eval_suite.sh # One-click full evaluation script
└── eval_script.sh # Example evaluation command
The benchmark contains 395 samples across multiple task categories:
subject— subject fidelity onlysubject + style— subject with style transfersubject + bg— subject with background replacementsubject + lighting— subject with lighting transfersubject + pose— subject with pose control- (combinations of the above)
Each sample in the JSON metadata contains:
{
"index": 0,
"prompt": "...",
"category": "subject_style",
"edit_image": [
"transfer_subjects/xxx.png",
"style/reference/xxx.png"
]
}The benchmark requires 3 separate conda environments due to dependency conflicts. We recommend following the official installation guides for each component to ensure CUDA extensions are correctly compiled.:
- Please follow the installation guide: Grounded-SAM-2
- Apply patch:
# Copy our evaluation scripts to the official Grounded-SAM-2 directory
cp -r Grounded-SAM-2_patch/* /path/to/your/Grounded-SAM-2/- Please follow the installation guide: CSD
- Apply patch:
# Copy our style & lighting evaluation scripts to the CSD directory
cp -r CSD_patch/* /path/to/your/CSD/- Please follow the installation guide: AlphaPose
- Apply patch:
# Copy our pose skeleton scripts to the AlphaPose directory
cp -r AlphaPose_patch/* /path/to/your/AlphaPose/This module does not require a complex official repo setup. You can use the groundingdino environment or a simple base environment:
pip install openai tqdmbash eval_suite.sh \
/path/to/generated_images \
/path/to/output_dir \
/path/to/test_set \
/path/to/test_set.jsonThis script sequentially runs all 6 evaluation tasks and saves results to output_dir/.
cd Grounded-SAM-2
conda activate groundingdino
python subject_fidelity_eval.py \
--img_path /path/to/generated_images \
--output_path /path/to/output \
--test_set_path /path/to/test_set \
--json_data_path /path/to/test_set.jsoncd CSD
conda activate style
python csd_eval_batch.py \
--image_dir /path/to/generated_images \
--output_path /path/to/output \
--reference_dir /path/to/test_set \
--json_data_path /path/to/test_set.jsonpython lighting_consistency_eval.py \
--img_path /path/to/generated_images \
--output_path /path/to/output \
--reference_base_path /path/to/test_set \
--json_data_path /path/to/test_set.jsoncd AlphaPose
conda activate alphapose
python scripts/pose_consistency_eval.py \
--cfg configs/coco/resnet/256x192_res50_lr1e-3_2x-dcn.yaml \
--checkpoint pretrained_models/fast_dcn_res50_256x192.pth \
--save_skeleton \
--indir /path/to/generated_pose_images \
--output_path /path/to/output \
--reference_dir /path/to/test_set \
--json_data_path /path/to/test_set.jsonEach metric produces a .json summary and a .jsonl per-sample file:
output/
├── subject.json # {"clip_i_score": 0.xx, "dino_score": 0.xx}
├── subject.jsonl # per-sample scores
├── background.json # {"background_score": 0.xx}
├── background.jsonl # per-sample scores
├── style.json # {"csd_score": 0.xx}
├── style.jsonl # per-sample scores
├── lighting.json # {"lighting_score": xx.xx}
├── lighting.jsonl # per-sample scores
├── pose.json # {"pose_score": 0.xx}
└── pose.jsonl # per-sample scores
cd MLLM_eval
export OPENAI_API_KEY=your_key_here
python mllm_eval.py \
--gen_image_dir /path/to/generated_images \
--output_file /path/to/output/vlm_results.jsonl \
--test_set_dir /path/to/test_set \
--metadata_file /path/to/test_set.json \
--base_url https://your-api-endpointcd MLLM_eval
python analysis.py --result_json_path /path/to/eval_resultsroot_dir/
├── 2_subjects/
│ ├── 0/
│ │ ├── 0.jpeg # target image
│ │ ├── metadata.json # json file containing the original T2I-prompt and subject list
│ │ ├── scores_vlm.json # subject reference filtering results
│ │ ├── transfer_subjects/ # subject references
│ │ ├── raw_subjects/ # segmented subjects from target image
│ │ ├── cropped_subjects/ # cropped subjects from target image
│ │ ├── individual_masks # segmented subject masks from target image
│ │ ├── background/
│ │ │ ├── background.png # background reference
│ │ │ └── vlm_eval.json # background reference filtering score
│ │ ├── lighting/
│ │ │ ├── lighting_reference.jpeg # lighting reference
│ │ │ └── score.json # lighting reference filtering score
│ │ ├── style/
│ │ │ ├── reference.png # style reference
│ │ │ ├── target.png # stylized target image
│ │ │ └── score.json # stylized target image filtering score
│ │ └── pose/
│ │ │ ├── skeleton/ # pose skeleton reference
│ │ │ ├── reference/ # pose reference
│ │ │ └── keypoints/ # skeleton keypoints
│ │
│ ├── 1/
│ ├── ...
│
├── 3_subjects/
├── ...
To reproduce or extend the dataset:
- Generate subject instances using Objects365 dataset.
cd data_construct/gen_prompt
# fill in the .env file to provide API key and base URL.
python gen_subject_instance.py --output /path/to/output/subject/instances.jsonl- Combine subject instances and generate T2I-prompts.
python gen_T2I_prompts.py --input /path/to/input/subject/instances.jsonl --output /dir/to/output/T2I/promptscd data_construct/gen_image
# fill in the .env file to provide API key and base URL.
python seedream_target.py \
--prompt_dir /dir/to/input/T2I/prompts \
--output_dir /root/dir/to/output/images \
--num_subjects number_of_subjects_per_promptEach target image will be stored at:
{output_dir}/{num_subects}_subjects/{prompt_index}/{prompt_index}.jpeg
cd Grounded-SAM-2
conda activate groundingdino
python grounded_sam2_pipeline.py \
--img_dir /dir/to/certain/number-of-subjects/target/imagesEach segmented subject and mask will be stored at:
{img_dir}/{prompt_index}/raw_subjects/{subject_name}.jpg
{img_dir}/{prompt_index}/individual_masks/{subject_name}_binary_mask_full.png
python crop_subjects.py \
--root_dir /root/dir/to/generated/images \
--num_subjects number_of_subjectsEach cropped subject will be stored at:
{root_dir}/{num_subects}_subjects/{prompt_index}/cropped_subjects/{subject_name}.png
cd data_construct/gen_image
# Fill IMAGE_EDIT_API_* in .env, or pass the matching --image-edit-api-* args.
python subject_transfer.py \
--root_dir /root/dir/to/generated/images \
--num_subjects number_of_subjectsEach subject reference will be stored at:
{root_dir}/{num_subects}_subjects/{prompt_index}/transfer_subjects/{subject_name}.png
# Fill IMAGE_EDIT_API_* in .env, or pass the matching --image-edit-api-* args.
python background_extract.py \
--root_dir /dir/to/certain/number-of-subjects/target/imagesEach background reference will be stored at:
{root_dir}/{prompt_index}/background/background.png
# fill in the .env file to provide API key and base URL.
cd data_construct/data_filtering
python filter_subject.py \
--root_dir /dir/to/certain/number-of-subjects/target/imagescd AlphaPose
conda activate alphapose
python scripts/gen_skeleton.py \
--cfg configs/coco/resnet/256x192_res50_lr1e-3_2x-dcn.yaml \
--checkpoint pretrained_models/fast_dcn_res50_256x192.pth \
--save_skeleton \
--indir /dir/to/certain/number-of-subjects/target/images \
--nested_structurecd data_construct/gen_image
python seedream_lighting.py \
--root_dir /dir/to/certain/number-of-subjects/target/images \
--sample number_of_lighting_references_to_generate
python seedream_pose.py \
--root_dir /root/dir/to/target/images
python seedream_style.py \
--root_dir /root/dir/to/target/imagescd data_construct/data_filtering
python filter_background.py \
--root_dir /dir/to/certain/number-of-subjects/target/images
python filter_style.py \
--root_dir /dir/to/certain/number-of-subjects/target/imagesLighting and pose references can be filtered using the evaluation scripts. (i.e., AlphaPose_patch/scripts/pose_consistency_eval.py and CSD_patch/lighting_consistency_eval.py)
We add markers for subject, background/style, lighting, pose references sequentially. Each output file of the previous stage serves as the input of the next stage.
cd data_construct/process_prompt
# fill in the .env file to provide API key and base URL.
python process_prompts.py \
--data_dir /dir/to/certain/number-of-subjects/target/images \
--output /path/to/output/jsonl/file \
--num_subjects number_of_subjects
python process_prompt_bg.py \
--data_dir /root/dir/to/target/images \
--input /path/to/input/jsonl/file/with/subject/markers/added \
--output /path/to/output/jsonl/file
python process_prompt_style.py \
--base_dir /root/dir/to/target/images \
--input /path/to/input/jsonl/file/with/subject/markers/added \
--output /path/to/output/jsonl/file
python process_prompt_lighting.py \
--data_dir /root/dir/to/target/images \
--input /path/to/input/jsonl/file/with/subject/markers/added \
--output /path/to/output/jsonl/file
python process_prompt_pose.py \
--data_root /root/dir/to/target/images \
--input /path/to/input/jsonl/file/with/other/markers/added \
--output /path/to/output/jsonl/fileIn this stage, we switch the positions of different reference markers in the processed prompts and diversify the expressions of referencing.
cd data_construct/process_prompt
# change natural language style reference expressions (e.g., in reference image x) into format forms (e.g., in <image x>) to facilitate augmentation.
python add_marker.py \
--input /path/to/input/jsonl/file \
--output /path/to/output/jsonl/file
python diversify_prompts.py \
--input /path/to/input/jsonl/file \
--output /path/to/output/jsonl/file
# change format forms back to natural language style reference expressions.
python remove_marker.py \
--input /path/to/input/jsonl/file \
--output /path/to/output/jsonl/file