点击下方卡片,关注“机器视觉与AI深度学习”
视觉/图像重磅干货,第一时间送达!
https://docs.ultralytics.com/models/yolo11/?source=post_page-----a793d51cc4ba--------------------------------
数据准备
https://github.com/varunpn7405/Vehicle_Accident_detection
避免误导模型:对象检测模型经过训练,可以预测图像中对象的存在和位置。如果包含没有注释的图像(即没有任何标记对象的图像),则模型可能会错误地了解到许多图像不包含对象,从而降低其有效检测对象的能力。 提高训练效率:在没有注释的图像上进行训练会浪费计算资源,因为模型在处理图像时没有学习任何关于对象位置的有用信息。删除这些图像有助于将训练重点放在相关的信息数据上。 减少偏差:包含大量空白图像可能会使模型偏向于预测图像通常不包含对象,从而导致更高的假阴性率(即无法检测到存在的对象)。 防止过度拟合:对过多的空图像进行训练可能会导致模型对预测未来图像的“无对象”过于自信,这可能会损害其对存在对象的真实场景的泛化。 确保正确的损失计算:目标检测模型通常使用依赖于目标存在的损失(如分类和定位损失)。空图像可能会影响这些损失的计算方式,尤其是当模型期望每个图像至少有一个对象时,这可能会导致训练期间的不稳定。
import os,shutil
# Function to check if a file is empty
def is_empty_file(file_path):
return os.path.exists(file_path) and os.stat(file_path).st_size == 0
image_extensions = ['.jpg', '.jpeg', '.png']
path = os.getcwd()
inputPar = os.path.join(path, r'dataset')
outputPar = os.path.join(path, r'filtered')
if not os.path.exists(outputPar):
os.makedirs(outputPar)
folders = os.listdir(inputPar)
for folder in folders:
if folder in ["test","train","valid"]:
inputChild = os.path.join(inputPar, folder,"labels")
outputChild1 = os.path.join(outputPar, folder,"labels")
if not os.path.exists(outputChild1):
os.makedirs(outputChild1)
outputChild2 = os.path.join(outputPar, folder,"images")
if not os.path.exists(outputChild2):
os.makedirs(outputChild2)
files = os.listdir(inputChild)
for file in files:
annotation_path = os.path.join(inputChild, file)
# Check if the annotation file is empty
if not is_empty_file(annotation_path):
shutil.copy(annotation_path,os.path.join(outputChild1,file))
# Try to find and remove the corresponding image file
image_name = os.path.splitext(file)[0]
for ext in image_extensions:
image_path = os.path.join(inputPar,folder,"images", image_name + ext)
if os.path.exists(image_path):
shutil.copy(image_path,os.path.join(outputChild2,image_name + ext))
import os,shutil
image_extensions = ['.jpg', '.jpeg', '.png']
path = os.getcwd()
inputPar = os.path.join(path, r'accident detection.v10i.yolov11')
outputPar = os.path.join(path, r'accident detection.v10i.yolov11(Filtered))')
if not os.path.exists(outputPar):
os.makedirs(outputPar)
folders = os.listdir(inputPar)
clsfile = os.path.join(path, 'classes.txt')
with open(clsfile) as tf:
clsnames = [cl.strip() for cl in tf.readlines()]
for folder in folders:
if folder in ["test","train","valid"]:
inputChild = os.path.join(inputPar, folder,"labels")
outputChild1 = os.path.join(outputPar, folder,"labels")
if not os.path.exists(outputChild1):
os.makedirs(outputChild1)
outputChild2 = os.path.join(outputPar, folder,"images")
if not os.path.exists(outputChild2):
os.makedirs(outputChild2)
files = os.listdir(inputChild)
for file in files:
fileName, ext = os.path.splitext(file)
finput = os.path.join(inputChild, file)
with open(finput) as tf:
Yolodata = tf.readlines()
# for obj in Yolodata:
if not all(int(obj.split(' ')[0])==2 or int(obj.split(' ')[0])==1 for obj in Yolodata):
print(file)
new_yolo_data=[]
for obj in Yolodata:
if not (int(obj.split(' ')[0])==2 or int(obj.split(' ')[0])==1) :
new_yolo_data.append(obj)
with open(os.path.join(outputChild1,file),"w") as tf:
tf.writelines(new_yolo_data)
image_name = os.path.splitext(file)[0]
for ext in image_extensions:
image_path = os.path.join(inputPar,folder,"images", image_name + ext)
if os.path.exists(image_path):
shutil.copy(image_path,os.path.join(outputChild2,image_name + ext))
break
import os
from PIL import Image,ImageDraw,ImageFont
font = ImageFont.truetype("arial.ttf", 15)
path = os.getcwd()
inputPar = os.path.join(path, r'Dataset')
outputPar = os.path.join(path, r'Visualisation')
if not os.path.exists(outputPar):
os.makedirs(outputPar)
folders = os.listdir(inputPar)
cls_clr = {"Accident":"#eb0523"}
clsfile = os.path.join(path, 'classes.txt')
with open(clsfile) as tf:
clsnames = [cl.strip() for cl in tf.readlines()]
for folder in folders:
if folder in ["test","train","valid"]:
inputChild = os.path.join(inputPar, folder,"labels")
outputChild = os.path.join(outputPar, folder)
if not os.path.exists(outputChild):
os.makedirs(outputChild)
files = os.listdir(inputChild)
for file in files:
fileName, ext = os.path.splitext(file)
finput = os.path.join(inputChild, file)
with open(finput) as tf:
Yolodata = tf.readlines()
imgpath1 = os.path.join(inputPar,folder,"images", fileName + '.jpg')
# imgpath2 = os.path.join(inputPar,folder,"images", fileName + '.png')
if os.path.exists(imgpath1):
imgpath=imgpath1
# elif os.path.exists(imgpath2):
# imgpath=imgpath2
if os.path.exists(imgpath):
print("plotting >>",fileName + '.jpg')
img = Image.open(imgpath)
draw = ImageDraw.Draw(img)
width, height = img.size
for obj in Yolodata:
clsName = clsnames[int(obj.split(' ')[0])]
xnew = float(obj.split(' ')[1])
ynew = float(obj.split(' ')[2])
wnew = float(obj.split(' ')[3])
hnew = float(obj.split(' ')[4])
label=f"{clsName}"
# box size
dw = 1 / width
dh = 1 / height
# coordinates
xmax = int(((2 * xnew) + wnew) / (2 * dw))
xmin = int(((2 * xnew) - wnew) / (2 * dw))
ymax = int(((2 * ynew) + hnew) / (2 * dh))
ymin = int(((2 * ynew) - hnew) / (2 * dh))
clr = cls_clr[clsName]
tw, th = font.getbbox(label)[2:]
# draw bbox and classname::
draw.rectangle([(xmin,ymin),(xmax,ymax)],outline =clr,width=2)
txtbox = [(xmin,ymin-th),(xmin+tw,ymin)]
draw.rectangle(txtbox, fill=clr)
draw.text((xmin,ymin-th),label,fill='white',font=font)
fout = os.path.join(outputChild, imgpath.split("\\")[-1])
img.save(fout)
else:
print(f'{imgpath} >> img not found:'
相同的 Project Config File 为
[
{
"name": "Accident",
"id": 3505802,
"color": "#f80b2b",
"type": "any",
"attributes": []
}
]
import os
import shutil
from concurrent.futures import ThreadPoolExecutor
import time
startTime=time.time()
def copy_files(src_dir, dst_dir):
"""Copy files from src_dir to dst_dir."""
os.makedirs(dst_dir, exist_ok=True)
for file in os.listdir(src_dir):
shutil.copy(os.path.join(src_dir, file), os.path.join(dst_dir, file))
def process_folder(inputPar, outPar, folder):
"""Process 'images' and 'labels' subfolders within the given folder."""
if folder in ["train", "valid", "test"]:
inputChild = os.path.join(inputPar, folder)
for subfldr in ["images", "labels"]:
inputSubChild = os.path.join(inputChild, subfldr)
outChild = os.path.join(outPar, subfldr, folder)
if os.path.exists(inputSubChild):
copy_files(inputSubChild, outChild)
def main():
cPath = os.getcwd()
inputPar = r"data_set"
outPar = os.path.join(cPath, "Dataset")
folders = ["train", "valid", "test"]
with ThreadPoolExecutor() as executor:
executor.map(lambda folder: process_folder(inputPar, outPar, folder), folders)
if __name__ == "__main__":
main()
endTime=time.time()
print("process Completed in !!",endTime-startTime)
import yaml
# Define the data configuration
data_config = {
'train': '/content/data_v2/images/train', # Replace with your train directory path
'val': '/content/data_v2/images/valid', # Replace with your train directory path
'nc': 1, # number of classes
'names': ['Accident']
}
# Write the configuration to a YAML file
with open('data.yaml', 'w') as file:
yaml.dump(data_config, file)
pip install ultralytics
from ultralytics import YOLO
# Load a model
model = YOLO("yolo11n.pt")
# Train the model
train_results = model.train(
data="data.yaml", # path to dataset YAML
epochs=100, # number of training epochs do adjust as you need
imgsz=640, # training image size
)
model.export(format="onnx") # creates 'best.onnx'
import cv2
from ultralytics import YOLO
image_path=r"Accident detection model.v2i.yolov11(Empty Filtered)\train\images\Accidents-online-video-cutter_com-_mp4-41_jpg.rf.549dce3991b2ae74ae65274cc32d8eff.jpg" # Replace with your test image path
onnx_model = YOLO("best.onnx")
class_names=onnx_model.names
image = cv2.imread(image_path)
# Run inference
results = onnx_model(image)
# Extract predictions
for result in results:
boxes = result.boxes # get bounding boxes
for box in boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) # Bounding box coordinates
conf = box.conf.item() # Confidence score
class_id = int(box.cls.item()) # Class ID
# Prepare the label text
label = f"{class_names[class_id]}: {conf:.2f}"
# Draw the bounding box (blue color, thickness of 2)
cv2.rectangle(image, (x1, y1), (x2, y2), (255, 0, 0), 2)
# Draw the label above the bounding box
font = cv2.FONT_HERSHEY_SIMPLEX
label_size, _ = cv2.getTextSize(label, font, 0.5, 1)
label_ymin = max(y1, label_size[1] + 10)
cv2.rectangle(image, (x1, label_ymin - label_size[1] - 10),
(x1 + label_size[0], label_ymin + 4), (255, 0, 0), -1) # Draw label background
cv2.putText(image, label, (x1, label_ymin), font, 0.5, (255, 255, 255), 1) # Put label text
# Save the image
output_path = "output_image.jpg"
cv2.imwrite(output_path, image)
print(f"Saved inference result to {output_path}")
{
"image_name_1": {
"bboxes": [
{"bbox": [xmin1, ymin1, xmax1, ymax1], "class": "cls1"},
{"bbox": [xmin2, ymin2, xmax2, ymax2], "class": "cls2"}
]
},
"image_name_2": {
"bboxes": [
{"bbox": [xmin3, ymin3, xmax3, ymax3], "class": "cls1"},
{"bbox": [xmin4, ymin4, xmax4, ymax4], "class": "cls2"},
{"bbox": [xmin5, ymin5, xmax5, ymax5], "class": "cls3"}
]
}
}
import os,json
from PIL import Image
img_data_dict={}
path = os.getcwd()
inputPar = os.path.join(path, r'Dataset')
folders = os.listdir(inputPar)
clsfile = os.path.join(path, 'classes.txt')
with open(clsfile) as tf:
clsnames = [cl.strip() for cl in tf.readlines()]
for folder in folders:
if folder in ["test"]:
inputChild = os.path.join(inputPar, folder,"images")
files = os.listdir(inputChild)
for file in files:
imgpath=os.path.join(inputChild,file)
img_data_dict[file]=[]
fileName, ext = os.path.splitext(file)
finput = os.path.join(inputPar,folder,"labels", fileName + '.txt')
with open(finput) as tf:
Yolodata = tf.readlines()
if os.path.exists(imgpath):
print("plotting >>",fileName + '.jpg')
img = Image.open(imgpath)
width, height = img.size
for obj in Yolodata:
clsName = clsnames[int(obj.split(' ')[0])]
xnew = float(obj.split(' ')[1])
ynew = float(obj.split(' ')[2])
wnew = float(obj.split(' ')[3])
hnew = float(obj.split(' ')[4])
# box size
dw = 1 / width
dh = 1 / height
# coordinates
xmax = int(((2 * xnew) + wnew) / (2 * dw))
xmin = int(((2 * xnew) - wnew) / (2 * dw))
ymax = int(((2 * ynew) + hnew) / (2 * dh))
ymin = int(((2 * ynew) - hnew) / (2 * dh))
bbx_dict={"Bbox":[xmin,ymin,xmax,ymax],"class":f"{clsName}"}
if file in img_data_dict:
img_data_dict[file].append(bbx_dict)
else:
print(f'{imgpath} >> img not found:')
with open("img_gt.json","w") as f:
json.dump(img_data_dict,f,indent=4)
import cv2,json,os
from ultralytics import YOLO
onnx_model = YOLO("best.onnx")
class_names=onnx_model.names
img_data_dict={}
path = os.getcwd()
inputPar = os.path.join(path, r'Dataset')
folders = os.listdir(inputPar)
for folder in folders:
if folder in ["test"]:
inputChild = os.path.join(inputPar, folder,"images")
files = os.listdir(inputChild)
for file in files:
img_data_dict[file]=[]
imgpath=os.path.join(inputChild,file)
image = cv2.imread(imgpath)
# Run inference
results = onnx_model(image)
# Extract predictions
for result in results:
boxes = result.boxes # get bounding boxes
for box in boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) # Bounding box coordinates
conf = box.conf.item() # Confidence score
class_id = int(box.cls.item()) # Class ID
clsName=class_names[class_id]
bbx_dict={"Bbox":[x1, y1, x2, y2],"class":f"{clsName}"}
if file in img_data_dict:
img_data_dict[file].append(bbx_dict)
with open("img_pred.json","w") as f:
json.dump(img_data_dict,f,indent=4)
import json
def load_data(ground_truth_file, predictions_file):
with open(ground_truth_file) as f:
ground_truth = json.load(f)
with open(predictions_file) as f:
predictions = json.load(f)
return ground_truth, predictions
# Load data
ground_truth_file = 'img_gt.json'
predictions_file = 'img_pred.json'
ground_truth, predictions = load_data(ground_truth_file, predictions_file)
# Make a copy of the data
ground_truth_upd, predictions_upd = ground_truth.copy(), predictions.copy()
# Update the lists so they have the same length
for gt_key, pred_key in zip(ground_truth, predictions):
# Get the annotations for the current key
gt_annotations = ground_truth[gt_key]
pred_annotations = predictions[pred_key]
if len(gt_annotations) != len(pred_annotations):
gt_len = len(gt_annotations)
pred_len = len(pred_annotations)
# Add padding to the smaller list
if gt_len < pred_len:
# Pad ground truth with empty boxes and None class
for _ in range(pred_len - gt_len):
ground_truth_upd[gt_key].append({"Bbox": [0, 0, 0, 0], "class": None})
elif pred_len < gt_len:
# Pad predictions with empty boxes and None class
for _ in range(gt_len - pred_len):
predictions_upd[pred_key].append({"Bbox": [0, 0, 0, 0], "class": None})
# Save updated data
with open("img_gt_upd.json", "w") as f:
json.dump(ground_truth_upd, f, indent=4)
with open("img_pred_upd.json", "w") as f:
json.dump(predictions_upd, f, indent=4)
import json
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import classification_report
def load_data(ground_truth_file, predictions_file):
with open(ground_truth_file) as f:
ground_truth = json.load(f)
with open(predictions_file) as f:
predictions = json.load(f)
return ground_truth, predictions
def iou(box1, box2):
# Calculate the intersection coordinates
xi1 = max(box1[0], box2[0])
yi1 = max(box1[1], box2[1])
xi2 = min(box1[2], box2[2])
yi2 = min(box1[3], box2[3])
# Calculate the area of intersection
intersection_area = max(0, xi2 - xi1) * max(0, yi2 - yi1)
# Calculate the area of both boxes
box1_area = (box1[2] - box1[0]) * (box1[3] - box1[1])
box2_area = (box2[2] - box2[0]) * (box2[3] - box2[1])
# Calculate the area of union
union_area = box1_area + box2_area - intersection_area
return intersection_area / union_area if union_area > 0 else 0
def calculate_metrics(ground_truth, predictions, iou_threshold=0.5):
tp = 0 # True Positives
fp = 0 # False Positives
fn = 0 # False Negatives
# For classification report
y_true = [] # Ground truth classes
y_pred = [] # Predicted classes
for image in ground_truth:
gt_boxes = ground_truth[image]
pred_boxes = predictions[image]
matched_gt = [False] * len(gt_boxes) # Track which ground truths have been matched
for pred in pred_boxes:
pred_box = pred['Bbox']
pred_class = pred['class']
# Append predicted class for report
best_iou = 0
best_gt_idx = -1
for idx, gt in enumerate(gt_boxes):
gt_box = gt['Bbox']
gt_class = gt['class']
# Only consider ground truths that match the predicted class
if gt_class == pred_class and not matched_gt[idx]:
current_iou = iou(pred_box, gt_box)
if current_iou > best_iou:
best_iou = current_iou
best_gt_idx = idx
# Check if the best IoU exceeds the threshold
if best_iou >= iou_threshold and best_gt_idx != -1:
tp += 1 # Count as true positive
matched_gt[best_gt_idx] = True # Mark this ground truth as matched
else:
fp += 1 # Count as false positive
fn += matched_gt.count(False) # Count unmatched ground truths as false negatives
# Append ground truth classes for the report
y_true.extend(gt['class'] for gt in gt_boxes)
y_pred.extend(pred['class'] for pred in pred_boxes)
y_true = [label if label is not None else -1 for label in y_true]
y_pred = [label if label is not None else -1 for label in y_pred]
# Calculate precision, recall, F1 score
precision = tp / (tp + fp) if (tp + fp) > 0 else 0
recall = tp / (tp + fn) if (tp + fn) > 0 else 0
f1_score = 2 * (precision * recall) / (precision + recall) if (precision + recall) > 0 else 0
return tp, fp, fn, precision, recall, f1_score, y_true, y_pred
def plot_metrics(precision, recall, f1_score):
metrics = [precision, recall, f1_score]
labels = ['Precision', 'Recall', 'F1 Score']
plt.figure(figsize=(8, 5))
plt.bar(labels, metrics, color=['blue', 'orange', 'green'])
plt.ylim(0, 1)
plt.ylabel('Score')
plt.title('Performance Metrics')
plt.grid(axis='y')
for i, v in enumerate(metrics):
plt.text(i, v + 0.02, f"{v:.2f}", ha='center', va='bottom')
plt.show()
def main(ground_truth_file, predictions_file):
ground_truth, predictions = load_data(ground_truth_file, predictions_file)
tp, fp, fn, precision, recall, f1_score, y_true, y_pred = calculate_metrics(ground_truth, predictions)
print(f"True Positives: {tp}")
print(f"False Positives: {fp}")
print(f"False Negatives: {fn}")
print(f"Precision: {precision:.2f}")
print(f"Recall: {recall:.2f}")
print(f"F1 Score: {f1_score:.2f}")
# Generate classification report
print("\nClassification Report:")
print(f"Length of y_true: {len(y_true)}")
print(f"Length of y_pred: {len(y_pred)}")
print(classification_report(y_true, y_pred))
# Plot metrics
plot_metrics(precision, recall, f1_score)
# Example usage
ground_truth_file = 'img_gt_upd.json'
predictions_file = 'img_pred_upd.json'
main(ground_truth_file, predictions_file)