Nodes/comfyui-libcom-image-composition/Harmony Score Evaluation
ComfyUI Node

Harmony Score Evaluation

No-reference harmony scoring with BargainNet

By fuselayer·Created 11 months ago·Updated 10 months ago· 0
Harmony Score Evaluation
  • composite_image
  • mask
  • harmonized_image
  • harmony_score
  • score_text

You harmonized the composite, and it looks better. But "looks better" is a vibe, not a number, and vibes don't survive an A/B test between five model variants. Harmony Score Evaluation gives you the number. It runs BargainNet - a no-reference harmony evaluator from the same libcom toolkit that backs this pack's harmonization models - and predicts how harmonious the foreground and background are on a 0–1 scale. Higher is better. No ground-truth image required; it judges your composite directly.

How it works

The mechanism is about as simple as it gets. Feed it composite_image and a mask (white = the foreground region), and it scores how well that foreground's appearance matches the background. Under the hood it lazy-loads a HarmonyScorer on first run and converts your tensors to the numpy format BargainNet expects. The interesting output path: if you also wire in the optional harmonized_image, it scores both versions and hands you the delta.

That's the workflow this node was built for. Run the pack's ImageHarmonization node, split your pipeline, feed the original and the result in here, and you get an actual improvement value instead of a hunch. It's the only honest way to tune pctnet_strength or pick between CDTNet and PCT-Net variants - run a couple of configurations, keep the one with the bigger improvement, move on.

The outputs

  • harmony_score (FLOAT) - 0–1, higher = more harmonious. With a harmonized_image wired in, this returns the harmonized score (not the composite's).
  • score_text (STRING) - the one you'll actually read. With a comparison wired up it's three lines: composite score, harmonized score, and the Improvement: +0.1234 delta. Without one, it's the single composite score, pretty-printed.

So: wire the FLOAT into anything that needs a number, or just glance at score_text in the node preview. For iteration, the text output is the whole product.

First-run download (the real gotcha)

Unlike the harmonization nodes, whose weights ship inside the repo, BargainNet's weights are downloaded at first run from HuggingFace (BCMIZB/Libcom_pretrained_models), with a ModelScope fallback. The download path lives in the vendored libcom code, and it needs huggingface_hub (and tqdm) - neither is in the pack's requirements.txt. If your first run dies on an import, that's why:

cd ComfyUI/custom_nodes/comfyui-libcom-image-composition
# portable: .\python_embeded\python.exe -m pip install huggingface_hub tqdm
pip install huggingface_hub tqdm

The download only happens once; after that the .pth sits in model/libcom/harmony_score/pretrained_models/.

Two honest caveats

First, BargainNet was trained on synthetic composites in the iHarmony4 style, so treat the score as relative guidance for A/B testing, not an absolute "is this photoreal" judge. It'll happily rank two bad composites against each other. Use it to pick the better output, not to certify one. Second, same pack health warning as the others: this is a one-commit, zero-impression project. Install the same way (ComfyUI Manager, search "comfyui-libcom-image-composition", or git clone https://github.com/fuselayer/comfyui-libcom-image-composition into custom_nodes/, restart). If a number instead of a gut feeling is worth one extra node in the graph, this is it.

Categoryimage/harmonization

Inputs (3)

NameTypeDefaultDescription
composite_imageIMAGE
maskMASK
harmonized_imageoptIMAGE

Outputs (2)

NameTypeDescription
harmony_scoreFLOAT
score_textSTRING