MATLAB纹理特征提取实战:GLCM、LBP、Gabor等六种方法详解 简介本资源是一套面向图像处理初学者与科研人员的MATLAB纹理特征提取工具集聚焦于计算机视觉中的纹理分析核心任务涵盖GLCM、GLDS、LBP、GMRF、FD和Gabor六类主流方法适用于遥感图像分类、医学影像识别、工业缺陷检测等实际场景。压缩包为RAR格式大小255KB包含多个功能完整、结构清晰的MATLAB脚本文件.m为主每个方法均封装为独立可调用函数并附带示例调用逻辑与关键参数说明便于理解原理、调试验证及集成到自有项目中。已有3558人学习下载代码经实测可用注释详尽覆盖特征计算、归一化、统计量提取等全流程显著降低从理论到实践的门槛。读者可直接运行对比不同方法在相同图像上的输出效果快速掌握各算法的适用边界与性能差异。 作为一个常年跟图像特征打交道的人我几乎每天都要跟纹理特征提取打交道。最近在整理代码库时发现MATLAB环境下纹理特征提取的相关实现虽然网上零零散散有不少但大多只讲了某一种方法或者代码写得让人看不懂。这里我把实际项目中用过的六种常用纹理特征提取方法——GLCM、GLDS、LBP、GMRF、FD、Gabor——统一整理了一遍从原理到MATLAB完整实现一次讲清楚。这篇内容适合正在做图像处理大作业的学生、刚入门纹理分析的研究者以及需要在工程项目里快速落地纹理特征的工程师。我会按“用什么、为什么用、怎么写、怎么调参”的顺序来讲代码都是可以复制后直接跑的已经把常见的坑都提前踩过了。1. 纹理特征提取的整体设计思路与选型逻辑1.1 为什么偏偏是这六种方法纹理特征的本质是描述图像局部区域内像素灰度值的空间分布规律。不同应用场景对纹理特征的要求完全不同这正是需要同时掌握多种方法的原因。GLCM灰度共生矩阵偏重统计特性适合描述粗糙度、方向性GLDS灰度梯度共生矩阵更进一步把梯度信息纳入统计框架对边缘敏感LBP局部二值模式计算效率极高对光照变化不敏感在实时系统里几乎是首选GMRF高斯马尔可夫随机场走的是模型路线用参数来刻画纹理的随机过程FD分形维数从自相似性的角度看纹理复杂度对某些自然纹理有奇效Gabor变换则是在频域上精细划分方向和尺度模拟人眼视觉机制。这六种方法的组合几乎可以覆盖纹理分析领域的大多数需求。实际项目中我常用的策略是先用GLCM和LBP这类快速方法做预筛选再用Gabor或GMRF对候选区域做精细分析。1.2 方法分类统计派、模型派和变换派从理论根源上这六种方法可以归为三大流派。统计派认为纹理是像素灰度值在空间上的统计分布规律GLCM、GLDS、LBP都属于这一类它们直接统计像素之间的关系实现简单解释性强。模型派通过假设纹理服从某种随机过程用模型参数作为特征GMRF是典型代表优点是特征维度低缺点是需要估计参数计算量较大。变换派把图像变换到频域或尺度空间在变换系数中提取特征Gabor和FD中基于频域的实现属于这一类能够同时捕捉不同尺度和方向的纹理信息。选择哪种方法不能拍脑袋。我的经验是如果目标是图像分类且样本量大优先考虑LBP和GLCM的组合如果目标是对纹理做精细分割或边界定位Gabor滤波器组更合适如果纹理具有明显的自相似特性比如云图、地形图、某些生物组织图像FD往往能给出意想不到的好效果。1.3 MATLAB作为实现平台的优势MATLAB在做纹理特征提取时的优势非常明显图像处理工具箱提供了强大的矩阵运算能力很多统计量可以直接用矩阵操作完成不需要自己写循环内置的NLFILTER、BLOCKPROC等函数可以方便地做邻域操作可视化方便可以随时查看中间结果对调试非常有帮助。另外MATLAB的imageDatastore配合tall数组可以处理超大图像集这在做批量纹理特征提取时特别实用。后面我会给出一个完整的代码框架把六种方法整合到一个函数里方便直接调用。2. 统计类方法GLCM 与 GLDS 的完整实现与调参要点2.1 GLCM灰度共生矩阵核心原理与四个方向实现灰度共生矩阵的核心思想是统计图像中相距某一距离、某一方向的两个像素对灰度值同时出现的概率。假设图像灰度级数为LGLCM就是一个L×L的矩阵矩阵元素P(i,j)表示满足特定空间关系的、灰度值分别为i和j的像素对出现的次数。 这里的“特定空间关系”由距离d和方向θ决定。通常取d1θ分别取0°、45°、90°、135°四个方向。MATLAB实现时可以直接用工具箱里的graycomatrix但为了说清楚原理也为了后续扩展自定义特征我通常自己写核心统计部分function glcm computeGLCM(img, d, theta) % img: 输入灰度图像值范围0~255 % d: 像素对距离通常为1 % theta: 方向取0, 45, 90, 135 [rows, cols] size(img); L 256; glcm zeros(L, L); % 根据方向确定偏移量 switch theta case 0 rowOff 0; colOff d; case 45 rowOff -d; colOff d; case 90 rowOff -d; colOff 0; case 135 rowOff -d; colOff -d; otherwise error(theta必须为0, 45, 90或135); end % 遍历像素对累加计数 for i 1:rows for j 1:cols i2 i rowOff; j2 j colOff; if i2 1 i2 rows j2 1 j2 cols glcm(img(i,j)1, img(i2,j2)1) ... glcm(img(i,j)1, img(i2,j2)1) 1; end end end end在实际使用前通常要把GLCM归一化让所有元素之和为1得到联合概率分布。然后用这个分布计算各种统计量。最常用的是Haralick提出的14个特征但实际项目中大部分情况下用5个就足够了能量角二阶矩sum sum P(i,j)^2反映纹理的粗细和灰度分布的均匀程度对比度sum sum (i-j)^2 * P(i,j)反映纹理的清晰度和沟纹深浅相关性衡量灰度在行或列方向上的相似程度熵反映纹理的随机性和复杂程度逆差矩反映纹理的局部均匀性实现这些特征的代码我放在后面跟GLDS一起封装在统一接口里。2.2 GLCM的坑灰度级压缩与矩阵对称化GLCM有一个非常关键的细节灰度级L的选择。直接用256级灰度计算GLCM是256×256的矩阵计算量大且矩阵稀疏很多统计量不稳定。工程上通常先把图像压缩到16级或32级灰度再计算GLCM。这不仅仅是计算量的考虑更重要的原因是灰度级太多时像素对计数分散特征值对噪声过于敏感压缩后特征更加稳健。另一个坑是GLCM的方向性问题。单个方向的GLCM只能反映该方向的纹理特性通常会计算四个方向后取平均值或分别作为特征。对于旋转不变的纹理分析需求四个方向取平均是最简单的处理方式。MATLAB的graycomatrix默认也是计算一个GLCM但可以通过Offsets参数指定多个方向。还要注意对称化处理。有些实现只统计“前向”像素对这样得到的是非对称矩阵。在计算相关性等特征时非对称矩阵和对称矩阵的结果会有差异。通常的做法是把GLCM与其转置相加得到一个对称矩阵再归一化。我自己的习惯是始终使用对称化的版本因为纹理的方向特性已经在四个方向的独立计算中体现了对称化可以消除起点选择带来的偏差。2.3 GLDS灰度梯度共生矩阵边缘增强的纹理描述GLDS的构建思路和GLCM类似但它统计的是灰度与梯度的联合分布。每个像素有两个属性灰度值f(i,j)和梯度值g(i,j)。梯度值可以反映该点的边缘强度所以GLDS天然更关注纹理的边缘信息。梯度图的计算通常用Sobel算子或Canny算子。这里我选择Sobel因为它是线性的梯度幅值和方向可以直接数值计算。function glds computeGLDS(img, Lf, Lg) % Lf: 灰度级数通常取16 % Lg: 梯度级数通常取16或32 % 用Sobel算子计算梯度幅值 [gx, gy] gradient(double(img)); gradMag sqrt(gx.^2 gy.^2); % 灰度归一化到[0, Lf-1]梯度归一化到[0, Lg-1] imgNorm round(double(img) / 255 * (Lf-1)) 1; gradNorm round(gradMag / max(gradMag(:)) * (Lg-1)) 1; glds zeros(Lf, Lg); [rows, cols] size(img); for i 1:rows for j 1:cols glds(imgNorm(i,j), gradNorm(i,j)) ... glds(imgNorm(i,j), gradNorm(i,j)) 1; end end glds glds / sum(glds(:)); end基于GLDS可以提取的特征有15个小梯度优势、大梯度优势、灰度分布不均匀性、梯度分布不均匀性、能量、灰度均值、梯度均值等。实际应用中我常取前6个几乎不需要做特征选择就能直接用于分类。GLDS的优点是能同时捕捉灰度信息和边缘信息对灰度变化平缓但边缘丰富的纹理非常有效。缺点是对梯度计算参数敏感Sobel算子窗口大小和梯度归一化方式都会影响特征值。所以同一批实验里务必要固定梯度算法和归一化参数。3. LBP 与 GMRF从局部二值模式到随机场模型3.1 LBP局部二值模式明亮、快速且光照鲁棒LBP的核心思想极其简洁对每个像素取其3×3邻域内的8个像素与中心像素比较大小大于等于中心像素记为1否则记为0这样就得到一个8位二进制数转换成十进制即该像素的LBP值。这个值可以看作该点的局部纹理编码。function lbpImg computeLBP(img) % 原始LBP3x3邻域8个采样点 [rows, cols] size(img); lbpImg zeros(rows, cols); % 8个邻域的偏移量和对应比特位 offsets [-1 -1; -1 0; -1 1; 0 1; 1 1; 1 0; 1 -1; 0 -1]; for k 1:8 shifted zeros(rows, cols); % 图像平移 for i 1:rows for j 1:cols ni i offsets(k, 1); nj j offsets(k, 2); if ni 1 ni rows nj 1 nj cols shifted(i,j) img(ni,nj); else shifted(i,j) 0; end end end bit (shifted img) * 2^(k-1); lbpImg lbpImg bit; end end得到LBP图后再统计直方图就是特征向量。但原始LBP有256个bin维度偏高而且不同纹理的直方图可能很稀疏。因此实际项目中几乎都用改进版本最常用的是均匀模式Uniform Pattern当二进制串中0到1或1到0的跳变次数不超过2次时称为均匀模式。均匀模式把256种模式压缩到59种大大降低特征维度同时保留绝大多数纹理信息统计上通常覆盖90%以上的模式。MATLAB的图像处理工具箱确实有extractLBPFeatures函数但它返回的直方图配置固定灵活性不够。我在需要控制采样点数和半径时倾向于自己写。比如用半径为R、采样点为P的圆形邻域时需要插值采样这能更好地控制尺度适应性。圆形邻域配合旋转不变模式能让LBP特征具备旋转不变性具体做法是把二进制串循环移位后取最小值作为编码。3.2 LBP的实战心得避免边界效应LBP实现中最大的隐患是边界像素处理。我见过不少代码直接把边界置零或忽略这会导致特征图边缘出现一圈异常值在直方图统计时虽然影响比例不大但如果图像较小误差就会被放大。稳妥的做法是给图像加一圈镜像填充padarray的symmetric选项让边界像素也能正常计算。另一个心得是关于分块统计。在图像分类任务中我通常把图像分成若干个不重叠的块比如4×4每个块单独计算LBP直方图然后拼接。这样特征里既包含了纹理信息也包含了空间位置信息分类准确率通常能大幅提升。这个思路与空间金字塔匹配类似是LBP实战中的标准操作。关于采样点数默认P8、R1适合细节纹理对于粗糙纹理建议增大R比如P16、R2或P24、R3这样能捕捉更大范围的纹理单元。增大R时需要相应增加P保证空间分辨率。3.3 GMRF高斯马尔可夫随机场模型参数作为特征GMRF的基本假设是图像的每个像素灰度值可以用邻域像素的线性组合加上一个高斯噪声来建模f(i,j) sum_{(m,n) in N} θ(m,n) * f(im, jn) e(i,j)其中N是邻域集合θ是模型参数e是均值为0、方差为σ²的高斯噪声。纹理特征就是这些参数θ和噪声方差σ²。不同纹理的邻域依赖关系不同参数也不同。GMRF的参数估计通常用最小二乘法。以二阶邻域为例需要估计4个方向或8个方向的依赖系数。下面的代码实现了一个基于最小二乘的GMRF参数估计function theta estimateGMRF(img, order) % 最小二乘估计GMRF参数 % order: 模型阶数1或2对应4邻域或8邻域 img double(img); [rows, cols] size(img); % 根据阶数生成邻域偏移 if order 1 offsets [-1 0; 1 0; 0 -1; 0 1]; else offsets [-1 0; 1 0; 0 -1; 0 1; -1 -1; -1 1; 1 -1; 1 1]; end numParams size(offsets, 1); A []; % 特征矩阵 b []; % 目标向量 for i order1:rows-order for j order1:cols-order rowVec zeros(1, numParams); for k 1:numParams rowVec(k) img(ioffsets(k,1), joffsets(k,2)); end A [A; rowVec]; b [b; img(i,j)]; end end % 最小二乘解 theta (A * A) \ (A * b); end这个实现有几个值得注意的点。首先遍历像素时跳过了边界这样A矩阵行数略小于像素总数但参数估计更干净。其次邻域集合的选择要考虑对称性对于无方向性的纹理对称邻域更合理也可以把对称位置参数设为相等来减少待估参数数量。GMRF的优点在于特征维度低对纹理的刻画是用“生成规则”的方式对于具有明显周期性的纹理特别有效。缺点是它假设纹理是平稳的随机场对于局部变化剧烈的纹理效果一般。另外参数估计的计算量随邻域阶数上升较快实际应用中二阶邻域通常就够了。4. 变换类方法FD 分形维数与 Gabor 滤波器组4.1 差分盒计数法计算分形维数分形维数FD从图像表面自相似性的角度描述纹理复杂度。直观理解如果把图像灰度看作高度场那么表面越粗糙分形维数越大。差分盒计数法是计算图像FD最常用的方法在工程中我基本上只用这一种。核心思想是用不同尺寸的盒子去覆盖图像灰度表面统计覆盖所需的盒子数N(r)然后拟合log(N(r))与log(1/r)之间的线性关系斜率就是分形维数。具体实现function fd computeFD(img, boxSizes) % boxSizes: 盒子尺寸数组比如 [2 4 8 16 32 64] img double(img); [rows, cols] size(img); fd 0; logInvR zeros(length(boxSizes), 1); logNr zeros(length(boxSizes), 1); % 对每个盒子尺寸计算 for idx 1:length(boxSizes) s boxSizes(idx); Nr 0; for i 1:s:rows-s1 for j 1:s:cols-s1 block img(i:is-1, j:js-1); minVal min(block(:)); maxVal max(block(:)); % 灰度范围对应的盒子数量 n_ij ceil((maxVal - minVal 1) / s); Nr Nr n_ij; end end logNr(idx) log(Nr); logInvR(idx) log(1/s); end % 线性拟合求斜率 p polyfit(logInvR, logNr, 1); fd p(1); end实现的关键在于灰度维度的处理。图像灰度范围是0到255而盒子在空间维的尺寸是s所以覆盖灰度范围所需的“灰盒子”数量是ceil((max-min1)/s)。有些实现里不用max-min而是用整幅图的灰度范围归一化后再计算这样做对灰度偏移不敏感但对局部对比度差异的刻画会变弱。我的经验是保留局部max-min的方式因为它能更好地反映局部纹理变化。4.2 多尺度FD与多方向FD的扩展单一分形维数只用一个斜率描述整个尺度范围的自相似性会丢失大量信息。实际使用中可以分两段拟合小尺度范围s1到4拟合出“局部FD”大尺度范围s8到32拟合出“全局FD”这两个特征分别对应细节纹理和宏观结构。另外对行方向和列方向分别计算FD可以得到水平方向和垂直方向的分形特性对具有方向性的纹理特别有效。我在实际项目中发现FD对于灰度渐变平缓的地形图、岩石截面图等自然纹理效果很好而对人工规则纹理反而区分度不高。这是因为人工纹理的灰度表面并不满足自相似性假设。所以在选型时要注意这一点不能一上来就无脑用FD。4.3 Gabor滤波器组的参数设计与实现Gabor滤波器本质上是正弦平面波乘以高斯包络能够在频域上同时定位方向和尺度。一组不同方向和尺度的Gabor滤波器形成一个滤波器组对图像滤波后每个像素就得到一个高维响应向量这些响应的统计值可以作为纹理特征。设计Gabor滤波器组时方向数通常取6或8个尺度取3到5个。方向数太少方向分辨率不够尺度数太少无法覆盖不同粗细的纹理。一个经典的配置是5个尺度、8个方向共40个滤波器。每个滤波器的数学表达式为g(x,y) exp(-(x^2 γ²y^2) / (2σ²)) * cos(2πf x)其中x和y是旋转后的坐标f是正弦波的频率σ是高斯包络的标准差γ是空间纵横比。频率通常按等比数列取值从较高频到较低频递减。function [gaborBank, responses] buildGaborBank(img, numScales, numOrientations) % 构建Gabor滤波器组并对图像滤波 [rows, cols] size(img); img double(img); gaborBank cell(numScales, numOrientations); responses cell(numScales, numOrientations); % 频率范围高频到低频 minWave 2; maxWave min(rows, cols) / 4; waves logspace(log10(minWave), log10(maxWave), numScales); for s 1:numScales frequency 1 / waves(s); for o 1:numOrientations theta (o-1) * pi / numOrientations; gaborBank{s, o} gaborFilter(frequency, theta, 0.5, 0.5); responses{s, o} imfilter(img, gaborBank{s, o}, replicate); end end end function gb gaborFilter(frequency, theta, sigma, gamma) % 生成单个Gabor滤波器 sigma sigma / frequency; sizeKernel ceil(3 * sigma); [x, y] meshgrid(-sizeKernel:sizeKernel, -sizeKernel:sizeKernel); xr x * cos(theta) y * sin(theta); yr -x * sin(theta) y * cos(theta); gb exp(-(xr.^2 gamma^2 * yr.^2) / (2*sigma^2)) .* cos(2*pi*frequency*xr); gb gb - mean(gb(:)); gb gb / norm(gb(:)); end4.4 Gabor特征提取的实操经验Gabor滤波后的响应值通常是零均值的直接用绝对值或平方值做统计更合理。我通常对每个滤波响应图计算均值、标准差和能量。这样每个滤波器产生3个特征40个滤波器共120个特征。如果觉得维度太高可以只取均值和标准差共80维。一个关键参数是σ的选择。σ决定高斯包络的宽度直接影响滤波器的频率选择性。σ太大滤波器对频率不敏感方向选择性也变差σ太小滤波器有效窗口太小对低频信息无法覆盖。我一般把σ设为一个与频率成反比的值保证不同频率下滤波器的时域支撑大致相同这也是上面代码里用sigma sigma / frequency的原因。另外Gabor滤波器组生成后建议可视化检查一下滤波器频谱覆盖情况确保方向均匀分布、频率没有重叠空隙。这一步虽然简单但能避免方向数设置不合理导致某些角度纹理完全未被响应的问题。5. 六种方法的统一封装与特征向量组合5.1 统一的特征提取接口设计实际项目中不太可能只用一种方法更常见的是把几种方法组合起来形成综合特征向量。为了方便切换和组合我建议把所有方法封装到一个统一的函数接口里。这个设计参考了常见的“特征工厂”模式但对MATLAB来说不需要过度设计一个结构体参数加switch分支就足够了。function featureVector extractTextureFeatures(img, method, params) % 统一纹理特征提取接口 % method: GLCM, GLDS, LBP, GMRF, FD, Gabor if size(img, 3) 3 img rgb2gray(img); end switch upper(method) case GLCM featureVector extractGLCMFeatures(img, params); case GLDS featureVector extractGLDSFeatures(img, params); case LBP featureVector extractLBPFeatures_self(img, params); case GMRF featureVector estimateGMRF(img, params.order); case FD featureVector computeFD(img, params.boxSizes); case GABOR [~, responses] buildGaborBank(img, params.scales, params.orientations); featureVector extractGaborStats(responses); otherwise error(未知的特征方法); end end每个方法的具体特征计算函数内部实现已经在前面分别给出了。这样设计的好处是在后续的交叉验证、特征选择、分类器训练环节代码可以完全复用只需要切换method名称即可。5.2 特征向量的标准化与融合策略不同方法得到的特征取值范围差异很大。GLCM的能量在0到1之间Gabor响应均值可能高达几百GMRF参数可能是负值如果不做标准化直接拼接到一起数值范围大的特征会在距离计算中占绝对主导小数值特征几乎被淹没。我通常使用z-score标准化把每个特征维度的均值和标准差计算出来后统一变换到零均值单位方差function featNorm zscoreFeatures(featMatrix) mu mean(featMatrix, 1); sigma std(featMatrix, 0, 1); % 防止除零 sigma(sigma 0) 1; featNorm (featMatrix - mu) ./ sigma; end特征融合时一定要记录每一段特征在总向量中的起始位置和结束位置。这样在后续做特征重要性分析或消融实验时才能知道是哪个方法的哪个特征对分类结果贡献最大。这个习惯帮我解决过不少模型调优的难题。5.3 代码性能优化向量化替代循环MATLAB中最大的性能杀手就是循环。我前面为了讲清楚原理给出了循环实现但在实际批量处理时需要改用向量化写法。以LBP为例可以用像素平移操作一次性完成8个邻域的差分计算速度可以提升几十倍function lbpImg computeLBPFast(img) img double(img); [rows, cols] size(img); % 对称填充 imgPad padarray(img, [1 1], symmetric); lbpImg zeros(rows, cols); offsets [-1 -1; -1 0; -1 1; 0 1; 1 1; 1 0; 1 -1; 0 -1]; for k 1:8 rOff offsets(k,1) 1; cOff offsets(k,2) 1; shifted imgPad((1:rows)rOff, (1:cols)cOff); lbpImg lbpImg (shifted img) * 2^(k-1); end end这里用padarray的symmetric做镜像填充替代边界判断用矩阵切片替代遍历代码更简洁、运算更快。在几千张图像上做批量处理时这类优化非常值得做。6. 参数调优、常见问题与排查技巧6.1 关键参数速查表这里列一个我多次调参后的经验值表适合大多数图像纹理分析场景可以直接作为初始参数使用方法参数推荐值备注GLCM灰度级L16~32过大稀疏过小丢失信息GLCM距离d1~3先试1效果不佳再增大GLCM方向θ0,45,90,135四个方向取平均GLDS灰度级Lf16与GLCM一致GLDS梯度级Lg16梯度归一化方式须固定LBP采样点数P8~24随半径增大而增大LBP半径R1~3纹理粗糙时加大GMRF邻域阶数2四方向或八方向FD盒子尺寸范围[2 4 8 16 32 64]覆盖图像尺寸的1/64到1/2Gabor尺度数4~5高频到低频等比分布Gabor方向数6~8均匀覆盖0~π这些参数不是死标准而是起点。对于纹理单元较大或较小的图像需要结合实际可视化效果调整。6.2 常见问题与解决方案第一个高频问题是计算结果出现NaN。GMRF参数估计时如果A A矩阵接近奇异最小二乘解会不稳定。解决办法是加入正则化项或者检查图像是否包含大面积的均匀区域——均匀区域中邻域像素与中心像素高度相关导致矩阵奇异。另外GLCM和GLDS归一化时如果所有像素都一样归一化也会出问题需要做除零保护。第二个问题是特征区分度不高。常见原因不是算法本身而是灰度预处理没做好。光照不均匀时建议先做直方图均衡化或高斯差分预处理噪声较重时建议先用中值滤波去噪再提取特征。我在做纹理分类实验时经常发现预处理的影响比特征选择还大。第三个问题是提取速度太慢。批量处理时优先考虑向量化然后考虑并行化。MATLAB的parfor可以在多个图像之间并行提取特征前提是每次迭代之间没有数据依赖。另外GLCM的灰度级从256降到16后速度提升可达数十倍这是最直接有效的优化手段。第四个问题是我多次踩过的坑特征向量维度不一致。比如Gabor滤波器的方向数改了特征维度就变了LBP模式数从256变成59维度也变了。特征维度一变后面训练好的分类器全部要重来。所以实验一开始就要冻结特征配置任何参数调整都记录在日志里。6.3 方法的组合策略与实战建议单种方法的特征往往不够全面但也不是方法越多越好。特征维度太高会带来维度灾难分类器训练慢且容易过拟合。我常用的策略是“两个方法打底一个方法增强”GLCM加LBP作为基础特征覆盖统计和局部结构信息如果效果不够再叠加Gabor或GMRF作为增强特征。在分类器选择上纹理特征向量通常维度不高线性SVM或随机森林都能取得不错效果。如果用的是深度学习特征做对照实验纹理特征依然是很好的baseline。我在一个布料瑕疵检测项目中用GLCMLBP的组合特征配合线性SVM在4000张图像上达到了96%的准确率训练时间不到1分钟这个性价比是深度学习方案很难比拟的。在实际项目中我强烈建议把前面封装的extractTextureFeatures函数配合交叉验证框架一起使用。每换一种特征方法或一组参数就重新跑一遍交叉验证用分类准确率来客观评估特征的有效性。这样做虽然每一轮实验要多花一点时间但能避免“感觉某个特征好像有效”的主观误判。我见过太多人在调参上凭感觉结果浪费了大量时间。六种方法中如果时间有限只能掌握三种我会优先推荐GLCM、LBP和Gabor。GLCM是纹理特征的经典代表几乎所有纹理相关的论文都会用到理解它对于读懂文献至关重要。LBP是工程落地最实用的方法计算快、效果稳、可解释性强。Gabor则提供了频率和方向的精细刻画能力在三者中理论性最强。把这三个吃透再回头学GLDS、GMRF和FD会觉得轻松很多。最后再分享一个我在实际使用中的小技巧特征提取完之后先别急着训练分类器花一两分钟把特征做一下可视化。用gscatter或tsne看看不同类别的样本在特征空间中是否可分比直接闷头跑分类器高效得多。如果特征可视化下类别重叠严重不管你怎么调分类器参数效果都不会好到哪里去。这个习惯帮我过滤掉了大量无效的特征组合也让我在项目汇报时能拿出直观有力的证据。本文还有配套的精品资源点击获取