deploy: 63a85616f5fc427cf1e1e7b425293131f2fce2b8
Browse files- README.md +143 -1
- layout-overlay.py +19 -2
- requirements.txt +134 -89
README.md
CHANGED
|
@@ -9,4 +9,146 @@ app_file: app.py
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 9 |
pinned: false
|
| 10 |
---
|
| 11 |
|
| 12 |
+
# Layout Overlay
|
| 13 |
+
|
| 14 |
+
## Description
|
| 15 |
+
|
| 16 |
+
The Layout Overlay metric measures the average IoU (Intersection over Union) of all pairs of layout elements, specifically excluding "underlay" or decoration elements. This metric is designed for poster and presentation layouts where underlay elements serve as backgrounds and should not be counted in overlap calculations.
|
| 17 |
+
|
| 18 |
+
## What It Measures
|
| 19 |
+
|
| 20 |
+
This metric computes:
|
| 21 |
+
|
| 22 |
+
- **Non-underlay overlap**: IoU between all pairs of foreground elements (text, images, logos)
|
| 23 |
+
- **Element collision**: How much non-decoration elements interfere with each other
|
| 24 |
+
- **Foreground placement quality**: Whether foreground elements are properly spaced
|
| 25 |
+
|
| 26 |
+
Underlay/decoration elements (like background shapes) are excluded from the calculation since they're intended to sit behind other elements.
|
| 27 |
+
|
| 28 |
+
## Metric Details
|
| 29 |
+
|
| 30 |
+
- Filters out decoration/underlay elements (typically class index 3 in PosterLayout)
|
| 31 |
+
- Removes invalid elements (< 0.1% of canvas area)
|
| 32 |
+
- Computes pairwise IoU for all remaining element pairs
|
| 33 |
+
- Returns average IoU across all overlapping pairs
|
| 34 |
+
- From PosterLayout (Hsu et al., CVPR 2023) for poster design evaluation
|
| 35 |
+
|
| 36 |
+
## Usage
|
| 37 |
+
|
| 38 |
+
### Installation
|
| 39 |
+
|
| 40 |
+
```bash
|
| 41 |
+
pip install evaluate
|
| 42 |
+
```
|
| 43 |
+
|
| 44 |
+
### Basic Example
|
| 45 |
+
|
| 46 |
+
```python
|
| 47 |
+
import evaluate
|
| 48 |
+
import numpy as np
|
| 49 |
+
|
| 50 |
+
# Load the metric with canvas dimensions
|
| 51 |
+
metric = evaluate.load(
|
| 52 |
+
"creative-graphic-design/layout-overlay",
|
| 53 |
+
canvas_width=360,
|
| 54 |
+
canvas_height=504,
|
| 55 |
+
decoration_label_index=3 # underlay/decoration class
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
# Prepare data
|
| 59 |
+
predictions = np.random.rand(1, 25, 4) # normalized ltrb coordinates
|
| 60 |
+
gold_labels = np.random.randint(0, 4, size=(1, 25)) # class labels
|
| 61 |
+
score = metric.compute(predictions=predictions, gold_labels=gold_labels)
|
| 62 |
+
print(score)
|
| 63 |
+
```
|
| 64 |
+
|
| 65 |
+
### Batch Processing Example
|
| 66 |
+
|
| 67 |
+
```python
|
| 68 |
+
import evaluate
|
| 69 |
+
import numpy as np
|
| 70 |
+
|
| 71 |
+
# Load the metric
|
| 72 |
+
metric = evaluate.load(
|
| 73 |
+
"creative-graphic-design/layout-overlay",
|
| 74 |
+
canvas_width=360,
|
| 75 |
+
canvas_height=504,
|
| 76 |
+
decoration_label_index=3
|
| 77 |
+
)
|
| 78 |
+
|
| 79 |
+
# Batch processing
|
| 80 |
+
batch_size = 128
|
| 81 |
+
predictions = np.random.rand(batch_size, 25, 4)
|
| 82 |
+
gold_labels = np.random.randint(0, 4, size=(batch_size, 25))
|
| 83 |
+
score = metric.compute(predictions=predictions, gold_labels=gold_labels)
|
| 84 |
+
print(score)
|
| 85 |
+
```
|
| 86 |
+
|
| 87 |
+
## Parameters
|
| 88 |
+
|
| 89 |
+
### Initialization Parameters
|
| 90 |
+
|
| 91 |
+
- **canvas_width** (`int`, required): Width of the canvas in pixels
|
| 92 |
+
- **canvas_height** (`int`, required): Height of the canvas in pixels
|
| 93 |
+
- **decoration_label_index** (`int`, optional, default=3): Class index for underlay/decoration elements to exclude
|
| 94 |
+
|
| 95 |
+
### Computation Parameters
|
| 96 |
+
|
| 97 |
+
- **predictions** (`list` of `lists` of `float`): Normalized bounding boxes in ltrb format (0.0 to 1.0)
|
| 98 |
+
- **gold_labels** (`list` of `lists` of `int`): Class labels for each element (0 = padding)
|
| 99 |
+
|
| 100 |
+
**Note**:
|
| 101 |
+
|
| 102 |
+
- Elements with label == 0 are treated as padding
|
| 103 |
+
- Elements with label == decoration_label_index are excluded (underlay)
|
| 104 |
+
- Very small elements (< 0.1% of canvas) are filtered out
|
| 105 |
+
|
| 106 |
+
## Returns
|
| 107 |
+
|
| 108 |
+
Returns a `float` value representing the average IoU of overlapping element pairs (excluding underlay).
|
| 109 |
+
|
| 110 |
+
## Interpretation
|
| 111 |
+
|
| 112 |
+
- **Lower is better** (range: 0.0 to 1.0)
|
| 113 |
+
- **Value of 0.0**: No overlap between foreground elements (ideal)
|
| 114 |
+
- **Value of 0.1-0.3**: Minor overlap, possibly acceptable in dense layouts
|
| 115 |
+
- **Value of 0.3-0.5**: Moderate overlap, may indicate placement issues
|
| 116 |
+
- **Value > 0.5**: Significant overlap, likely problematic
|
| 117 |
+
|
| 118 |
+
### Use Cases
|
| 119 |
+
|
| 120 |
+
- **Poster/presentation layout evaluation**: Ensure foreground elements don't overlap excessively
|
| 121 |
+
- **Content-aware design**: Evaluate layouts with distinct foreground and background layers
|
| 122 |
+
- **Layered designs**: Assess foreground element placement independent of decoration layers
|
| 123 |
+
- **Multi-layer layouts**: Focus on collision detection for primary content
|
| 124 |
+
|
| 125 |
+
### Key Insights
|
| 126 |
+
|
| 127 |
+
- **Underlay exclusion is important**: Decoration elements are meant to be behind others
|
| 128 |
+
- **Context-specific**: Appropriate for designs with clear foreground/background separation
|
| 129 |
+
- **Different from general overlap**: Focuses only on foreground element interactions
|
| 130 |
+
- **Use with related metrics**: Combine with underlay effectiveness for full picture
|
| 131 |
+
|
| 132 |
+
## Citations
|
| 133 |
+
|
| 134 |
+
```bibtex
|
| 135 |
+
@inproceedings{hsu2023posterlayout,
|
| 136 |
+
title={Posterlayout: A new benchmark and approach for content-aware visual-textual presentation layout},
|
| 137 |
+
author={Hsu, Hsiao Yuan and He, Xiangteng and Peng, Yuxin and Kong, Hao and Zhang, Qing},
|
| 138 |
+
booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
|
| 139 |
+
pages={6018--6026},
|
| 140 |
+
year={2023}
|
| 141 |
+
}
|
| 142 |
+
```
|
| 143 |
+
|
| 144 |
+
## References
|
| 145 |
+
|
| 146 |
+
- **Paper**: [PosterLayout (Hsu et al., CVPR 2023)](https://arxiv.org/abs/2303.15937)
|
| 147 |
+
- **Reference Implementation**: [PosterLayout eval.py](https://github.com/PKU-ICST-MIPL/PosterLayout-CVPR2023/blob/main/eval.py#L205-L222)
|
| 148 |
+
|
| 149 |
+
## Related Metrics
|
| 150 |
+
|
| 151 |
+
- [Layout Overlap](../layout_overlap/): General overlap metric for all elements
|
| 152 |
+
- [Layout Underlay Effectiveness](../layout_underlay_effectiveness/): Evaluates underlay element placement
|
| 153 |
+
- [Layout Average IoU](../layout_average_iou/): IoU-based overlap for all elements
|
| 154 |
+
- [Layout Validity](../layout_validity/): Checks basic validity constraints
|
layout-overlay.py
CHANGED
|
@@ -4,13 +4,22 @@ import datasets as ds
|
|
| 4 |
import evaluate
|
| 5 |
import numpy as np
|
| 6 |
import numpy.typing as npt
|
|
|
|
| 7 |
|
| 8 |
_DESCRIPTION = r"""\
|
| 9 |
Computes the average IoU of all pairs of elements except for underlay.
|
| 10 |
"""
|
| 11 |
|
| 12 |
_KWARGS_DESCRIPTION = """\
|
| 13 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
"""
|
| 15 |
|
| 16 |
_CITATION = """\
|
|
@@ -24,16 +33,19 @@ _CITATION = """\
|
|
| 24 |
"""
|
| 25 |
|
| 26 |
|
|
|
|
| 27 |
class LayoutOverlay(evaluate.Metric):
|
| 28 |
def __init__(
|
| 29 |
self,
|
| 30 |
canvas_width: int,
|
| 31 |
canvas_height: int,
|
|
|
|
| 32 |
**kwargs,
|
| 33 |
) -> None:
|
| 34 |
super().__init__(**kwargs)
|
| 35 |
self.canvas_width = canvas_width
|
| 36 |
self.canvas_height = canvas_height
|
|
|
|
| 37 |
|
| 38 |
def _info(self) -> evaluate.EvaluationModuleInfo:
|
| 39 |
return evaluate.MetricInfo(
|
|
@@ -114,8 +126,13 @@ class LayoutOverlay(evaluate.Metric):
|
|
| 114 |
|
| 115 |
for gold_label, prediction in zip(gold_labels, predictions):
|
| 116 |
ove = 0.0
|
| 117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 118 |
mask_box = prediction[mask]
|
|
|
|
| 119 |
n = len(mask_box)
|
| 120 |
for i in range(n):
|
| 121 |
bb1 = mask_box[i]
|
|
|
|
| 4 |
import evaluate
|
| 5 |
import numpy as np
|
| 6 |
import numpy.typing as npt
|
| 7 |
+
from evaluate.utils.file_utils import add_start_docstrings
|
| 8 |
|
| 9 |
_DESCRIPTION = r"""\
|
| 10 |
Computes the average IoU of all pairs of elements except for underlay.
|
| 11 |
"""
|
| 12 |
|
| 13 |
_KWARGS_DESCRIPTION = """\
|
| 14 |
+
Args:
|
| 15 |
+
predictions (`list` of `lists` of `float`): A list of lists of floats representing normalized `ltrb`-format bounding boxes.
|
| 16 |
+
gold_labels (`list` of `lists` of `int`): A list of lists of integers representing class labels.
|
| 17 |
+
|
| 18 |
+
Ruturns:
|
| 19 |
+
float: Average IoU except decoration (i.e., underlay) elements (used in PosterLayout).
|
| 20 |
+
|
| 21 |
+
Examples::
|
| 22 |
+
FIXME
|
| 23 |
"""
|
| 24 |
|
| 25 |
_CITATION = """\
|
|
|
|
| 33 |
"""
|
| 34 |
|
| 35 |
|
| 36 |
+
@add_start_docstrings(_DESCRIPTION, _KWARGS_DESCRIPTION)
|
| 37 |
class LayoutOverlay(evaluate.Metric):
|
| 38 |
def __init__(
|
| 39 |
self,
|
| 40 |
canvas_width: int,
|
| 41 |
canvas_height: int,
|
| 42 |
+
decoration_label_index: int = 3,
|
| 43 |
**kwargs,
|
| 44 |
) -> None:
|
| 45 |
super().__init__(**kwargs)
|
| 46 |
self.canvas_width = canvas_width
|
| 47 |
self.canvas_height = canvas_height
|
| 48 |
+
self.decoration_label_index = decoration_label_index
|
| 49 |
|
| 50 |
def _info(self) -> evaluate.EvaluationModuleInfo:
|
| 51 |
return evaluate.MetricInfo(
|
|
|
|
| 126 |
|
| 127 |
for gold_label, prediction in zip(gold_labels, predictions):
|
| 128 |
ove = 0.0
|
| 129 |
+
|
| 130 |
+
cond1 = (gold_label > 0).reshape(-1)
|
| 131 |
+
cond2 = (gold_label != self.decoration_label_index).reshape(-1)
|
| 132 |
+
|
| 133 |
+
mask = cond1 & cond2
|
| 134 |
mask_box = prediction[mask]
|
| 135 |
+
|
| 136 |
n = len(mask_box)
|
| 137 |
for i in range(n):
|
| 138 |
bb1 = mask_box[i]
|
requirements.txt
CHANGED
|
@@ -1,89 +1,134 @@
|
|
| 1 |
-
|
| 2 |
-
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
|
| 18 |
-
|
| 19 |
-
|
| 20 |
-
|
| 21 |
-
|
| 22 |
-
|
| 23 |
-
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
|
| 28 |
-
|
| 29 |
-
|
| 30 |
-
|
| 31 |
-
|
| 32 |
-
|
| 33 |
-
|
| 34 |
-
|
| 35 |
-
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
| 41 |
-
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
-
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
| 51 |
-
|
| 52 |
-
|
| 53 |
-
|
| 54 |
-
|
| 55 |
-
|
| 56 |
-
|
| 57 |
-
|
| 58 |
-
|
| 59 |
-
|
| 60 |
-
|
| 61 |
-
|
| 62 |
-
|
| 63 |
-
|
| 64 |
-
|
| 65 |
-
|
| 66 |
-
requests
|
| 67 |
-
|
| 68 |
-
|
| 69 |
-
|
| 70 |
-
|
| 71 |
-
|
| 72 |
-
|
| 73 |
-
|
| 74 |
-
|
| 75 |
-
|
| 76 |
-
|
| 77 |
-
|
| 78 |
-
|
| 79 |
-
|
| 80 |
-
|
| 81 |
-
|
| 82 |
-
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
-
|
| 89 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file was autogenerated by uv via the following command:
|
| 2 |
+
# uv export --package layout_overlay --no-dev --no-hashes --format requirements-txt
|
| 3 |
+
aiohappyeyeballs==2.6.1
|
| 4 |
+
# via aiohttp
|
| 5 |
+
aiohttp==3.13.2
|
| 6 |
+
# via fsspec
|
| 7 |
+
aiosignal==1.4.0
|
| 8 |
+
# via aiohttp
|
| 9 |
+
anyio==4.12.0
|
| 10 |
+
# via httpx
|
| 11 |
+
attrs==25.4.0
|
| 12 |
+
# via aiohttp
|
| 13 |
+
certifi==2025.11.12
|
| 14 |
+
# via
|
| 15 |
+
# httpcore
|
| 16 |
+
# httpx
|
| 17 |
+
# requests
|
| 18 |
+
charset-normalizer==3.4.4
|
| 19 |
+
# via requests
|
| 20 |
+
click==8.3.1
|
| 21 |
+
# via typer-slim
|
| 22 |
+
colorama==0.4.6 ; sys_platform == 'win32'
|
| 23 |
+
# via
|
| 24 |
+
# click
|
| 25 |
+
# tqdm
|
| 26 |
+
datasets==4.4.2
|
| 27 |
+
# via evaluate
|
| 28 |
+
dill==0.4.0
|
| 29 |
+
# via
|
| 30 |
+
# datasets
|
| 31 |
+
# evaluate
|
| 32 |
+
# multiprocess
|
| 33 |
+
evaluate==0.4.6
|
| 34 |
+
# via layout-overlay
|
| 35 |
+
filelock==3.20.1
|
| 36 |
+
# via
|
| 37 |
+
# datasets
|
| 38 |
+
# huggingface-hub
|
| 39 |
+
frozenlist==1.8.0
|
| 40 |
+
# via
|
| 41 |
+
# aiohttp
|
| 42 |
+
# aiosignal
|
| 43 |
+
fsspec==2025.10.0
|
| 44 |
+
# via
|
| 45 |
+
# datasets
|
| 46 |
+
# evaluate
|
| 47 |
+
# huggingface-hub
|
| 48 |
+
h11==0.16.0
|
| 49 |
+
# via httpcore
|
| 50 |
+
hf-xet==1.2.0 ; platform_machine == 'AMD64' or platform_machine == 'aarch64' or platform_machine == 'amd64' or platform_machine == 'arm64' or platform_machine == 'x86_64'
|
| 51 |
+
# via huggingface-hub
|
| 52 |
+
httpcore==1.0.9
|
| 53 |
+
# via httpx
|
| 54 |
+
httpx==0.28.1
|
| 55 |
+
# via
|
| 56 |
+
# datasets
|
| 57 |
+
# huggingface-hub
|
| 58 |
+
huggingface-hub==1.2.3
|
| 59 |
+
# via
|
| 60 |
+
# datasets
|
| 61 |
+
# evaluate
|
| 62 |
+
idna==3.11
|
| 63 |
+
# via
|
| 64 |
+
# anyio
|
| 65 |
+
# httpx
|
| 66 |
+
# requests
|
| 67 |
+
# yarl
|
| 68 |
+
multidict==6.7.0
|
| 69 |
+
# via
|
| 70 |
+
# aiohttp
|
| 71 |
+
# yarl
|
| 72 |
+
multiprocess==0.70.18
|
| 73 |
+
# via
|
| 74 |
+
# datasets
|
| 75 |
+
# evaluate
|
| 76 |
+
numpy==2.2.6
|
| 77 |
+
# via
|
| 78 |
+
# datasets
|
| 79 |
+
# evaluate
|
| 80 |
+
# pandas
|
| 81 |
+
packaging==25.0
|
| 82 |
+
# via
|
| 83 |
+
# datasets
|
| 84 |
+
# evaluate
|
| 85 |
+
# huggingface-hub
|
| 86 |
+
pandas==2.3.3
|
| 87 |
+
# via
|
| 88 |
+
# datasets
|
| 89 |
+
# evaluate
|
| 90 |
+
propcache==0.4.1
|
| 91 |
+
# via
|
| 92 |
+
# aiohttp
|
| 93 |
+
# yarl
|
| 94 |
+
pyarrow==22.0.0
|
| 95 |
+
# via datasets
|
| 96 |
+
python-dateutil==2.9.0.post0
|
| 97 |
+
# via pandas
|
| 98 |
+
pytz==2025.2
|
| 99 |
+
# via pandas
|
| 100 |
+
pyyaml==6.0.3
|
| 101 |
+
# via
|
| 102 |
+
# datasets
|
| 103 |
+
# huggingface-hub
|
| 104 |
+
requests==2.32.5
|
| 105 |
+
# via
|
| 106 |
+
# datasets
|
| 107 |
+
# evaluate
|
| 108 |
+
shellingham==1.5.4
|
| 109 |
+
# via huggingface-hub
|
| 110 |
+
six==1.17.0
|
| 111 |
+
# via python-dateutil
|
| 112 |
+
tqdm==4.67.1
|
| 113 |
+
# via
|
| 114 |
+
# datasets
|
| 115 |
+
# evaluate
|
| 116 |
+
# huggingface-hub
|
| 117 |
+
typer-slim==0.21.0
|
| 118 |
+
# via huggingface-hub
|
| 119 |
+
typing-extensions==4.15.0
|
| 120 |
+
# via
|
| 121 |
+
# aiosignal
|
| 122 |
+
# anyio
|
| 123 |
+
# huggingface-hub
|
| 124 |
+
# typer-slim
|
| 125 |
+
tzdata==2025.3
|
| 126 |
+
# via pandas
|
| 127 |
+
urllib3==2.6.2
|
| 128 |
+
# via requests
|
| 129 |
+
xxhash==3.6.0
|
| 130 |
+
# via
|
| 131 |
+
# datasets
|
| 132 |
+
# evaluate
|
| 133 |
+
yarl==1.22.0
|
| 134 |
+
# via aiohttp
|