[Python] Yolo v11 obj detection custom inference gives totally different results than yolo cli...

Discussão em 'Python' iniciado por Stack, Maio 7, 2025.

  1. Stack

    Stack Membro Participativo

    I am trying to run an exported verision of a fine-tunned yolov11n to detect roadsigns. When I run the model with the yolo cli on this exact same image, I get an object detected with confidence 0.86. But when I run it with my custom script, I get no meaningful detections - all confidence values are around 1e-7. I have been struggling to solve this for the past few days. I tried TensorFlow, Pillow, OpenCV, different normalization methods for preprocessing, but nothing seems to work. Since the model works, this either has to do with the preprocessing step, or with the post-processing step - does anyone have any ideas?

    Netron architecture graph(input/output)

    import onnxruntime as ort
    import numpy as np
    import cv2



    class YoloInference:
    # List of class names for YOLO model
    classes = [
    'speed20', 'speed30', 'speed50', 'speed60', 'speed70', 'speed80', 'speed100', 'speed120'
    ]

    def __init__(self, model_path):
    self.session = ort.InferenceSession(model_path)
    self.input_name = self.session.get_inputs()[0].name
    self.output_name = self.session.get_outputs()[0].name

    def preprocess(self, image):
    """This functions preprocess the image before inference
    preprocesses:resize(640x640),normalize,HWC to CHW,adds batch
    Returns:
    img preprocessed
    """
    img = cv2.resize(image, (640, 640)) # Resize to model input size
    img = img.astype(np.float32)
    img = img / 255.0 # Normalize
    img = np.transpose(img, [2, 0, 1]) # Change data layout from HWC to CHW
    img = np.expand_dims(img, axis=0) # Add batch dimension
    return img

    def postprocess(self, output, conf_threshold=0.5, nms_threshold=0.1):
    detections = output[0].T # Transpose the array

    boxes = []
    confidences = []
    class_ids = []

    for detection in detections: # Iterate through each of the 8400 predictions
    box = detection[:4]
    class_scores = detection[4:]

    class_id = np.argmax(class_scores)
    confidence = class_scores[class_id]
    if confidence > conf_threshold:
    # Convert from center coordinates to corner coordinates
    cx, cy,box_width, box_height = box # Note the order: x, y, height, width
    cx = cx.item()
    cy = cy.item()
    box_height = box_height.item()
    box_width = box_width.item()
    x1 = int((cx - box_width / 2))
    y1 = int((cy - box_height / 2))
    x2 = int(cx + box_width / 2)
    y2 = int(cy + box_height / 2)
    boxes.append([x1, y1, x2, y2])
    confidences.append(float(confidence.item()))
    class_ids.append(class_id)

    # Apply non-maximum suppression (NMS)
    indices = cv2.dnn.NMSBoxes(boxes, confidences, conf_threshold, nms_threshold)

    print(confidences)

    processed_results = []
    if len(indices) > 0:
    for i in indices.flatten():
    x1, y1, x2, y2 = boxes
    processed_results.append({
    'class_id': self.classes[class_ids],
    'confidence': confidences,
    'box': [x1, y1, x2, y2]
    })
    return processed_results

    def infer(self, image,desired_class_id=None): # 77-tedy 21-bear
    h,w,_ = image.shape
    input_image = self.preprocess(image)
    output = self.session.run([self.output_name], {self.input_name: input_image})
    processed_results = self.postprocess(output)
    orig_height, orig_width = image.shape[:2]
    scale_x = orig_width / w
    scale_y = orig_height / h
    if desired_class_id is not None:
    boxes = [result['box'] for result in processed_results if result['class_id']==self.classes[desired_class_id]]
    scores = [result['confidence'] for result in processed_results if result['class_id']==self.classes[desired_class_id]]
    class_ids = [result['class_id'] for result in processed_results if result['class_id']==self.classes[desired_class_id]]
    else:
    boxes = [result['box'] for result in processed_results]
    scores = [result['confidence'] for result in processed_results]
    class_ids = [result['class_id'] for result in processed_results]
    return boxes, scores, class_ids, scale_x, scale_y

    def draw_detections(self,image, boxes, scores, class_ids, scale_x, scale_y):
    for box, score, class_id in zip(boxes, scores, class_ids):
    x1, y1, x2, y2 = box

    # Scale the coordinates back to the original image size
    x1 = int(x1 * scale_x)
    y1 = int(y1 * scale_y)
    x2 = int(x2 * scale_x)
    y2 = int(y2 * scale_y)

    print(x1, y1, x2, y2)

    # Ensure class_id is used correctly to fetch class name
    class_name = class_id if isinstance(class_id, str) else self.classes[class_id]

    # Draw the bounding box
    cv2.rectangle(image, (x1, y1), (x2, y2), (0, 255, 0), 2)

    # Label the bounding box with class name and confidence score
    label = f'{class_name}: {score:.2f}'
    cv2.putText(image, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (36, 255, 12), 2)

    return image

    if __name__ == "__main__":
    model_path = r"D:\Research licenta\yolo-speedlimits-combined-dataset-nano.onnx"
    image_path = r"D:\AndroidStudioProjects\Licenta\app\src\main\assets\0000000089.png"

    # Load and run inference
    yolo = YoloInference(model_path)
    image = cv2.imread(image_path)
    boxes, scores, class_ids, scale_x, scale_y = yolo.infer(image)

    # Draw and display detections
    image_with_detections = yolo.draw_detections(image, boxes, scores, class_ids, scale_x, scale_y)
    cv2.imwrite("Detectionsl.jpg", image_with_detections)

    Continue reading...

Compartilhe esta Página