一、系统架构与核心思路
1.1 检测原理
铁路裂缝在图像中表现为:
- 形态特征:细长、曲折、暗色线条
- 灰度特征:局部低灰度值区域
- 纹理特征:破坏轨面均匀纹理
1.2 处理流程
原始图像 → 预处理 → 裂缝增强 → 分割提取 → 形态学优化 → 特征筛选 → 标记输出
二、完整 MATLAB 实现
2.1 主程序
matlab
%% 基于图像处理的铁路裂缝检测系统
clear; clc; close all;
%% 1. 读取图像
img_path = 'rail_crack.jpg'; % 替换为实际图像路径
I = imread(img_path);
% 如果是彩色图则转换
if ndims(I) == 3
I_gray = rgb2gray(I);
else
I_gray = I;
end
I_gray = im2double(I_gray);
fprintf('图像尺寸: %d × %d\n', size(I_gray,1), size(I_gray,2));
%% 2. 预处理
fprintf('预处理...\n');
I_denoised = denoise_rail_image(I_gray);
%% 3. 裂缝增强(多方法融合)
fprintf('裂缝增强...\n');
I_enhanced = enhance_crack(I_denoised);
%% 4. 分割提取
fprintf('分割提取...\n');
BW_raw = segment_crack(I_enhanced);
%% 5. 形态学优化
fprintf('形态学优化...\n');
BW_clean = morphological_refinement(BW_raw, size(I_gray));
%% 6. 特征筛选(去除伪裂缝)
fprintf('特征筛选...\n');
[crack_mask, crack_props] = filter_crack_regions(BW_clean, I_gray);
%% 7. 可视化结果
fprintf('绘制结果...\n');
visualize_crack_detection(I, I_gray, I_enhanced, BW_raw, crack_mask, crack_props);
%% 8. 定量输出
fprintf('\n========== 检测结果 ==========\n');
if ~isempty(crack_props)
for i = 1:length(crack_props)
fprintf('裂缝 #%d: 面积=%d px, 长度≈%.1f px, 平均宽度≈%.1f px, 方向=%.1f°\n', ...
i, crack_props(i).Area, crack_props(i).MajorAxisLength, ...
crack_props(i).MeanWidth, crack_props(i).Orientation);
end
else
fprintf('未检测到裂缝。\n');
end
2.2 预处理模块
matlab
function I_out = denoise_rail_image(I)
% 铁路图像专用去噪:保留边缘,抑制轨面纹理噪声
% 1. 引导滤波 / 双边滤波(保边去噪)
I_out = imbilatfilt(I, 'DegreeOfSmoothing', 0.1, 'SpatialSigma', 2, 'RangeSigma', 0.05);
% 2. 轻度高斯平滑(进一步压制椒盐噪声)
I_out = imgaussfilt(I_out, 0.5);
% 3. 对比度受限自适应直方图均衡(CLAHE)--- 拉出暗裂缝对比度
I_out = adapthisteq(I_out, 'ClipLimit', 0.02, 'Distribution', 'rayleigh');
end
2.3 裂缝增强(核心)
matlab
function I_enh = enhance_crack(I)
% 用 Hessian 多尺度血管/裂纹增强(Frangi filter 思路简化版)
% 辅以顶帽变换抓极暗细节
%% 方法1:基于 Hessian 的第二方向增强(裂缝=线性暗结构)
scales = [1.5, 2.5, 4]; % 对应不同裂缝宽度
resp = zeros(size(I));
for s = scales
[~,~, hess, ~] = imgradientxy(imgaussfilt(I, s), 'central');
% Hessian: [Ixx Ixy; Ixy Iyy]
Ix = imgradientx(imgaussfilt(I, s));
Iy = imgradienty(imgaussfilt(I, s));
Ixx = imgradientx(Ix);
Iyy = imgradienty(Iy);
Ixy = imgradienty(Ix);
% 特征值(2×2 Hessian)
% 裂缝希望 λ1≈0,λ2负大(暗脊沿λ1方向)
% 用 |λ2|/(|λ1|+eps) 作为线性度
for r = 1:size(I,1)
for c = 1:size(I,2)
H = [Ixx(r,c) Ixy(r,c); Ixy(r,c) Iyy(r,c)];
[V,D] = eig(H);
l = diag(D);
l = sort(l, 'descend'); % l1≥l2
if l(2) < 0 % 沿第二特征方向是"暗"
score = abs(l(2)) / (abs(l(1)) + 1e-6);
resp(r,c) = max(resp(r,c), score * (1 - exp(l(2)/0.01)));
end
end
end
end
%% 方法2:顶帽(Top-hat)抓暗细节
se = strel('disk', 7);
top = imtophat(I, se); % 亮异常
bot = imbothat(I, se); % 暗异常
I_bot = mat2gray(bot); % 暗细节图
%% 融合
I_enh = mat2gray(resp) .* 0.7 + I_bot .* 0.3;
I_enh = mat2gray(I_enh);
end
如果觉得 Hessian 逐像素 eig 太慢,可用
imgradient+ 结构张量 的简化版:
matlab
function I_enh = enhance_crack_fast(I)
% 更快的裂缝增强(结构张量 / 方向二阶导)
I = im2double(I);
I_enh = zeros(size(I));
for sigma = [1.5, 2.5, 4]
G = fspecial('gaussian', ceil(sigma*6), sigma);
Ig = conv2(I, G, 'same');
% 一阶导
[gx, gy] = imgradientxy(Ig, 'central');
% 二阶导沿梯度垂直方向 ( -gy, gx )
Jxx = conv2(gx.^2, G, 'same');
Jxy = conv2(gx.*gy, G, 'same');
Jyy = conv2(gy.^2, G, 'same');
% 沿垂直方向的二阶导(类似"暗线"响应)
Jdet = Jxx.*Jyy - Jxy.^2 + 1e-10;
Jtr = Jxx + Jyy;
% 线性度:|λmin|大且各向异性
lin = sqrt(max((Jtr.^2 - 4*Jdet),0)) ./ (Jtr + eps);
dark_line_resp = -min(Jxx, Jyy); % 暗区+线状
score = lin .* (dark_line_resp);
I_enh = max(I_enh, score);
end
I_enh = mat2gray(I_enh);
end
2.4 分割提取
matlab
function BW = segment_crack(I_enh)
% 多阈值策略:Otsu + 局部自适应底线
% 全局 Otsu(裂缝应为低灰度/高增强值,注意上面增强输出在 0-1)
T_otsu = graythresh(I_enh);
BW1 = I_enh > T_otsu * 1.1; % 增强图上用">",因增强后裂缝亮
% 如果上一步得到的反了(视增强极性),也可用原图暗区:
T_dark = graythresh(I_enh);
BW2 = I_enh < T_dark * 0.6; % 若裂缝是暗的,用<
% 融合(OR),并对边缘做一下清理
BW = BW1 | BW2;
BW = imfill(BW, 'holes');
BW = bwareaopen(BW, 20); % 去极小噪点
end
2.5 形态学优化(非常关键)
matlab
function BW_out = morphological_refinement(BW, imgsize)
% 根据裂缝"细长"特性做连接与修剪
% 1. 先轻度开:去掉毛刺
se1 = strel('line', 6, 0);
BW = imopen(BW, se1); % 水平方向开运算
se2 = strel('line', 6, 90);
BW = imopen(BW, se2); % 竖直方向开运算
% 2. 闭运算:连接断裂裂缝(短断开)
se3 = strel('line', 12, 45); % 沿典型裂缝方向
BW = imclose(BW, se3);
BW = imclose(BW, strel('disk',2));
% 3. 再去掉小区域
BW_out = bwareaopen(BW, 50);
end
2.6 特征筛选(拒绝伪裂缝:油污/阴影/锈迹)
matlab
function [mask, props] = filter_crack_regions(BW, I_gray)
% 用区域几何+灰度特征筛掉非裂缝
CC = bwconncomp(BW);
mask = false(size(BW));
props = [];
idx = 0;
for k = 1:CC.NumObjects
region = false(size(BW));
region(CC.PixelIdxList{k}) = true;
% 基本几何
stats = regionprops(region, I_gray, ...
{'Area','MajorAxisLength','MinorAxisLength','Orientation', ...
'Eccentricity','Solidity','Centroid','PixelIdxList'});
s = stats(1);
% 平均宽度估计
if s.MinorAxisLength > 0
MeanWidth = s.Area / s.MajorAxisLength;
else
MeanWidth = 0;
end
% ---- 规则:裂缝先验 ----
% 1) 面积不能太小
rule1 = s.Area > 80;
% 2) "细长":长度 >> 宽度
rule2 = (s.MajorAxisLength / max(MeanWidth,1)) > 3.5;
% 3) 偏心/实心度:裂缝通常不太"蓬松"
rule3 = s.Eccentricity > 0.7 && s.Solidity > 0.3;
% 4) 灰度:裂缝应在轨面偏暗侧
region_vals = I_gray(s.PixelIdxList);
rule4 = mean(region_vals) < graythresh(I_gray)*0.85;
if rule1 && rule2 && rule3 && rule4
idx = idx + 1;
mask = mask | region;
props(idx).Area = s.Area;
props(idx).MajorAxisLength = s.MajorAxisLength;
props(idx).MeanWidth = MeanWidth;
props(idx).Orientation = s.Orientation;
props(idx).Centroid = s.Centroid;
end
end
end
2.7 可视化
matlab
function visualize_crack_detection(I_rgb, I_gray, I_enh, BW_raw, mask, props)
figure('Position',[100 100 1400 900]);
subplot(2,3,1);
if ndims(I_rgb)==3, imshow(I_rgb); else imshow(I_rgb,[]); end
title('原始图像');
subplot(2,3,2);
imshow(I_gray,[]); title('灰度图');
subplot(2,3,3);
imshow(I_enh,[]); title('裂缝增强图');
subplot(2,3,4);
imshow(BW_raw); title('分割二值图(粗)');
subplot(2,3,5);
imshow(mask); title('裂缝掩膜(精)');
subplot(2,3,6);
if ndims(I_rgb)==3, imshow(I_rgb); else imshow(I_gray,[]); end; hold on;
% 轮廓标红
if any(mask(:))
BW3 = imdilate(mask, strel('disk',2));
[B,L] = bwboundaries(mask,'noholes');
for b = 1:length(B)
boundary = B{b};
plot(boundary(:,2), boundary(:,1), 'r', 'LineWidth', 2);
end
% 中心点
for i = 1:length(props)
plot(props(i).Centroid(1), props(i).Centroid(2), 'yo', ...
'MarkerSize',8,'LineWidth',2);
end
end
title('裂缝标记结果');
hold off;
end
参考代码 利用图像处理的铁路裂缝检测 www.youwenfan.com/contentcsv/79246.html
三、针对"轨面反光/阴影"的实用技巧
铁路现场图像经常有:
- 轨面镜面反光(亮斑)
- 锈迹/油污(大面积暗色但不是裂缝)
- 枕木/扣件边缘(直线但不是裂缝)
对策 :在 filter_crack_regions 里再加两条硬规则即可大幅降误报:
matlab
% 5) 不是大面积暗块:对比度局部应高(裂缝两侧灰度跳变)
edgeStrength = mean(imgradient(I_gray)); % 全局参考
localGrad = imgradient(region_vals .* double(region)); % 伪
% 更直接:沿主轴方向灰度剖面应有"低-高(背景)-低"三明治
rule5 = (std(region_vals) / (mean(region_vals)+eps)) > 0.18;
% 6) 长宽比 + 面积上限:拒绝"大片暗斑"
rule6 = s.Area < prod(size(I_gray)) * 0.08;