基于图像处理的铁路裂缝检测系统

一、系统架构与核心思路

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;
相关推荐
程xu袁2 小时前
AI写歌词和AI作曲有什么区别?想做完整歌曲,AI音乐工具怎么选?
人工智能
ACME20442 小时前
破产财产处置新规落地,管理人如何选聘拍卖机构?
人工智能
matlab代码2 小时前
基于matlab阈值分割的车牌识别系统【源码75期】
图像处理·opencv·计算机视觉
AI让世界更懂你2 小时前
计算机专业研究生核心能力培养(6)——论文写作的表达与打磨
人工智能
风之清扬2 小时前
Agent学习之四-初识Agent CLI
人工智能·科技·学习
零依赖极客2 小时前
Day 9·1 KV 也量化——q8 KV 把缓存与 decode 带宽压到一半
c语言·开发语言·arm开发·人工智能·缓存·矩阵
陈童学哦2 小时前
AI术语大全
人工智能
tuanxiang2 小时前
用去AI味工具调整大模型生成的技术文档,我踩了检测阈值的坑
人工智能
天辛大师2 小时前
天辛大师谈AI时代的沉思录,All in AI 持续做事与放大效应
大数据·人工智能·随机森林·重构·启发式算法
不要生病了2 小时前
Brain-JEPA:用功能梯度定位与时空遮蔽预训练 fMRI 基础模型
人工智能·深度学习