红外弱小目标检测MATLAB代码推荐
红外弱小目标检测的难点很明确:目标像素少、信噪比低、背景杂波复杂。平衡检测率与虚警率常需反复调参、对比多种算法。下面这套 MATLAB 代码将几种主流小目标检测方法打包在一起,覆盖预处理、分割、评估到报告输出,安装即用——特别适合算法对比实验与快速原型验证。
程序功能总览
1. 核心功能特性
这套代码覆盖了完整的检测链路:
- 集成5种主流小目标检测算法
- 包含完整的预处理与背景抑制流程
- 支持Otsu、自适应、百分比三种分割阈值方法
- 自带性能评估指标与可视化模块
- 自动生成检测报告,方便复现与对比
从模拟数据生成到最终报告输出,一条龙跑完,省去大量重复编码。
2. 集成算法清单
- Top-Hat 滤波:经典形态学方法,对小目标增强效果好,依赖结构元素尺寸匹配。
- 最大中值滤波:利用局部窗口最大值与中值的差值突出目标,对脉冲噪声有一定鲁棒性。
- 局部对比度方法(LCM):基于人眼视觉特性,通过内外窗口对比度定位目标。
- 改进的 LCM(ILCM):加入中心与周围最小值的对比度量,抗背景干扰能力更强。
- 梯度加权方法:结合梯度幅值与局部均值,适合边缘或纹理较清晰的场景。
3. 快速上手
将完整代码保存为 infrared_target_detection.m,在 MATLAB 中直接运行即可。默认会生成一幅模拟红外图像,包含随机位置、大小和强度的弱小目标(3~8个)。随后依次执行背景抑制、五种算法检测、三种阈值分割,最后输出性能评估表格和检测报告。
不想准备数据就直接跑,看看效果。运行结束后你会看到一系列对比图:原始图像、背景抑制结果、各算法的检测响应图,以及不同阈值方法下分割标记后的直观结果。
4. 如何替换为真实数据
换成自己的红外图像也很简单,在代码中找到第13行(生成模拟图像那一行):
% 原代码
img = generateSimulatedIRImage();
% 替换为:
img = imread('your_image.pgm'); % 读入原始图像
img = rgb2gray(img); % 若是彩色图,先转灰度
注意真实图像的灰度分布和目标特性通常与模拟数据不同,你可能需要微调后续的阈值参数。
5. 参数调优建议
几个关键参数的调整方向:
- 目标大小:Top-Hat 滤波的结构元素尺寸(第148行附近)应与目标直径匹配,一般设为目标直径的1.5~2倍。
- 检测灵敏度:自适应阈值中的
'Sensitivity'参数(第248行)默认0.6,调高会检测出更多目标,但虚警也会上升。 - 窗口尺寸:最大中值滤波和LCM算法的窗口大小(第161行、第179行)根据目标大小设定。窗口太小背景估计不准,太大则可能漏掉弱小目标。
没有一套参数通吃所有场景,建议先用模拟数据调通流程,再对准真实数据微调。实际经验表明,ILCM 与梯度加权方法在低信噪比下通常比 Top-Hat 和原始 LCM 更稳定。
%% ==============================================
% 红外弱小目标检测系统
% 用途:集成多种小目标检测算法,便于对比与验证
%% ==============================================
clear all; close all; clc;
%% 1. 读取并显示原始红外图像
% 你可以用自己的红外图像,这里先生成模拟图像
disp('生成模拟红外图像中...');
img = generateSimulatedIRImage();
original_img = img;
figure('Name', '原始红外图像', 'Position', [100, 100, 1200, 400]);
subplot(1,3,1);
imshow(original_img, []);
title('原始红外图像');
colorbar;
% 直方图均衡化增强显示
subplot(1,3,2);
img_enhanced = histeq(original_img);
imshow(img_enhanced, []);
title('直方图均衡化增强');
colorbar;
% 3D表面图显示
subplot(1,3,3);
[x, y] = meshgrid(1:size(original_img,2), 1:size(original_img,1));
surf(x, y, double(original_img), 'EdgeColor', 'none');
title('红外图像3D表面图');
xlabel('X轴'); ylabel('Y轴'); zlabel('强度');
colormap('hot');
view(-30, 60);
%% 2. 预处理——背景抑制
disp('执行背景抑制...');
background_suppressed = backgroundSuppression(original_img);
figure('Name', '背景抑制结果', 'Position', [100, 100, 1000, 400]);
subplot(1,2,1);
imshow(original_img, []);
title('原始图像');
subplot(1,2,2);
imshow(background_suppressed, []);
title('背景抑制后图像');
colorbar;
%% 3. 多种目标检测算法
disp('开始多算法目标检测...');
% 3.1 Top-Hat滤波
tophat_result = topHatFilter(original_img);
% 3.2 最大中值滤波
maxmedian_result = maxMedianFilter(original_img);
% 3.3 局部对比度方法 (LCM)
lcm_result = localContrastMethod(original_img);
% 3.4 改进局部对比度方法 (ILCM)
ilcm_result = improvedLCM(original_img);
% 3.5 梯度加权方法
gradient_result = gradientWeightedMethod(original_img);
%% 4. 显示所有检测结果
figure('Name', '多算法结果对比', 'Position', [50, 50, 1400, 800]);
% 原始图像
subplot(2,3,1);
imshow(original_img, []);
title('原始红外图像');
colorbar;
% Top-Hat滤波
subplot(2,3,2);
imshow(tophat_result, []);
title('Top-Hat滤波');
colorbar;
% 最大中值滤波
subplot(2,3,3);
imshow(maxmedian_result, []);
title('最大中值滤波');
colorbar;
% LCM方法
subplot(2,3,4);
imshow(lcm_result, []);
title('局部对比度 (LCM)');
colorbar;
% ILCM方法
subplot(2,3,5);
imshow(ilcm_result, []);
title('改进LCM (ILCM)');
colorbar;
% 梯度加权方法
subplot(2,3,6);
imshow(gradient_result, []);
title('梯度加权方法');
colorbar;
%% 5. 目标分割与标记
disp('进行目标分割与标记...');
threshold_methods = {'otsu', 'adaptive', 'percentile'};
segmentation_results = cell(1, length(threshold_methods));
figure('Name', '目标分割结果', 'Position', [100, 100, 1200, 400]);
for i = 1:length(threshold_methods)
% 用ILCM结果分割(效果相对更稳)
binary_mask = targetSegmentation(ilcm_result, threshold_methods{i});
segmentation_results{i} = binary_mask;
% 连通域标记
[labeled_img, num_targets] = labelTargets(binary_mask);
% 显示分割标签图
subplot(1,3,i);
imshow(label2rgb(labeled_img, 'jet', 'k', 'shuffle'));
title(sprintf('%s阈值: 检测到%d个目标', ...
upper(threshold_methods{i}), num_targets));
% 在原图上叠加标记
figure_temp = figure('Visible', 'off');
imshow(original_img, []);
hold on;
stats = regionprops(labeled_img, 'Centroid', 'BoundingBox');
for j = 1:length(stats)
centroid = stats(j).Centroid;
plot(centroid(1), centroid(2), 'r*', 'MarkerSize', 15, 'LineWidth', 2);
rectangle('Position', stats(j).BoundingBox, ...
'EdgeColor', 'g', 'LineWidth', 2);
end
hold off;
title(sprintf('原图上标记 (%s阈值)', upper(threshold_methods{i})));
% 捕获当前图像
frame = getframe(gcf);
close(figure_temp);
figure('Name', sprintf('目标标记结果-%s', upper(threshold_methods{i})), ...
'Position', [100, 100, 800, 600]);
imshow(frame.cdata);
title(sprintf('共检测到%d个弱小目标', num_targets));
end
%% 6. 性能评估
disp('评估各方法检测性能...');
% 用模拟目标的真实位置(已知)
[true_targets, ~] = generateSimulatedTargets(size(original_img));
% 评估不同方法
methods = {'Top-Hat', 'Max-Median', 'LCM', 'ILCM', 'Gradient'};
results = {tophat_result, maxmedian_result, lcm_result, ilcm_result, gradient_result};
figure('Name', '检测性能评估', 'Position', [100, 100, 1000, 600]);
for i = 1:length(methods)
% 转为二值图像做评估
binary_result = imbinarize(mat2gray(results{i}), 'adaptive');
% 计算指标
metrics = evaluateDetection(binary_result, true_targets);
% 显示评估结果
subplot(2,3,i);
imshow(binary_result);
title(sprintf('%s\n精确度: %.2f%%, 召回率: %.2f%%', ...
methods{i}, metrics.precision*100, metrics.recall*100));
fprintf('方法: %s\n', methods{i});
fprintf('精确度: %.2f%%\n', metrics.precision*100);
fprintf('召回率: %.2f%%\n', metrics.recall*100);
fprintf('F1分数: %.2f%%\n', metrics.f1_score*100);
fprintf('虚警率: %.2f%%\n', metrics.false_alarm_rate*100);
end
%% 7. 生成检测报告
generateDetectionReport(methods, metrics, num_targets);
disp('红外弱小目标检测流程完成!');
%% ==============================================
% 辅助函数定义
%% ==============================================
% 生成模拟红外图像
function img = generateSimulatedIRImage()
% 创建背景(模拟天空或均匀场景)
[rows, cols] = deal(256);
background = 100 + 20 * randn(rows, cols);
% 添加云层纹理
[X, Y] = meshgrid(1:cols, 1:rows);
cloud_pattern = 15 * sin(0.05*X + 0.1*Y) + 10 * cos(0.03*X + 0.07*Y);
background = background + cloud_pattern;
% 叠加高斯噪声
background = background + 5 * randn(rows, cols);
% 添加弱小目标(小亮点)
img = background;
num_targets = randi([3, 8]); % 随机生成3-8个目标
for i = 1:num_targets
% 随机位置
target_row = randi([20, rows-20]);
target_col = randi([20, cols-20]);
% 目标大小(小目标,3x3到5x5像素)
target_size = randi([2, 3]);
% 目标强度(高于背景)
target_intensity = 80 + 40 * rand();
% 高斯形状目标
[x, y] = meshgrid(-target_size:target_size, -target_size:target_size);
gaussian_target = target_intensity * exp(-(x.^2 + y.^2)/(2*(target_size/2)^2));
% 将目标嵌入图像
r_start = max(1, target_row-target_size);
r_end = min(rows, target_row+target_size);
c_start = max(1, target_col-target_size);
c_end = min(cols, target_col+target_size);
target_r_start = target_size - (target_row - r_start) + 1;
target_r_end = target_size + (r_end - target_row) + 1;
target_c_start = target_size - (target_col - c_start) + 1;
target_c_end = target_size + (c_end - target_col) + 1;
img(r_start:r_end, c_start:c_end) = ...
img(r_start:r_end, c_start:c_end) + ...
gaussian_target(target_r_start:target_r_end, target_c_start:target_c_end);
end
% 转换为uint8
img = uint8(mat2gray(img) * 255);
end
% 背景抑制函数
function suppressed_img = backgroundSuppression(img)
% 用引导滤波估计背景
img_double = double(img);
% 引导滤波(保边平滑)
guided_bg = imguidedfilter(img);
% 减去背景
suppressed_img = img_double - double(guided_bg);
% 增强对比度
suppressed_img = suppressed_img - min(suppressed_img(:));
suppressed_img = suppressed_img / max(suppressed_img(:)) * 255;
end
% Top-Hat滤波
function result = topHatFilter(img)
% 形态学Top-Hat增强小目标
se = strel('disk', 3); % 结构元素大小根据目标尺寸调整
result = imtophat(img, se);
end
% 最大中值滤波
function result = maxMedianFilter(img)
img_double = double(img);
[rows, cols] = size(img_double);
result = zeros(rows, cols);
% 窗口大小
window_size = 5;
half_win = floor(window_size/2);
for i = 1+half_win:rows-half_win
for j = 1+half_win:cols-half_win
% 提取局部窗口
local_window = img_double(i-half_win:i+half_win, j-half_win:j+half_win);
% 中值
median_val = median(local_window(:));
% 最大值与中值之差
max_val = max(local_window(:));
result(i,j) = max_val - median_val;
end
end
end
% 局部对比度方法 (LCM)
function result = localContrastMethod(img)
img_double = double(img);
[rows, cols] = size(img_double);
result = zeros(rows, cols);
% 内窗口与外窗口尺寸
inner_size = 3;
outer_size = 9;
half_outer = floor(outer_size/2);
for i = 1+half_outer:rows-half_outer
for j = 1+half_outer:cols-half_outer
% 内窗口(目标区域)
inner_region = img_double(i-1:i+1, j-1:j+1);
% 外窗口(背景区,排除内窗口)
outer_region = img_double(i-half_outer:i+half_outer, j-half_outer:j+half_outer);
outer_region(inner_size:inner_size+2, inner_size:inner_size+2) = NaN;
% 局部对比度计算
inner_mean = mean(inner_region(:));
outer_mean = nanmean(outer_region(:));
inner_max = max(inner_region(:));
if outer_mean > 0
result(i,j) = (inner_max - outer_mean) / outer_mean;
else
result(i,j) = 0;
end
end
end
end
% 改进局部对比度方法 (ILCM)
function result = improvedLCM(img)
img_double = double(img);
[rows, cols] = size(img_double);
result = zeros(rows, cols);
window_size = 9;
half_win = floor(window_size/2);
for i = 1+half_win:rows-half_win
for j = 1+half_win:cols-half_win
% 提取窗口
window = img_double(i-half_win:i+half_win, j-half_win:j+half_win);
% 中心像素与周围对比
center_val = window(half_win+1, half_win+1);
surrounding = window;
surrounding(half_win+1, half_win+1) = NaN;
% 改进度量:同时考虑均值和极差
max_surround = nanmax(surrounding(:));
min_surround = nanmin(surrounding(:));
mean_surround = nanmean(surrounding(:));
if mean_surround > 0
contrast1 = (center_val - mean_surround) / mean_surround;
contrast2 = (center_val - min_surround) / (max_surround - min_surround + eps);
result(i,j) = contrast1 * contrast2;
else
result(i,j) = 0;
end
end
end
end
% 梯度加权方法
function result = gradientWeightedMethod(img)
% 计算梯度幅值
[Gx, Gy] = imgradientxy(img);
gradient_mag = sqrt(Gx.^2 + Gy.^2);
% 归一化梯度
gradient_norm = mat2gray(gradient_mag);
% 局部均值
mean_filter = fspecial('average', 5);
local_mean = imfilter(double(img), mean_filter);
% 梯度加权
result = double(img) .* gradient_norm - local_mean;
% 去掉负值
result(result < 0) = 0;
end
% 目标分割函数
function binary_mask = targetSegmentation(img, method)
img_normalized = mat2gray(img);
switch lower(method)
case 'otsu'
level = graythresh(img_normalized);
binary_mask = imbinarize(img_normalized, level);
case 'adaptive'
binary_mask = imbinarize(img_normalized, 'adaptive', ...
'Sensitivity', 0.6, 'ForegroundPolarity', 'bright');
case 'percentile'
% 百分比阈值:取前2%最亮像素
sorted_vals = sort(img_normalized(:));
percentile = 98;
idx = round(length(sorted_vals) * percentile / 100);
threshold = sorted_vals(idx);
binary_mask = img_normalized > threshold;
otherwise
error('未知的阈值方法');
end
% 形态学去噪:移除小于3像素的区域,闭运算连接邻近目标
binary_mask = bwareaopen(binary_mask, 3);
se = strel('disk', 1);
binary_mask = imclose(binary_mask, se);
end
% 标记目标函数
function [labeled_img, num_targets] = labelTargets(binary_mask)
% 连通区域标记
labeled_img = bwlabel(binary_mask);
num_targets = max(labeled_img(:));
end
% 评估检测性能函数
function metrics = evaluateDetection(detected, ground_truth)
% 计算真阳性、假阳性、假阴性、真阴性
true_positive = sum(detected(:) & ground_truth(:));
false_positive = sum(detected(:) & ~ground_truth(:));
false_negative = sum(~detected(:) & ground_truth(:));
true_negative = sum(~detected(:) & ~ground_truth(:));
% 各项指标
if (true_positive + false_positive) > 0
metrics.precision = true_positive / (true_positive + false_positive);
else
metrics.precision = 0;
end
if (true_positive + false_negative) > 0
metrics.recall = true_positive / (true_positive + false_negative);
else
metrics.recall = 0;
end
if (metrics.precision + metrics.recall) > 0
metrics.f1_score = 2 * metrics.precision * metrics.recall / ...
(metrics.precision + metrics.recall);
else
metrics.f1_score = 0;
end
metrics.false_alarm_rate = false_positive / (false_positive + true_negative);
end
% 生成模拟目标真实位置
function [ground_truth, target_positions] = generateSimulatedTargets(img_size)
% 简单生成一些随机目标位置
rows = img_size(1);
cols = img_size(2);
ground_truth = false(rows, cols);
% 随机生成5个目标
num_targets = 5;
target_positions = zeros(num_targets, 2);
for i = 1:num_targets
r = randi([20, rows-20]);
c = randi([20, cols-20]);
target_positions(i,:) = [r, c];
% 在目标位置创建小区域
ground_truth(r-1:r+1, c-1:c+1) = true;
end
end
% 生成检测报告
function generateDetectionReport(methods, metrics, num_detected)
fprintf('========== 检测报告 ==========\n');
fprintf('检测时间: %s\n', datestr(now));
fprintf('检测到的目标数量: %d\n', num_detected);
fprintf('各方法性能对比:\n');
fprintf('%-15s %-10s %-10s %-10s\n', '方法', '精确度', '召回率', 'F1');
fprintf('--------------------------------------------\n');
for i = 1:length(methods)
fprintf('%-15s %-10.2f %-10.2f %-10.2f\n', ...
methods{i}, metrics(i).precision, metrics(i).recall, metrics(i).f1_score);
end
fprintf('==========================================\n');
% 保存报告到文件
report_filename = sprintf('detection_report_%s.txt', datestr(now, 'yyyymmdd_HHMMSS'));
fid = fopen(report_filename, 'w');
if fid ~= -1
fprintf(fid, '红外弱小目标检测报告\n');
fprintf(fid, '生成时间: %s\n', datestr(now));
fprintf(fid, '检测统计:\n');
fprintf(fid, '总检测目标数: %d\n', num_detected);
fclose(fid);
fprintf('检测报告已保存到: %s\n', report_filename);
end
end