1、将下面代码所提取的视频的的第一帧图片,也就是(% 2. 获取第一帧用于设置警戒线)这一步骤进行“灰度化 → 高斯滤波 → 梯度计算 → 自适应阈值 → 交互测量”这一操作。最终效果是:用户点击两个点之间的直线长度为1cm,然后再点击两个点,根据刚才的1CM计算出这两点之间的距离。
2、报警部分。报警部分在警报后停止视频继续播放,并只要记录第一次超过警戒线的时间。
function video_surveillance_system()
% 清除工作区
close all; clear; clc;
% 1. 读取视频文件
[filename, pathname] = uigetfile({'*.mp4;*.avi;*.mov','视频文件'}, '选择监控视频');
if isequal(filename, 0)
disp('用户取消选择');
return;
end
video_path = fullfile(pathname, filename);
video_reader = VideoReader(video_path);
% 2. 获取第一帧用于设置警戒线
first_frame = readFrame(video_reader);
fig = figure('Name', '视频监控系统 - 警戒线设置', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 600]);
subplot(1,2,1);
h_img = imshow(first_frame);
title('原始视频帧', 'FontSize', 12);
hold on;
% 3. 手动设置警戒线
subplot(1,2,2);
imshow(first_frame);
title('请设置警戒线:点击起点和终点', 'FontSize', 12);
hold on;
% 获取用户设置的两个点
[x, y] = ginput(2);
line_start = [x(1), y(1)];
line_end = [x(2), y(2)];
% 绘制警戒线
plot([line_start(1), line_end(1)], [line_start(2), line_end(2)], 'r-', 'LineWidth', 3);
plot(line_start(1), line_start(2), 'go', 'MarkerSize', 10, 'MarkerFaceColor', 'g');
plot(line_end(1), line_end(2), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
title('警戒线设置完成', 'FontSize', 12);
% 4. 初始化报警记录
alarm_log = table('Size', [0, 3], ...
'VariableTypes', {'double', 'double', 'double'}, ...
'VariableNames', {'FrameNumber', 'Timestamp', 'ObjectID'});
% 5. 创建报警日志文件
log_filename = 'alarm_log.csv';
fid = fopen(log_filename, 'w');
fprintf(fid, 'FrameNumber,Timestamp(s),ObjectID\n');
fclose(fid);
% 6. 初始化背景减法器
detector = vision.ForegroundDetector('NumGaussians', 3, 'NumTrainingFrames', 50, ...
'MinimumBackgroundRatio', 0.7, 'LearningRate', 0.005);
% 7. 创建斑点分析器
blob_analyzer = vision.BlobAnalysis('BoundingBoxOutputPort', true, ...
'AreaOutputPort', true, ...
'CentroidOutputPort', true, ...
'MinimumBlobArea', 500);
% 8. 主处理循环
frame_count = 0;
prev_centroids = [];
tracked_objects = {};
next_id = 1;
% 创建处理结果展示窗口
result_fig = figure('Name', '视频监控系统 - 实时分析', 'NumberTitle', 'off', 'Position', [100, 100, 1200, 600]);
while hasFrame(video_reader)
frame = readFrame(video_reader);
frame_count = frame_count + 1;
timestamp = frame_count / video_reader.FrameRate;
% 9. 运动目标检测
gray_frame = rgb2gray(frame);
foreground_mask = detector.step(gray_frame);
% 形态学操作去除噪声
se = strel('square', 3);
cleaned_mask = imopen(foreground_mask, se);
cleaned_mask = imclose(cleaned_mask, se);
cleaned_mask = imfill(cleaned_mask, 'holes');
% 10. 目标检测与跟踪
[areas, centroids, bboxes] = blob_analyzer.step(cleaned_mask);
% 目标跟踪
[tracked_objects, next_id] = track_objects(centroids, tracked_objects, next_id);
% 11. 越线检测
current_centroids = centroids;
alarm_triggered = false;
alarm_positions = [];
object_ids = [];
for i = 1:size(current_centroids, 1)
centroid = current_centroids(i, :);
object_id = tracked_objects{i}.id;
% 检查是否越过警戒线
if is_crossing_line(line_start, line_end, centroid)
alarm_triggered = true;
alarm_positions = [alarm_positions; centroid];
object_ids = [object_ids; object_id];
% 记录报警信息
new_entry = {frame_count, timestamp, object_id};
alarm_log = [alarm_log; new_entry];
% 写入日志文件
fid = fopen(log_filename, 'a');
fprintf(fid, '%d,%.2f,%d\n', frame_count, timestamp, object_id);
fclose(fid);
end
end
% 12. 显示处理结果
figure(result_fig);
subplot(1,2,1);
imshow(frame);
hold on;
% 绘制警戒线
plot([line_start(1), line_end(1)], [line_start(2), line_end(2)], 'r-', 'LineWidth', 3);
plot(line_start(1), line_start(2), 'go', 'MarkerSize', 10, 'MarkerFaceColor', 'g');
plot(line_end(1), line_end(2), 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
% 绘制检测到的目标
for i = 1:size(centroids, 1)
centroid = centroids(i, :);
object_id = tracked_objects{i}.id;
% 绘制目标边界框和ID
bbox = bboxes(i, :);
rectangle('Position', bbox, 'EdgeColor', 'g', 'LineWidth', 2);
text(bbox(1), bbox(2)-10, sprintf('ID: %d', object_id), ...
'Color', 'g', 'FontSize', 10, 'FontWeight', 'bold');
end
% 显示报警信息
if alarm_triggered
for i = 1:size(alarm_positions, 1)
pos = alarm_positions(i, :);
plot(pos(1), pos(2), 'rx', 'MarkerSize', 20, 'LineWidth', 3);
text(pos(1)+20, pos(2)+20, 'ALARM!', 'Color', 'r', ...
'FontSize', 16, 'FontWeight', 'bold');
end
title(sprintf('帧号: %d, 时间: %.2f秒 - 检测到越线!', frame_count, timestamp), ...
'Color', 'r', 'FontSize', 14);
else
title(sprintf('帧号: %d, 时间: %.2f秒', frame_count, timestamp), 'FontSize', 14);
end
% 显示运动目标检测结果
subplot(1,2,2);
imshow(cleaned_mask);
title('运动目标检测结果', 'FontSize', 12);
% 刷新显示
drawnow;
% 控制处理速度
pause(0.5 / video_reader.FrameRate);
end
% 13. 显示报警日志
disp('===== 报警事件记录 =====');
disp(alarm_log);
% 14. 绘制报警事件时间分布
figure('Name', '报警事件时间分布', 'NumberTitle', 'off');
if ~isempty(alarm_log)
plot(alarm_log.Timestamp, alarm_log.ObjectID, 'ro', 'MarkerSize', 8, 'MarkerFaceColor', 'r');
xlabel('时间 (秒)', 'FontSize', 12);
ylabel('目标ID', 'FontSize', 12);
title('报警事件时间分布', 'FontSize', 14);
grid on;
else
text(0.5, 0.5, '未检测到报警事件', 'HorizontalAlignment', 'center', 'FontSize', 16);
end
% 15. 保存报警日志
writetable(alarm_log, 'alarm_log_full.csv');
disp('处理完成!报警日志已保存为 alarm_log.csv 和 alarm_log_full.csv');
end
% 目标跟踪函数
function [tracked_objects, next_id] = track_objects(centroids, tracked_objects, next_id)
% 初始化新的跟踪对象列表
new_tracked_objects = cell(size(centroids, 1), 1);
% 如果没有检测到目标,重置跟踪
if isempty(centroids)
tracked_objects = {};
return;
end
% 如果没有现有跟踪对象,创建新对象
if isempty(tracked_objects)
for i = 1:size(centroids, 1)
new_tracked_objects{i} = struct('id', next_id, 'centroid', centroids(i, :));
next_id = next_id + 1;
end
tracked_objects = new_tracked_objects;
return;
end
% 计算现有对象和新检测点之间的距离
num_existing = length(tracked_objects);
num_new = size(centroids, 1);
distances = zeros(num_existing, num_new);
for i = 1:num_existing
for j = 1:num_new
distances(i, j) = norm(tracked_objects{i}.centroid - centroids(j, :));
end
end
% 分配ID给检测到的目标
assigned = false(num_new, 1);
for i = 1:num_existing
[min_dist, idx] = min(distances(i, :));
if min_dist < 50 % 距离阈值
tracked_objects{i}.centroid = centroids(idx, :);
new_tracked_objects{idx} = tracked_objects{i};
assigned(idx) = true;
distances(:, idx) = inf; % 标记为已分配
end
end
% 为未分配的目标创建新ID
for i = 1:num_new
if ~assigned(i)
new_tracked_objects{i} = struct('id', next_id, 'centroid', centroids(i, :));
next_id = next_id + 1;
end
end
tracked_objects = new_tracked_objects;
end
% 越线检测函数
function crossing = is_crossing_line(line_start, line_end, point)
% 计算点到直线的距离
numerator = abs((line_end(2)-line_start(2))*point(1) - ...
(line_end(1)-line_start(1))*point(2) + ...
line_end(1)*line_start(2) - line_end(2)*line_start(1));
denominator = norm(line_end - line_start);
distance = numerator / denominator;
% 计算点到线段起止点的距离
dist_to_start = norm(point - line_start);
dist_to_end = norm(point - line_end);
% 计算线段长度
line_length = norm(line_end - line_start);
% 检查点是否在警戒线附近
proximity_threshold = line_length * 0.05; % 警戒线长度的5%
crossing = (distance < 15) && (dist_to_start < line_length + proximity_threshold) && ...
(dist_to_end < line_length + proximity_threshold);
end
最新发布