nikigoli commited on
Commit
06bd674
·
verified ·
1 Parent(s): d6e10eb

Upload test_all_prompts.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. test_all_prompts.py +139 -0
test_all_prompts.py ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Run CountGD++ on every prompt combination and save a results table + detection images.
2
+
3
+ Positive prompt: text | exemplars | text + exemplars
4
+ Negative prompt: none | text | exemplars | text + exemplars
5
+ Exemplars from: the counted image itself ("internal") or a separate image ("external")
6
+ Targets: strawberry (negative: blueberry) and blueberry (negative: strawberry)
7
+
8
+ python test_all_prompts.py [--repo nikigoli/CountGDPlusPlus] [--device cuda] [--out prompt_tests]
9
+
10
+ Writes <out>/results.csv, <out>/summary.png (all cases on one sheet) and one
11
+ image per case. img/336.jpg has about 16 strawberries and well over 100 blueberries.
12
+ """
13
+ import argparse
14
+ import csv
15
+ import itertools
16
+ import os
17
+
18
+ import torch
19
+ from PIL import Image, ImageDraw
20
+
21
+ from countgdpp import CountGDPlusPlus, count
22
+
23
+ HERE = os.path.dirname(os.path.abspath(__file__))
24
+ IMG = os.path.join(HERE, "img")
25
+ IMAGE = os.path.join(IMG, "336.jpg")
26
+
27
+ # Visual exemplars as [x1, y1, x2, y2] pixel boxes.
28
+ EXEMPLARS = {
29
+ "strawberry": {
30
+ "internal": (IMAGE, [[158, 62, 206, 134], [95, 133, 145, 184]]),
31
+ "external": (os.path.join(IMG, "synthetic_strawberry.jpg"), [[205, 95, 822, 915]]),
32
+ },
33
+ "blueberry": {
34
+ "internal": (IMAGE, [[235, 38, 259, 62], [330, 165, 356, 192]]),
35
+ "external": (os.path.join(IMG, "synthetic_blueberry.jpg"), [[143, 140, 878, 850]]),
36
+ },
37
+ }
38
+ OTHER = {"strawberry": "blueberry", "blueberry": "strawberry"}
39
+ POS_MODES = ["text", "exemplars", "text+exemplars"]
40
+ NEG_MODES = ["none", "text", "exemplars", "text+exemplars"]
41
+ SOURCES = ["internal", "external"]
42
+
43
+
44
+ def build_cases():
45
+ cases, seen = [], set()
46
+ for target, pos, neg, src in itertools.product(OTHER, POS_MODES, NEG_MODES, SOURCES):
47
+ uses_exemplars = "exemplars" in pos or "exemplars" in neg
48
+ key = (target, pos, neg, src if uses_exemplars else "-")
49
+ if key in seen:
50
+ continue
51
+ seen.add(key)
52
+ cases.append(key)
53
+ # Two negatives at once (text + exemplars for the other fruit, text only for "plate").
54
+ for target in OTHER:
55
+ cases.append((target, "text+exemplars", "two negatives", "internal"))
56
+ return cases
57
+
58
+
59
+ def run_case(model, target, pos, neg, src):
60
+ kwargs = {"text": target if "text" in pos else ""}
61
+ if "exemplars" in pos:
62
+ img, boxes = EXEMPLARS[target][src]
63
+ kwargs.update(exemplar_boxes=boxes, exemplar_image=img)
64
+
65
+ other = OTHER[target]
66
+ if neg == "two negatives":
67
+ img, boxes = EXEMPLARS[other][src]
68
+ kwargs.update(negative_texts=[other, "plate"],
69
+ negative_exemplar_boxes=[boxes, None],
70
+ negative_exemplar_images=[img, None])
71
+ elif neg != "none":
72
+ kwargs["negative_texts"] = [other if "text" in neg else ""]
73
+ if "exemplars" in neg:
74
+ img, boxes = EXEMPLARS[other][src]
75
+ kwargs.update(negative_exemplar_boxes=[boxes], negative_exemplar_images=[img])
76
+ return count(model, IMAGE, **kwargs)
77
+
78
+
79
+ def draw(result, title):
80
+ im = Image.open(IMAGE).convert("RGB")
81
+ w, h = im.size
82
+ d = ImageDraw.Draw(im)
83
+ for cx, cy, bw, bh in result["boxes"]:
84
+ d.rectangle([(cx - bw / 2) * w, (cy - bh / 2) * h, (cx + bw / 2) * w, (cy + bh / 2) * h],
85
+ outline="cyan", width=2)
86
+ canvas = Image.new("RGB", (w, h + 22), "white")
87
+ canvas.paste(im, (0, 22))
88
+ ImageDraw.Draw(canvas).text((4, 5), title, fill="black")
89
+ return canvas
90
+
91
+
92
+ def main():
93
+ p = argparse.ArgumentParser()
94
+ p.add_argument("--repo", default="nikigoli/CountGDPlusPlus")
95
+ p.add_argument("--device", default="cuda" if torch.cuda.is_available() else "cpu")
96
+ p.add_argument("--out", default="prompt_tests")
97
+ args = p.parse_args()
98
+ os.makedirs(args.out, exist_ok=True)
99
+
100
+ model = CountGDPlusPlus.from_pretrained(args.repo).to(args.device).eval()
101
+
102
+ rows, tiles = [], []
103
+ cases = build_cases()
104
+ print(f"{'#':>3} {'target':<10} {'positive':<15} {'negative':<15} {'exemplars':<9} {'count':>5}")
105
+ for i, (target, pos, neg, src) in enumerate(cases, 1):
106
+ try:
107
+ res = run_case(model, target, pos, neg, src)
108
+ n, err = res["count"], ""
109
+ except Exception as e: # keep going so one failure doesn't hide the rest
110
+ res, n, err = None, "", f"{type(e).__name__}: {e}"
111
+ print(f"{i:>3} {target:<10} {pos:<15} {neg:<15} {src:<9} {n!s:>5} {err}")
112
+ rows.append({"case": i, "target": target, "positive": pos, "negative": neg,
113
+ "exemplar_source": src, "count": n, "error": err})
114
+ if res is not None:
115
+ tile = draw(res, f"#{i} {target} | pos: {pos} | neg: {neg} | {src} -> {n}")
116
+ tile.save(os.path.join(args.out, f"{i:02d}_{target}_{pos}_{neg}_{src}.png".replace("+", "-").replace(" ", "-")))
117
+ tiles.append(tile)
118
+
119
+ with open(os.path.join(args.out, "results.csv"), "w", newline="") as f:
120
+ writer = csv.DictWriter(f, fieldnames=list(rows[0]))
121
+ writer.writeheader()
122
+ writer.writerows(rows)
123
+
124
+ if tiles:
125
+ cols = 4
126
+ tw, th = tiles[0].size
127
+ sheet = Image.new("RGB", (cols * tw, -(-len(tiles) // cols) * th), "white")
128
+ for k, t in enumerate(tiles):
129
+ sheet.paste(t, ((k % cols) * tw, (k // cols) * th))
130
+ sheet.save(os.path.join(args.out, "summary.png"))
131
+
132
+ failed = [r for r in rows if r["error"]]
133
+ print(f"\n{len(rows) - len(failed)}/{len(rows)} cases ran. Results in {args.out}/")
134
+ if failed:
135
+ raise SystemExit(f"{len(failed)} case(s) failed, see the error column.")
136
+
137
+
138
+ if __name__ == "__main__":
139
+ main()