shunk031 commited on
Commit
b2214a3
·
1 Parent(s): 7914fea

deploy: 63a85616f5fc427cf1e1e7b425293131f2fce2b8

Browse files
Files changed (3) hide show
  1. README.md +161 -1
  2. layout-unreadability.py +5 -3
  3. requirements.txt +139 -90
README.md CHANGED
@@ -8,4 +8,164 @@ sdk_version: 4.36.1
8
  app_file: app.py
9
  pinned: false
10
  ---
11
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
8
  app_file: app.py
9
  pinned: false
10
  ---
11
+
12
+ # Layout Unreadability
13
+
14
+ ## Description
15
+
16
+ The Layout Unreadability metric evaluates whether text elements are placed on visually complex or non-flat background regions that could impair readability. This metric computes the non-flatness (gradient intensity) of regions where text is positioned, helping assess whether text placement respects readability principles in content-aware layout design.
17
+
18
+ ## What It Measures
19
+
20
+ This metric computes:
21
+
22
+ - **Background complexity under text**: Gradient intensity in regions occupied by text elements
23
+ - **Text readability risk**: Whether text is placed on busy or complex backgrounds
24
+ - **Content-awareness**: How well the layout avoids placing text on unsuitable regions
25
+
26
+ Lower scores indicate better text placement on flat, readable backgrounds.
27
+
28
+ ## Metric Details
29
+
30
+ - Uses Sobel gradient operators to detect edges and texture in background canvas
31
+ - Computes gradient magnitude (non-flatness) in regions covered by text elements
32
+ - Excludes underlay/decoration elements from background canvas analysis
33
+ - From PosterLayout (Hsu et al., CVPR 2023) and CGL-GAN methodology
34
+ - Lower gradient scores mean text is on flatter, more readable backgrounds
35
+
36
+ ## Usage
37
+
38
+ ### Installation
39
+
40
+ ```bash
41
+ pip install evaluate opencv-python
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-unreadability",
53
+ canvas_width=360,
54
+ canvas_height=504,
55
+ text_label_index=1,
56
+ decoration_label_index=3
57
+ )
58
+
59
+ # Prepare data
60
+ predictions = np.random.rand(1, 25, 4) # normalized ltrb coordinates
61
+ gold_labels = np.random.randint(0, 4, size=(1, 25)) # class labels
62
+ # Paths to canvas background images
63
+ image_canvases = ["path/to/canvas_image.jpg"]
64
+
65
+ score = metric.compute(
66
+ predictions=predictions,
67
+ gold_labels=gold_labels,
68
+ image_canvases=image_canvases
69
+ )
70
+ print(score)
71
+ ```
72
+
73
+ ### Batch Processing Example
74
+
75
+ ```python
76
+ import evaluate
77
+
78
+ # Load the metric
79
+ metric = evaluate.load(
80
+ "creative-graphic-design/layout-unreadability",
81
+ canvas_width=360,
82
+ canvas_height=504,
83
+ text_label_index=1,
84
+ decoration_label_index=3
85
+ )
86
+
87
+ # Batch processing
88
+ batch_size = 128
89
+ predictions = np.random.rand(batch_size, 25, 4)
90
+ gold_labels = np.random.randint(0, 4, size=(batch_size, 25))
91
+ image_canvases = [f"path/to/canvas_{i}.jpg" for i in range(batch_size)]
92
+
93
+ score = metric.compute(
94
+ predictions=predictions,
95
+ gold_labels=gold_labels,
96
+ image_canvases=image_canvases
97
+ )
98
+ print(score)
99
+ ```
100
+
101
+ ## Parameters
102
+
103
+ ### Initialization Parameters
104
+
105
+ - **canvas_width** (`int`, required): Width of the canvas in pixels
106
+ - **canvas_height** (`int`, required): Height of the canvas in pixels
107
+ - **text_label_index** (`int`, optional, default=1): Class index for text elements
108
+ - **decoration_label_index** (`int`, optional, default=3): Class index for underlay/decoration elements to mask out
109
+
110
+ ### Computation Parameters
111
+
112
+ - **predictions** (`list` of `lists` of `float`): Normalized bounding boxes in ltrb format (0.0 to 1.0)
113
+ - **gold_labels** (`list` of `lists` of `int`): Class labels for each element (0 = padding)
114
+ - **image_canvases** (`list` of `str`): File paths to canvas background images
115
+
116
+ **Note**:
117
+
118
+ - Canvas images should show the background content (photos, graphics) where layout will be placed
119
+ - Underlay/decoration elements are masked out before computing gradients
120
+ - Only text elements (text_label_index) are evaluated for readability
121
+
122
+ ## Returns
123
+
124
+ Returns a `float` value representing the average gradient intensity under text elements (range: 0.0 to 1.0).
125
+
126
+ ## Interpretation
127
+
128
+ - **Lower is better** (range: 0.0 to 1.0)
129
+ - **Value ~0.0**: Text placed on flat, uniform backgrounds (ideal for readability)
130
+ - **Value 0.0-0.2**: Good text placement on relatively flat regions
131
+ - **Value 0.2-0.4**: Moderate background complexity, may affect readability
132
+ - **Value 0.4-0.6**: High background complexity, readability concerns
133
+ - **Value > 0.6**: Very complex backgrounds under text (poor placement)
134
+
135
+ ### Use Cases
136
+
137
+ - **Content-aware poster generation**: Ensure text is readable on background imagery
138
+ - **Advertisement layout**: Place call-to-action text on suitable backgrounds
139
+ - **Presentation slides**: Validate text visibility on photo backgrounds
140
+ - **Magazine/flyer design**: Assess text-background contrast and readability
141
+
142
+ ### Key Insights
143
+
144
+ - **Readability principle**: Text should be on flat or low-detail backgrounds
145
+ - **Design solutions**: Use underlay/decoration elements to create readable regions
146
+ - **Trade-off**: Sometimes text must go on complex backgrounds (consider semi-transparent overlays)
147
+ - **Context matters**: Title text may tolerate more complexity than body text
148
+
149
+ ## Citations
150
+
151
+ ```bibtex
152
+ @inproceedings{hsu2023posterlayout,
153
+ title={Posterlayout: A new benchmark and approach for content-aware visual-textual presentation layout},
154
+ author={Hsu, Hsiao Yuan and He, Xiangteng and Peng, Yuxin and Kong, Hao and Zhang, Qing},
155
+ booktitle={Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition},
156
+ pages={6018--6026},
157
+ year={2023}
158
+ }
159
+ ```
160
+
161
+ ## References
162
+
163
+ - **Paper**: [PosterLayout (Hsu et al., CVPR 2023)](https://arxiv.org/abs/2303.15937)
164
+ - **Reference Implementation**: [PosterLayout eval.py](https://github.com/PKU-ICST-MIPL/PosterLayout-CVPR2023/blob/main/eval.py#L144-L171)
165
+ - **Related**: CGL-GAN text readability evaluation
166
+
167
+ ## Related Metrics
168
+
169
+ - [Layout Occlusion](../layout_occlusion/): Evaluates coverage of salient regions
170
+ - [Layout Utility](../layout_utility/): Measures utilization of suitable space
171
+ - [Layout Underlay Effectiveness](../layout_underlay_effectiveness/): Evaluates underlay placement
layout-unreadability.py CHANGED
@@ -6,6 +6,7 @@ import datasets as ds
6
  import evaluate
7
  import numpy as np
8
  import numpy.typing as npt
 
9
  from PIL import Image
10
  from PIL.Image import Image as PilImage
11
 
@@ -30,6 +31,7 @@ _CITATION = """\
30
  ReqType = Literal["pil2cv", "cv2pil"]
31
 
32
 
 
33
  class LayoutUnreadability(evaluate.Metric):
34
  def __init__(
35
  self,
@@ -72,7 +74,7 @@ class LayoutUnreadability(evaluate.Metric):
72
  if req == "pil2cv":
73
  assert isinstance(img, PilImage)
74
  color_code = color_code or cv2.COLOR_RGB2BGR
75
- return cv2.cvtColor(np.asarray(img), color_code)
76
  elif req == "cv2pil":
77
  assert isinstance(img, np.ndarray)
78
  color_code = color_code or cv2.COLOR_BGR2RGB
@@ -102,9 +104,9 @@ class LayoutUnreadability(evaluate.Metric):
102
  filepath = filepath[0]
103
 
104
  canvas_pil = Image.open(filepath) # type: ignore
105
- canvas_pil = canvas_pil.convert("RGB")
106
  if canvas_pil.size != (self.canvas_width, self.canvas_height):
107
- canvas_pil = canvas_pil.resize((self.canvas_width, self.canvas_height))
108
 
109
  canvas_pil = self.img_to_g_xy(canvas_pil)
110
  assert isinstance(canvas_pil, PilImage)
 
6
  import evaluate
7
  import numpy as np
8
  import numpy.typing as npt
9
+ from evaluate.utils.file_utils import add_start_docstrings
10
  from PIL import Image
11
  from PIL.Image import Image as PilImage
12
 
 
31
  ReqType = Literal["pil2cv", "cv2pil"]
32
 
33
 
34
+ @add_start_docstrings(_DESCRIPTION, _KWARGS_DESCRIPTION)
35
  class LayoutUnreadability(evaluate.Metric):
36
  def __init__(
37
  self,
 
74
  if req == "pil2cv":
75
  assert isinstance(img, PilImage)
76
  color_code = color_code or cv2.COLOR_RGB2BGR
77
+ return cv2.cvtColor(np.asarray(img), color_code) # type: ignore
78
  elif req == "cv2pil":
79
  assert isinstance(img, np.ndarray)
80
  color_code = color_code or cv2.COLOR_BGR2RGB
 
104
  filepath = filepath[0]
105
 
106
  canvas_pil = Image.open(filepath) # type: ignore
107
+ canvas_pil = canvas_pil.convert("RGB") # type: ignore
108
  if canvas_pil.size != (self.canvas_width, self.canvas_height):
109
+ canvas_pil = canvas_pil.resize((self.canvas_width, self.canvas_height)) # type: ignore
110
 
111
  canvas_pil = self.img_to_g_xy(canvas_pil)
112
  assert isinstance(canvas_pil, PilImage)
requirements.txt CHANGED
@@ -1,90 +1,139 @@
1
- aiofiles==23.2.1 ; python_version >= "3.9" and python_version < "4.0"
2
- aiohttp==3.9.3 ; python_version >= "3.9" and python_version < "4.0"
3
- aiosignal==1.3.1 ; python_version >= "3.9" and python_version < "4.0"
4
- altair==5.2.0 ; python_version >= "3.9" and python_version < "4.0"
5
- annotated-types==0.6.0 ; python_version >= "3.9" and python_version < "4.0"
6
- anyio==4.2.0 ; python_version >= "3.9" and python_version < "4.0"
7
- arrow==1.3.0 ; python_version >= "3.9" and python_version < "4.0"
8
- async-timeout==4.0.3 ; python_version >= "3.9" and python_version < "3.11"
9
- attrs==23.2.0 ; python_version >= "3.9" and python_version < "4.0"
10
- binaryornot==0.4.4 ; python_version >= "3.9" and python_version < "4.0"
11
- certifi==2024.2.2 ; python_version >= "3.9" and python_version < "4.0"
12
- chardet==5.2.0 ; python_version >= "3.9" and python_version < "4.0"
13
- charset-normalizer==3.3.2 ; python_version >= "3.9" and python_version < "4.0"
14
- click==8.1.7 ; python_version >= "3.9" and python_version < "4.0"
15
- colorama==0.4.6 ; python_version >= "3.9" and python_version < "4.0"
16
- contourpy==1.2.0 ; python_version >= "3.9" and python_version < "4.0"
17
- cookiecutter==2.5.0 ; python_version >= "3.9" and python_version < "4.0"
18
- cycler==0.12.1 ; python_version >= "3.9" and python_version < "4.0"
19
- datasets==2.17.0 ; python_version >= "3.9" and python_version < "4.0"
20
- dill==0.3.8 ; python_version >= "3.9" and python_version < "4.0"
21
- evaluate[template]==0.4.1 ; python_version >= "3.9" and python_version < "4.0"
22
- exceptiongroup==1.2.0 ; python_version >= "3.9" and python_version < "3.11"
23
- fastapi==0.109.2 ; python_version >= "3.9" and python_version < "4.0"
24
- ffmpy==0.3.1 ; python_version >= "3.9" and python_version < "4.0"
25
- filelock==3.13.1 ; python_version >= "3.9" and python_version < "4.0"
26
- fonttools==4.48.1 ; python_version >= "3.9" and python_version < "4.0"
27
- frozenlist==1.4.1 ; python_version >= "3.9" and python_version < "4.0"
28
- fsspec==2023.10.0 ; python_version >= "3.9" and python_version < "4.0"
29
- fsspec[http]==2023.10.0 ; python_version >= "3.9" and python_version < "4.0"
30
- gradio-client==0.10.0 ; python_version >= "3.9" and python_version < "4.0"
31
- gradio==4.18.0 ; python_version >= "3.9" and python_version < "4.0"
32
- h11==0.14.0 ; python_version >= "3.9" and python_version < "4.0"
33
- httpcore==1.0.2 ; python_version >= "3.9" and python_version < "4.0"
34
- httpx==0.26.0 ; python_version >= "3.9" and python_version < "4.0"
35
- huggingface-hub==0.20.3 ; python_version >= "3.9" and python_version < "4.0"
36
- idna==3.6 ; python_version >= "3.9" and python_version < "4.0"
37
- importlib-resources==6.1.1 ; python_version >= "3.9" and python_version < "4.0"
38
- jinja2==3.1.3 ; python_version >= "3.9" and python_version < "4.0"
39
- jsonschema-specifications==2023.12.1 ; python_version >= "3.9" and python_version < "4.0"
40
- jsonschema==4.21.1 ; python_version >= "3.9" and python_version < "4.0"
41
- kiwisolver==1.4.5 ; python_version >= "3.9" and python_version < "4.0"
42
- markdown-it-py==3.0.0 ; python_version >= "3.9" and python_version < "4.0"
43
- markupsafe==2.1.5 ; python_version >= "3.9" and python_version < "4.0"
44
- matplotlib==3.8.2 ; python_version >= "3.9" and python_version < "4.0"
45
- mdurl==0.1.2 ; python_version >= "3.9" and python_version < "4.0"
46
- multidict==6.0.5 ; python_version >= "3.9" and python_version < "4.0"
47
- multiprocess==0.70.16 ; python_version >= "3.9" and python_version < "4.0"
48
- numpy==1.26.4 ; python_version >= "3.9" and python_version < "4.0"
49
- opencv-python==4.10.0.84 ; python_version >= "3.9" and python_version < "4.0"
50
- orjson==3.9.13 ; python_version >= "3.9" and python_version < "4.0"
51
- packaging==23.2 ; python_version >= "3.9" and python_version < "4.0"
52
- pandas==2.2.0 ; python_version >= "3.9" and python_version < "4.0"
53
- pillow==10.2.0 ; python_version >= "3.9" and python_version < "4.0"
54
- pyarrow-hotfix==0.6 ; python_version >= "3.9" and python_version < "4.0"
55
- pyarrow==15.0.0 ; python_version >= "3.9" and python_version < "4.0"
56
- pydantic-core==2.16.2 ; python_version >= "3.9" and python_version < "4.0"
57
- pydantic==2.6.1 ; python_version >= "3.9" and python_version < "4.0"
58
- pydub==0.25.1 ; python_version >= "3.9" and python_version < "4.0"
59
- pygments==2.17.2 ; python_version >= "3.9" and python_version < "4.0"
60
- pyparsing==3.1.1 ; python_version >= "3.9" and python_version < "4.0"
61
- python-dateutil==2.8.2 ; python_version >= "3.9" and python_version < "4.0"
62
- python-multipart==0.0.9 ; python_version >= "3.9" and python_version < "4.0"
63
- python-slugify==8.0.4 ; python_version >= "3.9" and python_version < "4.0"
64
- pytz==2024.1 ; python_version >= "3.9" and python_version < "4.0"
65
- pyyaml==6.0.1 ; python_version >= "3.9" and python_version < "4.0"
66
- referencing==0.33.0 ; python_version >= "3.9" and python_version < "4.0"
67
- requests==2.31.0 ; python_version >= "3.9" and python_version < "4.0"
68
- responses==0.18.0 ; python_version >= "3.9" and python_version < "4.0"
69
- rich==13.7.0 ; python_version >= "3.9" and python_version < "4.0"
70
- rpds-py==0.17.1 ; python_version >= "3.9" and python_version < "4.0"
71
- ruff==0.2.1 ; python_version >= "3.9" and python_version < "4.0"
72
- semantic-version==2.10.0 ; python_version >= "3.9" and python_version < "4.0"
73
- shellingham==1.5.4 ; python_version >= "3.9" and python_version < "4.0"
74
- six==1.16.0 ; python_version >= "3.9" and python_version < "4.0"
75
- sniffio==1.3.0 ; python_version >= "3.9" and python_version < "4.0"
76
- starlette==0.36.3 ; python_version >= "3.9" and python_version < "4.0"
77
- text-unidecode==1.3 ; python_version >= "3.9" and python_version < "4.0"
78
- tomlkit==0.12.0 ; python_version >= "3.9" and python_version < "4.0"
79
- toolz==0.12.1 ; python_version >= "3.9" and python_version < "4.0"
80
- tqdm==4.66.2 ; python_version >= "3.9" and python_version < "4.0"
81
- typer[all]==0.9.0 ; python_version >= "3.9" and python_version < "4.0"
82
- types-python-dateutil==2.8.19.20240106 ; python_version >= "3.9" and python_version < "4.0"
83
- typing-extensions==4.9.0 ; python_version >= "3.9" and python_version < "4.0"
84
- tzdata==2024.1 ; python_version >= "3.9" and python_version < "4.0"
85
- urllib3==2.2.0 ; python_version >= "3.9" and python_version < "4.0"
86
- uvicorn==0.27.1 ; python_version >= "3.9" and python_version < "4.0"
87
- websockets==11.0.3 ; python_version >= "3.9" and python_version < "4.0"
88
- xxhash==3.4.1 ; python_version >= "3.9" and python_version < "4.0"
89
- yarl==1.9.4 ; python_version >= "3.9" and python_version < "4.0"
90
- zipp==3.17.0 ; python_version >= "3.9" and python_version < "3.10"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # This file was autogenerated by uv via the following command:
2
+ # uv export --package layout_unreadability --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-unreadability
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
+ # opencv-python
81
+ # pandas
82
+ opencv-python==4.12.0.88
83
+ # via layout-unreadability
84
+ packaging==25.0
85
+ # via
86
+ # datasets
87
+ # evaluate
88
+ # huggingface-hub
89
+ pandas==2.3.3
90
+ # via
91
+ # datasets
92
+ # evaluate
93
+ pillow==12.0.0
94
+ # via layout-unreadability
95
+ propcache==0.4.1
96
+ # via
97
+ # aiohttp
98
+ # yarl
99
+ pyarrow==22.0.0
100
+ # via datasets
101
+ python-dateutil==2.9.0.post0
102
+ # via pandas
103
+ pytz==2025.2
104
+ # via pandas
105
+ pyyaml==6.0.3
106
+ # via
107
+ # datasets
108
+ # huggingface-hub
109
+ requests==2.32.5
110
+ # via
111
+ # datasets
112
+ # evaluate
113
+ shellingham==1.5.4
114
+ # via huggingface-hub
115
+ six==1.17.0
116
+ # via python-dateutil
117
+ tqdm==4.67.1
118
+ # via
119
+ # datasets
120
+ # evaluate
121
+ # huggingface-hub
122
+ typer-slim==0.21.0
123
+ # via huggingface-hub
124
+ typing-extensions==4.15.0
125
+ # via
126
+ # aiosignal
127
+ # anyio
128
+ # huggingface-hub
129
+ # typer-slim
130
+ tzdata==2025.3
131
+ # via pandas
132
+ urllib3==2.6.2
133
+ # via requests
134
+ xxhash==3.6.0
135
+ # via
136
+ # datasets
137
+ # evaluate
138
+ yarl==1.22.0
139
+ # via aiohttp