Views
No views yet
icon_detect_v3, an MIT licensed interactable region detector finetuned from YOLOv9-E using the MIT licensed MultimediaTechLab/YOLO implementation (see New: MIT licensed detector weights). For more details of the models used and finetuning, please refer to the paper.icon_detect_v3)icon_detect weights are finetuned from YOLOv8 and are therefore distributed under the AGPL-3.0 license, which is a blocker for many downstream users. We now additionally release icon_detect_v3/model.pt, an interactable region detector finetuned from YOLOv9-E on the same detection data and released under the MIT license (see icon_detect_v3/LICENSE).icon_detect, neither the training code nor the resulting weights carry AGPL-3.0 obligations.icon_detect_v3 with icon_caption gives a fully MIT licensed OmniParser pipeline. icon_detect is still available and unchanged for users who are fine with AGPL-3.0.torch (no ultralytics and no AGPL licensed code at runtime):1import numpy as np
2import torch
3from PIL import Image
4from torchvision.ops import nms
5
6IMGSZ = 1280
7STRIDES = (8, 16, 32)
8CONF_THRESHOLD = 0.05
9IOU_THRESHOLD = 0.45
10
11model = torch.jit.load("icon_detect_v3/model.pt", map_location="cpu").eval()
12
13# Letterbox the screenshot into a square IMGSZ canvas, keeping the aspect ratio.
14image = Image.open("screenshot.png").convert("RGB")
15width, height = image.size
16scale = min(IMGSZ / width, IMGSZ / height)
17resized = image.resize((round(width * scale), round(height * scale)), Image.BILINEAR)
18canvas = Image.new("RGB", (IMGSZ, IMGSZ), (114, 114, 114))
19canvas.paste(resized, (0, 0))
20x = torch.from_numpy(np.array(canvas)).permute(2, 0, 1).float()[None] / 255.0
21
22with torch.no_grad():
23 outputs = model(x) # (cls_logits, box_ltrb) per stride, in that order
24
25# Decode the raw heads: class logits need a sigmoid, and the 4 box channels are
26# left/top/right/bottom distances from each grid cell center, in grid units.
27boxes, scores = [], []
28for i, stride in enumerate(STRIDES):
29 cls = outputs[2 * i].sigmoid()[0, 0]
30 ltrb = outputs[2 * i + 1][0]
31 grid = cls.shape[-1]
32 gy, gx = torch.meshgrid(
33 torch.arange(grid, dtype=torch.float32),
34 torch.arange(grid, dtype=torch.float32),
35 indexing="ij",
36 )
37 cx, cy = gx + 0.5, gy + 0.5
38 left, top, right, bottom = ltrb
39 boxes.append(
40 torch.stack(
41 [(cx - left) * stride, (cy - top) * stride,
42 (cx + right) * stride, (cy + bottom) * stride], dim=-1
43 ).reshape(-1, 4)
44 )
45 scores.append(cls.reshape(-1))
46
47boxes, scores = torch.cat(boxes), torch.cat(scores)
48keep = scores > CONF_THRESHOLD
49boxes, scores = boxes[keep], scores[keep]
50keep = nms(boxes, scores, IOU_THRESHOLD)
51boxes, scores = boxes[keep], scores[keep]
52
53# Map the boxes from the letterboxed canvas back to original image coordinates.
54boxes = boxes / scale
55boxes[:, 0::2] = boxes[:, 0::2].clamp(0, width)
56boxes[:, 1::2] = boxes[:, 1::2].clamp(0, height)
57# boxes: (N, 4) xyxy in original pixels, scores: (N,) confidencecls has one channel per scale.CONF_THRESHOLD defaults to 0.05 to match the box_threshold that OmniParser uses with icon_detect. The detector is deliberately low confidence on small UI elements, so raising this much above 0.1 starts dropping real elements (icons, toolbar buttons, footer links) rather than just filtering noise. Tune CONF_THRESHOLD / IOU_THRESHOLD for your screenshots the same way you would tune box_threshold / iou_threshold for icon_detect.scale division. If you center the padding instead, subtract the pad offsets before dividing.| Folder | Model | License |
|---|---|---|
icon_detect | YOLOv8 based interactable region detector (Ultralytics) | AGPL-3.0 |
icon_detect_v3 | YOLOv9-E based interactable region detector (MultimediaTechLab/YOLO, MIT) | MIT |
icon_caption | Florence-2 based icon captioner | MIT |
icon_detect_v3 together with icon_caption yields an OmniParser pipeline that is entirely MIT licensed.