%% FINAL FINAL FINAL
%% === BULLET TRACKING WITH KALMAN FILTER + VELOCITY/DISTANCE ===
clc; clear; close all;
%% --- Video setup ---
videoFile = '[Link]';
v = VideoReader(videoFile);
fps = [Link];
ScalingFactor = 8; % Pixel -> meters (adjust per calibration)
videoPlayer = [Link]('Position',[100 100 700 400]);
%% --- Foreground detector & blob analyser ---
detector =
[Link]('NumGaussians',3,'NumTrainingFrames',40,'MinimumBackgroun
dRatio',0.7);
blobAnalyser =
[Link]('BoundingBoxOutputPort',true,'AreaOutputPort',true,'CentroidOut
putPort',true,'MinimumBlobArea',40);
%% --- Kalman & tracking initialization ---
kalmanFilter = [];
isTrackInitialized = false;
trackedCentroid = [];
trackedBbox = [];
maxMissingFrames = 30;
missingFrameCount = 0;
%% --- Environment setup (for occlusion) ---
obstacles = [815, 10, 27, 363; 580, 10, 27, 363]; % Example stick-like occlusions
obstacleRanges = [obstacles(:,1)-10, obstacles(:,1)+obstacles(:,3)+10];
%% --- Parameters ---
bboxScale = 1.3;
smoothFactor = 0.6;
%% --- Velocity & distance ---
bulletCentroids = [];
totalDistance = 0;
avgVelocity = 0;
disp('--- Tracking started ---');
while hasFrame(v)
frame = readFrame(v);
% --- Foreground mask ---
mask = step(detector, frame);
mask = imopen(mask, strel('rectangle',[5 5]));
mask = imclose(mask, strel('rectangle',[5 5]));
mask = imfill(mask,'holes');
[areas, centroids, bboxes] = blobAnalyser(mask);
usedCentroid = [];
usedBbox = [];
if ~isempty(centroids)
[~, idx] = max(areas);
measuredCentroid = double(centroids(idx,:));
measuredBbox = double(bboxes(idx,:));
if ~isTrackInitialized
kalmanFilter = configureKalmanFilter('ConstantVelocity',
measuredCentroid,[400,100],[100,25],100);
usedCentroid = measuredCentroid;
usedBbox = measuredBbox;
trackedCentroid = usedCentroid;
trackedBbox = usedBbox;
isTrackInitialized = true;
label = 'Corrected';
color = 'green';
else
% --- Kalman prediction ---
predictedCentroid = double(predict(kalmanFilter));
% --- Check if measured centroid is inside obstacle ---
inObstacle = any(measuredCentroid(1) > obstacleRanges(:,1) &
measuredCentroid(1) < obstacleRanges(:,2));
if inObstacle
usedCentroid = predictedCentroid;
label = 'Predicted';
color = 'red';
missingFrameCount = missingFrameCount + 1;
else
corrected = double(correct(kalmanFilter, measuredCentroid));
usedCentroid = smoothFactor * trackedCentroid(end,:) + (1 -
smoothFactor) * corrected;
label = 'Corrected';
color = 'green';
missingFrameCount = 0;
end
% --- Smooth bounding box ---
bboxW = measuredBbox(3) * bboxScale;
bboxH = measuredBbox(4) * bboxScale;
if ~isempty(trackedBbox)
bboxW = smoothFactor * trackedBbox(3) + (1 - smoothFactor) * bboxW;
bboxH = smoothFactor * trackedBbox(4) + (1 - smoothFactor) * bboxH;
end
usedBbox = [usedCentroid - [bboxW/2, bboxH/2], bboxW, bboxH];
trackedCentroid(end+1,:) = usedCentroid;
trackedBbox = usedBbox;
end
% --- Update centroids for velocity/distance ---
bulletCentroids = [bulletCentroids; usedCentroid];
if size(bulletCentroids,1) > 1
distances = sqrt(sum(diff(bulletCentroids).^2,2)); % pixel distances
totalDistance = sum(distances) * ScalingFactor; % meters
velocities = distances * ScalingFactor * fps; % m/s
avgVelocity = mean(velocities);
else
totalDistance = 0;
avgVelocity = 0;
end
% --- Draw bounding box and label ---
frame =
insertShape(frame,'Rectangle',usedBbox,'Color',color,'LineWidth',3);
frame = insertText(frame, usedBbox(1:2),
label,'BoxColor',color,'TextColor','white','FontSize',12,'AnchorPoint','LeftTop');
% --- Draw centroid marker ---
frame = insertMarker(frame, usedCentroid,'o','Color','blue','Size',5);
% --- Display velocity & distance ---
infoText = sprintf('Velocity: %.2f m/s | Distance: %.2f m', avgVelocity,
totalDistance);
frame = insertText(frame,[10
10],infoText,'FontSize',14,'BoxColor','yellow','TextColor','black');
elseif isTrackInitialized && missingFrameCount < maxMissingFrames
% --- Predicted when object missing entirely ---
predictedCentroid = double(predict(kalmanFilter));
usedCentroid = predictedCentroid;
trackedCentroid(end+1,:) = usedCentroid;
if ~isempty(trackedBbox)
bboxW = trackedBbox(3);
bboxH = trackedBbox(4);
else
bboxW = 20;
bboxH = 20;
end
usedBbox = [usedCentroid - [bboxW/2, bboxH/2], bboxW, bboxH];
bulletCentroids = [bulletCentroids; usedCentroid];
if size(bulletCentroids,1) > 1
distances = sqrt(sum(diff(bulletCentroids).^2,2));
totalDistance = sum(distances) * ScalingFactor;
velocities = distances * ScalingFactor * fps;
avgVelocity = mean(velocities);
end
frame =
insertShape(frame,'Rectangle',usedBbox,'Color','red','LineWidth',3);
frame = insertText(frame, usedBbox(1:2),
'Predicted','BoxColor','red','TextColor','white','FontSize',12,'AnchorPoint','LeftT
op');
frame = insertMarker(frame, usedCentroid,'o','Color','blue','Size',5);
missingFrameCount = missingFrameCount + 1;
end
step(videoPlayer,frame);
end
release(videoPlayer);
disp('--- Tracking finished ---');