Validation

 avatar
unknown
plain_text
5 months ago
6.0 kB
3
Indexable
def x1y1wh_2_x1y1x2y2(box):
    img_w, img_h = 1920, 1080  # Kích thước ảnh
    x1, y1, w_, h_, label, _ = box
    x2 = x1 + w_
    y2 = y1 + h_

    # Chuẩn hóa giá trị x1, y1, x2, y2 về tỉ lệ [0, 1] dựa trên kích thước ảnh
    return (
        float(x1 / img_w),  # x1 chuẩn hóa
        float(y1 / img_h),  # y1 chuẩn hóa
        float(x2 / img_w),  # x2 chuẩn hóa
        float(y2 / img_h),  # y2 chuẩn hóa
        label
    )

def calculate_iou(boxA, boxB):
    # boxA và boxB có định dạng [x1, y1, x2, y2]
    x1_A, y1_A, x2_A, y2_A = boxA
    x1_B, y1_B, x2_B, y2_B = boxB

    # Tính diện tích của các box
    area_A = (x2_A - x1_A) * (y2_A - y1_A)
    area_B = (x2_B - x1_B) * (y2_B - y1_B)

    # Tính tọa độ của hộp giới hạn chung
    x1_intersection = max(x1_A, x1_B)
    y1_intersection = max(y1_A, y1_B)
    x2_intersection = min(x2_A, x2_B)
    y2_intersection = min(y2_A, y2_B)

    # Tính diện tích của hộp giới hạn chung
    width_intersection = max(0, x2_intersection - x1_intersection)
    height_intersection = max(0, y2_intersection - y1_intersection)
    area_intersection = width_intersection * height_intersection

    # Tính IoU
    total_area = area_A + area_B - area_intersection
    iou = area_intersection / total_area if total_area > 0 else 0
    return iou

import os
from collections import defaultdict
import torch  # Nhập thư viện torch
from ultralytics.utils.metrics import box_iou  # Nhập hàm box_iou

# Danh sách các lớp
classes = ['motorbike', 'DHelmet', 'DNoHelmet', 'P1Helmet', 'P1NoHelmet', 'P2Helmet', 'P2NoHelmet', 'P0Helmet', 'P0NoHelmet']

# Khởi tạo biến để lưu trữ số liệu cho từng lớp
true_positive = defaultdict(int)
false_positive = defaultdict(int)
false_negative = defaultdict(int)

iou_thres = 0.5

# Danh sách các file image
image_files = [f for f in os.listdir('/kaggle/input/helmet-detection-with-yolo-pna/dataset/val/labels') if f.endswith('.txt')]

for image_file in image_files:
    annotations = []
    with open(os.path.join('/kaggle/input/helmet-detection-with-yolo-pna/dataset/val/labels', image_file), 'r') as f:
        for line in f:
            parts = line.strip().split()
            class_id = int(parts[0])  # Lớp (class ID)
            x_center, y_center, width, height = map(float, parts[1:])  # Tọa độ
            annotations.append((class_id, x_center, y_center, width, height))

    normalized_boxes = []
    
    img_name = image_file.replace('.txt', '.jpg')
    
    if img_name not in results: 
        print(f"Error: {img_name} not in results")
        continue
        
    for box in results[img_name]:  # Thay đổi theo tên file ảnh
        normalized_box = x1y1wh_2_x1y1x2y2(box)  # chuyển x1,y1,w,h --> x1,y1,x2,y2 và normalize
        normalized_boxes.append(normalized_box)

    # total_predictions = len(normalized_boxes)

    # Tạo dictionary để tăng tốc độ tìm kiếm
    annotations_dict = { (x_center_ann, y_center_ann, width_ann, height_ann): class_id for (class_id, x_center_ann, y_center_ann, width_ann, height_ann) in annotations }

    matched_annotations = set()  # Để theo dõi nhãn nào đã được dự đoán đúng

    # So sánh từng dự đoán với nhãn thực tế
    for box in normalized_boxes:
        (x1_pred, y1_pred, x2_pred, y2_pred, class_pred) = box
        
        # Tạo bbox cho hàm box_iou
        # pred_box = torch.tensor([x1 - x2 / 2, y1 - y2 / 2, 
        #                           x1 + x2 / 2, y1 + y2 / 2]).float()
        # pred_box = torch.tensor([x1_pred, y1_pred, x2_pred, y2_pred]).float()
        pred_box = x1_pred, y1_pred, x2_pred, y2_pred
        
        match_found = False
        
        for (x_center_ann, y_center_ann, width_ann, height_ann), class_id in annotations_dict.items():
            if class_pred == class_id:  # Kiểm tra lớp
                # Tạo bbox cho nhãn thực tế
                # true_box = torch.tensor([x_center_ann - width_ann / 2, y_center_ann - height_ann / 2,
                #                          x_center_ann + width_ann / 2, y_center_ann + height_ann / 2]).float()
                true_box = [x_center_ann - width_ann / 2, y_center_ann - height_ann / 2,
                                         x_center_ann + width_ann / 2, y_center_ann + height_ann / 2]
                
                # Tính IoU
                # iou = box_iou(pred_box.unsqueeze(0), true_box.unsqueeze(0)).item()  # Chuyển đổi thành tensor 2 chiều
                iou = calculate_iou(pred_box, true_box)

                if iou > iou_thres:  # Ngưỡng IoU
                    true_positive[class_pred] += 1  # Dự đoán đúng
                    matched_annotations.add((x_center_ann, y_center_ann, width_ann, height_ann))
                    match_found = True
                    break
        
        if not match_found:
            false_positive[class_pred] += 1  # Dự đoán sai

    # Cập nhật số lượng nhãn thực tế
    # for (class_id, _, _, _, _) in annotations:
    #     if (class_id, _, _, _) not in matched_annotations:
    #         false_negative[class_id] += 1  # Nhãn thực tế không được dự đoán đúng
    for (class_id, _, _, _, _) in annotations:
        if (x_center_ann, y_center_ann, width_ann, height_ann) not in matched_annotations:
            false_negative[class_id] += 1  # Nhãn thực tế không được dự đoán đúng


# Tính toán độ chính xác và độ hồi tưởng
precision = {}
recall = {}

for class_id in range(len(classes)):
    tp = true_positive[class_id]
    fp = false_positive[class_id]
    fn = false_negative[class_id]
    
    precision[class_id] = tp / (tp + fp) if (tp + fp) > 0 else 0
    recall[class_id] = tp / (tp + fn) if (tp + fn) > 0 else 0
    
    print(f"{classes[class_id]} - Precision: {precision[class_id] * 100:.2f}%, Recall: {recall[class_id] * 100:.2f}%")
Editor is loading...
Leave a Comment