ragebhanukiran's picture
initial commit
7aad26f verified
Raw
History Blame Contribute Delete
6.01 kB
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import os
import cv2
from pathlib import Path
from ultralytics import YOLO
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from tqdm import tqdm
# === CONFIG ===
csv_path = r"runs\detect\train\results.csv"
images_dir = r"runs\detect\train"
MODEL_PATH = "runs/detect/train/weights/best.pt"
VAL_IMG_DIR = Path("C:/Users/rageb/Desktop/new yolo model/datasets/valid_filtered/images")
VAL_LABEL_DIR = Path("C:/Users/rageb/Desktop/new yolo model/datasets/valid_filtered/labels")
CLASS_NAMES = ['car', 'emv', 'htv']
IOU_THRESH = 0.5
CONF_THRESH = 0.25
SAVE_DIR = Path("metrics")
SAVE_DIR.mkdir(exist_ok=True)
# === Load YOLO model ===
model = YOLO(MODEL_PATH)
# === Helpers ===
def xywh2xyxy(xc, yc, w, h, img_w, img_h):
x1 = (xc - w/2) * img_w
y1 = (yc - h/2) * img_h
x2 = (xc + w/2) * img_w
y2 = (yc + h/2) * img_h
return [x1, y1, x2, y2]
def compute_iou(b1, b2):
xi1, yi1 = max(b1[0], b2[0]), max(b1[1], b2[1])
xi2, yi2 = min(b1[2], b2[2]), min(b1[3], b2[3])
inter_w, inter_h = max(0, xi2-xi1), max(0, yi2-yi1)
inter = inter_w * inter_h
area1 = (b1[2]-b1[0])*(b1[3]-b1[1])
area2 = (b2[2]-b2[0])*(b2[3]-b2[1])
union = area1 + area2 - inter
return inter/union if union > 0 else 0
# === Confusion Matrix Generation ===
num_classes = len(CLASS_NAMES)
bg_idx = num_classes - 1
y_true, y_pred = [], []
for img_path in tqdm(list(VAL_IMG_DIR.rglob("*.jpg")), desc="Evaluating"):
img = cv2.imread(str(img_path))
h, w = img.shape[:2]
results = model(img, conf=CONF_THRESH)[0]
pred_boxes, pred_cls, pred_scores = [], [], []
if results.boxes is not None:
for box in results.boxes:
pred_boxes.append(box.xyxy.cpu().numpy()[0].tolist())
pred_cls.append(int(box.cls.cpu().numpy()[0]))
pred_scores.append(float(box.conf.cpu().numpy()[0]))
gt_file = VAL_LABEL_DIR / f"{img_path.stem}.txt"
if not gt_file.exists():
continue
gt_boxes, gt_cls = [], []
with open(gt_file) as f:
for line in f:
parts = line.strip().split()
if len(parts) < 5:
continue
cid = int(parts[0])
xc, yc, ww, hh = map(float, parts[1:5])
gt_cls.append(cid)
gt_boxes.append(xywh2xyxy(xc, yc, ww, hh, w, h))
matched_gt, matched_pred = set(), set()
preds = sorted(
zip(pred_boxes, pred_cls, pred_scores, range(len(pred_boxes))),
key=lambda x: x[2], reverse=True
)
for pb, pc, ps, pidx in preds:
best_i, best_iou = -1, 0.0
for gi, gb in enumerate(gt_boxes):
if gi in matched_gt:
continue
iou = compute_iou(pb, gb)
if iou > best_iou:
best_iou, best_i = iou, gi
if best_iou >= IOU_THRESH:
y_true.append(gt_cls[best_i])
y_pred.append(pc)
matched_gt.add(best_i)
matched_pred.add(pidx)
for pidx, pc in enumerate(pred_cls):
if pidx not in matched_pred:
y_true.append(bg_idx)
y_pred.append(pc)
for gi, gc in enumerate(gt_cls):
if gi not in matched_gt:
y_true.append(gc)
y_pred.append(bg_idx)
cm = confusion_matrix(y_true, y_pred, labels=range(num_classes))
cm_norm = cm.astype(float) / cm.sum(axis=1)[:, None]
disp = ConfusionMatrixDisplay(cm_norm, display_labels=CLASS_NAMES)
disp.plot(cmap=plt.cm.Blues)
plt.title("Normalized Confusion Matrix")
plt.savefig(SAVE_DIR / "confusion_matrix_normalized.png")
plt.close()
# === Plot Training/Validation Stats ===
df = pd.read_csv(csv_path)
df.columns = df.columns.str.strip()
# Losses
plt.figure(figsize=(12, 8))
plt.plot(df["epoch"], df["train/box_loss"], label="Box Loss")
plt.plot(df["epoch"], df["train/cls_loss"], label="Class Loss")
plt.plot(df["epoch"], df["train/dfl_loss"], label="DFL Loss")
plt.plot(df["epoch"], df["val/box_loss"], label="Val Box Loss")
plt.plot(df["epoch"], df["val/cls_loss"], label="Val Class Loss")
plt.plot(df["epoch"], df["val/dfl_loss"], label="Val DFL Loss")
plt.title("Training and Validation Losses")
plt.xlabel("Epoch")
plt.ylabel("Loss")
plt.legend()
plt.grid(True)
plt.savefig(SAVE_DIR / "losses_plot.png")
plt.close()
# Metrics
plt.figure(figsize=(12, 8))
plt.plot(df["epoch"], df["metrics/precision(B)"], label="Precision")
plt.plot(df["epoch"], df["metrics/recall(B)"], label="Recall")
plt.plot(df["epoch"], df["metrics/mAP50(B)"], label="mAP@0.5")
plt.plot(df["epoch"], df["metrics/mAP50-95(B)"], label="mAP@0.5:0.95")
plt.title("Eval Metrics")
plt.xlabel("Epoch")
plt.ylabel("Score")
plt.legend()
plt.grid(True)
plt.savefig(SAVE_DIR / "metrics_plot.png")
plt.close()
# Learning Rates
plt.figure(figsize=(12, 8))
plt.plot(df["epoch"], df["lr/pg0"], label="lr/pg0")
plt.plot(df["epoch"], df["lr/pg1"], label="lr/pg1")
plt.plot(df["epoch"], df["lr/pg2"], label="lr/pg2")
plt.title("Learning Rates")
plt.xlabel("Epoch")
plt.ylabel("LR")
plt.legend()
plt.grid(True)
plt.savefig(SAVE_DIR / "learning_rates_plot.png")
plt.close()
# === Display Pre-generated Curves (if available) ===
image_files = [
"F1_curve.png",
"P_curve_.png",
"P_curve.png",
"PR_curve.png",
"R_curve.png",
]
for filename in image_files:
src_path = os.path.join(images_dir, filename)
dst_path = SAVE_DIR / filename
if os.path.exists(src_path):
img = mpimg.imread(src_path)
plt.figure(figsize=(10, 8))
plt.imshow(img)
plt.axis('off')
plt.title(filename.replace(".png", "").replace("_", " ").title())
plt.savefig(dst_path)
plt.close()
else:
print(f"[Warning] {filename} not found in {images_dir}")