from pathlib import Path import numpy as np import onnxruntime as ort from PIL import Image, ImageDraw MODEL_PATH = Path(__file__).with_name("best.onnx") TEST_DIR = Path(__file__).with_name("test") OUTPUT_DIR = Path(__file__).with_name("ouptsw") IMAGE_SUFFIXES = {".jpg", ".jpeg", ".png", ".bmp", ".webp"} CONFIDENCE_THRESHOLD = 0.1 IOU_THRESHOLD = 0.5 def _dtype(onnx_type): if onnx_type == "tensor(float)": return np.float32 if onnx_type == "tensor(float16)": return np.float16 if onnx_type == "tensor(double)": return np.float64 if onnx_type in {"tensor(int64)", "tensor(uint64)"}: return np.int64 if onnx_type in {"tensor(int32)", "tensor(uint32)"}: return np.int32 raise ValueError(f"Unsupported input type: {onnx_type}") def _shape(input_meta): return [dim if isinstance(dim, int) else 1 for dim in input_meta.shape] def _iou(box, boxes): x1 = np.maximum(box[0], boxes[:, 0]) y1 = np.maximum(box[1], boxes[:, 1]) x2 = np.minimum(box[2], boxes[:, 2]) y2 = np.minimum(box[3], boxes[:, 3]) intersection = np.maximum(0, x2 - x1) * np.maximum(0, y2 - y1) box_area = np.maximum(0, box[2] - box[0]) * np.maximum(0, box[3] - box[1]) boxes_area = np.maximum(0, boxes[:, 2] - boxes[:, 0]) * np.maximum( 0, boxes[:, 3] - boxes[:, 1], ) return intersection / np.maximum(box_area + boxes_area - intersection, 1e-6) def _nms(detections): detections = detections[detections[:, 4] >= CONFIDENCE_THRESHOLD] if len(detections) == 0: return detections detections = detections[np.argsort(detections[:, 4])[::-1]] kept = [] while len(detections) > 0: best = detections[0] kept.append(best) if len(detections) == 1: break detections = detections[1:][_iou(best[:4], detections[1:, :4]) < IOU_THRESHOLD] return np.array(kept) def _preprocess(image, input_shape): _, _, height, width = input_shape resized = image.resize((width, height)) array = np.asarray(resized, dtype=np.float32) / 255.0 return np.transpose(array, (2, 0, 1))[None] def _scale_detections(detections, original_size, input_shape): _, _, input_height, input_width = input_shape original_width, original_height = original_size scaled = detections.copy() scaled[:, [0, 2]] *= original_width / input_width scaled[:, [1, 3]] *= original_height / input_height scaled[:, [0, 2]] = np.clip(scaled[:, [0, 2]], 0, original_width) scaled[:, [1, 3]] = np.clip(scaled[:, [1, 3]], 0, original_height) return scaled def _draw_detections(image, detections): draw = ImageDraw.Draw(image) for detection in detections: x1, y1, x2, y2, score, class_id = detection cx = (x1 + x2) / 2 cy = (y1 + y2) / 2 label = f"({cx:.1f}, {cy:.1f}) {score:.2f}" draw.rectangle((x1, y1, x2, y2), outline="red", width=3) draw.ellipse((cx - 5, cy - 5, cx + 5, cy + 5), fill="yellow", outline="red") draw.line((cx - 10, cy, cx + 10, cy), fill="red", width=2) draw.line((cx, cy - 10, cx, cy + 10), fill="red", width=2) draw.text((x1, max(0, y1 - 14)), label, fill="yellow") def main(): session = ort.InferenceSession(str(MODEL_PATH)) input_meta = session.get_inputs()[0] input_shape = _shape(input_meta) print(f"model: {MODEL_PATH}") print(f"providers: {session.get_providers()}") print("inputs:") feeds = {} for input_meta in session.get_inputs(): print( f"- name={input_meta.name}, type={input_meta.type}, " f"shape={input_meta.shape}" ) feeds[input_meta.name] = np.zeros( _shape(input_meta), dtype=_dtype(input_meta.type), ) print("outputs:") for output_meta in session.get_outputs(): print( f"- name={output_meta.name}, type={output_meta.type}, " f"shape={output_meta.shape}" ) outputs = session.run(None, feeds) print("dummy inference: ok") for index, output in enumerate(outputs): print(f"- output[{index}]: shape={output.shape}, dtype={output.dtype}") OUTPUT_DIR.mkdir(exist_ok=True) result_lines = ["image,class_id,score,center_x,center_y,x1,y1,x2,y2"] for image_path in sorted(TEST_DIR.iterdir()): if image_path.suffix.lower() not in IMAGE_SUFFIXES: continue image = Image.open(image_path).convert("RGB") tensor = _preprocess(image, input_shape) detections = session.run(None, {input_meta.name: tensor})[0][0] detections = _scale_detections(_nms(detections), image.size, input_shape) annotated = image.copy() _draw_detections(annotated, detections) output_path = OUTPUT_DIR / image_path.name annotated.save(output_path) print(f"{image_path.name}: {len(detections)} target(s) -> {output_path}") for detection in detections: x1, y1, x2, y2, score, class_id = detection cx = (x1 + x2) / 2 cy = (y1 + y2) / 2 print(f" center=({cx:.1f}, {cy:.1f}), score={score:.3f}") result_lines.append( f"{image_path.name},{int(class_id)},{score:.6f},{cx:.2f},{cy:.2f}," f"{x1:.2f},{y1:.2f},{x2:.2f},{y2:.2f}" ) (OUTPUT_DIR / "coordinates.csv").write_text("\n".join(result_lines) + "\n") if __name__ == "__main__": main()