Skip to content

Commit d07415b

Browse files
committed
feat(visualize_order_annotations_{single_page, two_page}.py): add order annotation visualization
1 parent fe4e2ee commit d07415b

2 files changed

Lines changed: 320 additions & 0 deletions

File tree

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
import argparse
2+
from collections import defaultdict
3+
import math
4+
import os
5+
from typing import Tuple
6+
from PIL import Image, ImageDraw
7+
from matplotlib import pyplot as plt
8+
9+
from vrdu import utils
10+
11+
12+
def arrowedLine(
13+
image: Image.Image,
14+
point_A: Tuple[float, float],
15+
point_B: Tuple[float, float],
16+
width=1,
17+
color=(0, 255, 0),
18+
) -> Image.Image:
19+
"""Draw a line from point_A to point_B with an arrow headed at ppoint_B."""
20+
draw = ImageDraw.Draw(image)
21+
draw.line((point_A, point_B), width=width, fill=color)
22+
23+
# Calculate arrowhead vertices
24+
x0, y0 = point_A
25+
x1, y1 = point_B
26+
xb = 0.95 * (x1 - x0) + x0
27+
yb = 0.95 * (y1 - y0) + y0
28+
alpha = math.atan2(y1 - y0, x1 - x0) - 90 * math.pi / 180
29+
a = 8 * math.cos(alpha)
30+
b = 8 * math.sin(alpha)
31+
vtx0 = (xb + a, yb + b)
32+
vtx1 = (xb - a, yb - b)
33+
34+
# Draw the arrowhead triangle
35+
draw.polygon([vtx0, vtx1, point_B], fill=color)
36+
return image
37+
38+
39+
def visualize_order_annotation_single_page(path: str, page_index: int) -> None:
40+
order_annotation_file = os.path.join(path, "order_annotation.json")
41+
image_file = os.path.join(path, f"page_{page_index:04}.jpg")
42+
43+
# extract blocks in this page
44+
order_annotation_data = utils.load_json(order_annotation_file)
45+
page_blocks = defaultdict(list)
46+
id2blocks = {}
47+
page2id2 = defaultdict(list)
48+
for block in order_annotation_data["annotations"]:
49+
page_blocks[block["page_index"]].append(block)
50+
id2blocks[block["block_id"]] = block
51+
page2id2[block["page_index"]].append(block["block_id"])
52+
53+
page_relations = []
54+
for item in order_annotation_data["orders"]:
55+
if item["from"] not in page2id2[page_index]:
56+
continue
57+
if item["to"] not in page2id2[page_index]:
58+
continue
59+
page_relations.append(item)
60+
61+
# visualize
62+
image = Image.open(image_file)
63+
width, height = image.size
64+
65+
fig, (ax1, ax2) = plt.subplots(
66+
2, 1, figsize=(16, 20), gridspec_kw={"height_ratios": [5, 1]}
67+
)
68+
ax1.imshow(image, extent=[0, width, height, 0])
69+
ax1.set_xlim(0, width)
70+
ax1.set_ylim(height, 0)
71+
color_map = {
72+
"identical": "green",
73+
"adj": "blue",
74+
"peer": "red",
75+
"implicit-cite": "purple",
76+
"explicit-cite": "brown",
77+
"sub": "orange",
78+
"unknown": "black",
79+
}
80+
81+
for relation in page_relations:
82+
print(relation)
83+
block_from = id2blocks[relation["from"]]
84+
block_to = id2blocks[relation["to"]]
85+
center_from = (
86+
(block_from["bbox"][0] + block_from["bbox"][2]) / 2,
87+
(block_from["bbox"][1] + block_from["bbox"][3]) / 2,
88+
)
89+
center_to = (
90+
(block_to["bbox"][0] + block_to["bbox"][2]) / 2,
91+
(block_to["bbox"][1] + block_to["bbox"][3]) / 2,
92+
)
93+
ax1.arrow(
94+
center_from[0],
95+
center_from[1],
96+
center_to[0] - center_from[0],
97+
center_to[1] - center_from[1],
98+
fc=color_map[relation["type"]],
99+
ec=color_map[relation["type"]],
100+
width=3,
101+
)
102+
ax1.axis("off")
103+
104+
legend_handles = []
105+
legend_labels = []
106+
for relation_type, color in color_map.items():
107+
legend_handles.append(
108+
plt.Line2D(
109+
[0], [0], color=color, marker="o", linestyle="", label=relation_type
110+
)
111+
)
112+
legend_labels.append(relation_type)
113+
114+
# Add the legend to ax2
115+
ax2.legend(
116+
handles=legend_handles,
117+
labels=legend_labels,
118+
loc="upper center",
119+
ncol=len(legend_handles),
120+
)
121+
ax2.axis("off")
122+
plt.tight_layout()
123+
124+
# plt.show()
125+
plt.savefig("output/order_annotation.png", dpi=200)
126+
127+
128+
def main() -> None:
129+
parser = argparse.ArgumentParser()
130+
parser.add_argument("-p", "--path", help="path to the path", type=str)
131+
parser.add_argument("-i", "--page_index", help="page index", type=int)
132+
args = parser.parse_args()
133+
134+
path = args.path
135+
page_index = args.page_index
136+
137+
visualize_order_annotation_single_page(path, page_index)
138+
139+
140+
if __name__ == "__main__":
141+
main()
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
import argparse
2+
from collections import defaultdict
3+
import math
4+
import os
5+
from typing import Tuple
6+
from PIL import Image, ImageDraw
7+
from matplotlib import pyplot as plt
8+
9+
from vrdu import utils
10+
11+
12+
def arrowedLine(
13+
image: Image.Image,
14+
point_A: Tuple[float, float],
15+
point_B: Tuple[float, float],
16+
width=1,
17+
color=(0, 255, 0),
18+
) -> Image.Image:
19+
"""Draw a line from point_A to point_B with an arrow headed at ppoint_B."""
20+
draw = ImageDraw.Draw(image)
21+
draw.line((point_A, point_B), width=width, fill=color)
22+
23+
# Calculate arrowhead vertices
24+
x0, y0 = point_A
25+
x1, y1 = point_B
26+
xb = 0.95 * (x1 - x0) + x0
27+
yb = 0.95 * (y1 - y0) + y0
28+
alpha = math.atan2(y1 - y0, x1 - x0) - 90 * math.pi / 180
29+
a = 8 * math.cos(alpha)
30+
b = 8 * math.sin(alpha)
31+
vtx0 = (xb + a, yb + b)
32+
vtx1 = (xb - a, yb - b)
33+
34+
# Draw the arrowhead triangle
35+
draw.polygon([vtx0, vtx1, point_B], fill=color)
36+
return image
37+
38+
39+
def visualize_order_annotation_across_pages(path: str, page_index: int) -> None:
40+
order_annotation_file = os.path.join(path, "order_annotation.json")
41+
image_file1 = os.path.join(path, f"page_{page_index:04}.jpg")
42+
image_file2 = os.path.join(path, f"page_{page_index+1:04}.jpg")
43+
44+
# extract blocks in this page
45+
order_annotation_data = utils.load_json(order_annotation_file)
46+
page_blocks = defaultdict(list)
47+
id2blocks = {}
48+
page2id2 = defaultdict(list)
49+
for block in order_annotation_data["annotations"]:
50+
page_blocks[block["page_index"]].append(block)
51+
id2blocks[block["block_id"]] = block
52+
page2id2[block["page_index"]].append(block["block_id"])
53+
54+
page_relations = []
55+
for item in order_annotation_data["orders"]:
56+
if item["from"] not in page2id2[page_index] + page2id2[page_index + 1]:
57+
continue
58+
if item["to"] not in page2id2[page_index] + page2id2[page_index + 1]:
59+
continue
60+
page_relations.append(item)
61+
62+
# visualize
63+
image1 = Image.open(image_file1)
64+
65+
image2 = Image.open(image_file2)
66+
67+
# crop
68+
margin = 150
69+
h_margin = margin
70+
v_margin = margin * 17 / 22
71+
bbox = (v_margin, h_margin, 1700 - v_margin * 2.2, 2200 - h_margin * 0.9)
72+
image1 = image1.crop(bbox)
73+
image2 = image2.crop(bbox)
74+
75+
width, height = image1.size
76+
new_width = image1.width + image2.width
77+
new_image = Image.new("RGB", (new_width, height))
78+
new_image.paste(image1, (0, 0))
79+
new_image.paste(image2, (image1.width, 0))
80+
new_image.save(f"concatenated_image_{page_index}_{page_index+1}.png")
81+
82+
fig, (ax1, ax2) = plt.subplots(
83+
2, 1, figsize=(17, 22) # , gridspec_kw={"height_ratios": [4, 1]}
84+
)
85+
ax1.imshow(new_image, extent=[0, new_width, height, 0])
86+
ax1.set_xlim(0, new_width)
87+
ax1.set_ylim(height, 0)
88+
color_map = {
89+
"identical": "green",
90+
"adj": "blue",
91+
"peer": "red",
92+
"implicit-cite": "purple",
93+
"explicit-cite": "brown",
94+
"sub": "orange",
95+
}
96+
97+
for relation in page_relations:
98+
print(relation)
99+
block_from = id2blocks[relation["from"]]
100+
block_to = id2blocks[relation["to"]]
101+
if block_from["page_index"] != page_index:
102+
center_from = (
103+
width + (block_from["bbox"][0] + block_from["bbox"][2]) / 2,
104+
(block_from["bbox"][1] + block_from["bbox"][3]) / 2,
105+
)
106+
else:
107+
center_from = (
108+
(block_from["bbox"][0] + block_from["bbox"][2]) / 2,
109+
(block_from["bbox"][1] + block_from["bbox"][3]) / 2,
110+
)
111+
112+
if block_to["page_index"] != page_index:
113+
center_to = (
114+
width + (block_to["bbox"][0] + block_to["bbox"][2]) / 2,
115+
(block_to["bbox"][1] + block_to["bbox"][3]) / 2,
116+
)
117+
else:
118+
center_to = (
119+
(block_to["bbox"][0] + block_to["bbox"][2]) / 2,
120+
(block_to["bbox"][1] + block_to["bbox"][3]) / 2,
121+
)
122+
ax1.arrow(
123+
center_from[0] - margin,
124+
center_from[1] - margin,
125+
center_to[0] - center_from[0],
126+
center_to[1] - center_from[1],
127+
fc=color_map[relation["type"]],
128+
ec=color_map[relation["type"]],
129+
width=3,
130+
)
131+
ax1.axis("off")
132+
133+
legend_handles = []
134+
legend_labels = []
135+
relation_type_maps = {
136+
"identical": "identical",
137+
"adj": "non-title adjac",
138+
"peer": "title adjacent",
139+
"implicit-cite": "implicitly-referred",
140+
"explicit-cite": "explicitly-referred",
141+
"sub": "subordinate",
142+
}
143+
for relation_type, color in color_map.items():
144+
legend_handles.append(
145+
plt.Line2D(
146+
[0], [0], color=color, marker="o", linestyle="", label=relation_type
147+
)
148+
)
149+
legend_labels.append(relation_type_maps[relation_type])
150+
151+
# Add the legend to ax2
152+
ax2.legend(
153+
handles=legend_handles,
154+
labels=legend_labels,
155+
loc="upper center",
156+
ncol=len(legend_handles),
157+
)
158+
ax2.axis("off")
159+
plt.tight_layout()
160+
161+
# plt.show()
162+
163+
plt.savefig(f"output/order_annotation_{page_index}_{page_index + 1}.png", dpi=200)
164+
165+
166+
def main() -> None:
167+
parser = argparse.ArgumentParser()
168+
parser.add_argument("-p", "--path", help="path to the path", type=str)
169+
parser.add_argument("-i", "--page_index", help="page index", type=int)
170+
args = parser.parse_args()
171+
172+
path = args.path
173+
page_index = args.page_index
174+
175+
visualize_order_annotation_across_pages(path, page_index)
176+
177+
178+
if __name__ == "__main__":
179+
main()

0 commit comments

Comments
 (0)