1from huggingface_hub import hf_hub_download
2import onnxruntime as ort, numpy as np
3from PIL import Image
4
5onnx = hf_hub_download("pictograph/receipt-detection", "yolox-c4b9f885.onnx")
6sess = ort.InferenceSession(onnx, providers=["CPUExecutionProvider"])
7S = 640 # model input size
8
9# letterbox to SxS, pad 114, CHW float32 (YOLOX uses raw 0-255, NO /255)
10img = Image.open("photo.jpg").convert("RGB")
11w0, h0 = img.size; r = min(S / h0, S / w0)
12resized = img.resize((round(w0 * r), round(h0 * r)))
13canvas = np.full((S, S, 3), 114, np.uint8)
14canvas[: resized.height, : resized.width] = np.array(resized)
15x = canvas.transpose(2, 0, 1)[None].astype(np.float32)
16
17pred = sess.run(None, {sess.get_inputs()[0].name: x})[0][0] # [8400, 5+C]
18
19# decode the YOLOX grid (strides 8/16/32)
20grids, strides = [], []
21for s in (8, 16, 32):
22 n = S // s
23 xv, yv = np.meshgrid(np.arange(n), np.arange(n))
24 grids.append(np.stack((xv, yv), 2).reshape(-1, 2))
25 strides.append(np.full((n * n, 1), s))
26grids = np.concatenate(grids); strides = np.concatenate(strides)
27pred[:, :2] = (pred[:, :2] + grids) * strides
28pred[:, 2:4] = np.exp(pred[:, 2:4]) * strides
29
30xy, wh = pred[:, :2], pred[:, 2:4]
31boxes = np.concatenate([xy - wh / 2, xy + wh / 2], 1) / r # xyxy, source px
32s = pred[:, 4:5] * pred[:, 5:]
33cls, conf = s.argmax(1), s.max(1)
34keep = conf > 0.3
35boxes, conf, cls = boxes[keep], conf[keep], cls[keep]
36
37def nms(b, sc, iou=0.45):
38 order = sc.argsort()[::-1]; out = []
39 while len(order):
40 i = order[0]; out.append(i)
41 x1 = np.maximum(b[i, 0], b[order[1:], 0]); y1 = np.maximum(b[i, 1], b[order[1:], 1])
42 x2 = np.minimum(b[i, 2], b[order[1:], 2]); y2 = np.minimum(b[i, 3], b[order[1:], 3])
43 inter = np.clip(x2 - x1, 0, None) * np.clip(y2 - y1, 0, None)
44 ai = (b[i, 2] - b[i, 0]) * (b[i, 3] - b[i, 1])
45 ar = (b[order[1:], 2] - b[order[1:], 0]) * (b[order[1:], 3] - b[order[1:], 1])
46 order = order[1:][inter / (ai + ar - inter + 1e-9) < iou]
47 return out
48
49final = nms(boxes, conf)
50print(boxes[final], conf[final], cls[final]) # [x1,y1,x2,y2], score, class index