
简介本资源是一套面向图像处理研究者与MATLAB初学者的纹理特征提取实践代码集聚焦于计算机视觉中纹理建模与分类的核心任务。涵盖灰度共生矩阵GLCM、灰度差分统计GLDS、局部二值模式LBP、广义马尔可夫随机场GMRF、分形盒维数FD及Gabor滤波器六类主流方法每种均提供完整、可直接运行的MATLAB函数实现含清晰注释与典型调用示例便于理解原理、调试参数及集成至实际项目。压缩包为RAR格式共包含多个.m源文件如glcm_features.m、lbp_hist.m、gabor_filterbank.m等总大小255KB结构简洁无冗余依赖适合快速上手与二次开发。已有3558人学习下载是开展纹理分析算法对比、课程实验设计或科研基线复现的高实用性工具包。 做图像算法这些年纹理特征提取几乎是绕不开的一道坎。不管是做遥感影像分类、医学图像分析还是工业表面缺陷检测纹理特征都是最能反映图像本质信息的线索之一。今天把我在MATLAB里常用的六种纹理特征提取方法一次性整理出来分别是GLCM灰度共生矩阵、GLDS灰度差分统计、LBP局部二值模式、GMRF高斯马尔可夫随机场、FD分形维数和Gabor变换附上可直接运行的代码和我在实际项目中踩过的坑。这六个方法基本覆盖了统计纹理、模型纹理、频谱纹理三大类适合做图像分类、检索、分割任务的开发者参考也适合刚入门图像处理的研究生快速上手。1. 六种纹理特征方法选型与互补逻辑1.1 纹理特征的本质是什么在深入代码之前先理清一个概念纹理特征到底在描述什么。简单说纹理是图像局部区域内像素灰度值在空间上重复排列形成的模式。不同材质的物体表面比如木材纹理、布料纹理、细胞组织切片在灰度分布规律上会有明显的差异化表现。纹理特征提取的核心任务就是把这个灰度分布规律转化为一组数值向量让计算机能够量化比较。这六种方法分别从不同角度刻画纹理GLCM和GLDS从灰度空间依赖关系入手属于统计分析方法LBP从局部邻域的二值编码模式入手抗光照干扰能力强GMRF从随机过程建模的角度入手用模型参数描述纹理FD从分形几何的自相似性入手衡量纹理的粗糙度和复杂度Gabor从频域和方向选择性入手模拟人类视觉系统的多通道感知特性我在实际项目中通常不会只用单一方法而是根据任务需要选择2到3种组合使用。比如做织物疵点检测时GLCM加Gabor的组合效果就比单独用任何一种都好。1.2 六种方法的优缺点与适用场景对比这六个方法各有脾气没有哪个是万能钥匙。我整理了一个对比表方便大家根据实际场景做选型方法原理类别主要优点主要缺点典型应用场景GLCM统计特征维度可控、对纹理周期敏感计算量大、方向敏感遥感图像分类、医学图像分析GLDS统计计算量小、实现简单只考虑差分统计信息量有限快速纹理筛选、在线检测LBP统计/结构灰度不变性好、计算高效对噪声敏感、尺度信息缺失人脸识别、细胞图像分类GMRF模型参数物理意义明确、适合纹理合成模型阶数难定、计算复杂纹理分割、图像恢复FD几何对尺度变化不敏感、描述粗糙度准确对方向性纹理描述弱材料分析、形貌表征Gabor频谱多尺度多方向、逼近人眼感知特征维数大、冗余度高指纹识别、缺陷检测从我的经验来看如果项目周期紧、需要快速出效果优先考虑GLCM加LBP如果是学术研究追求精度GLCM加Gabor加GMRF的配置会更完整。2. MATLAB环境准备与图像预处理细节2.1 工具箱依赖确认写代码之前先把环境确认好避免运行到一半报错。上面六个方法中GLCM可以直接用Image Processing Toolbox里的graycomatrix和graycoprops函数Gabor变换可以用Image Processing Toolbox自带的imgaborfilt也可以用小波工具箱里的gaborfilter。其他几个方法GLDS、LBP、GMRF、FD在MATLAB基础版中就能实现只需要有基本的矩阵运算能力。所以理论上只要你的MATLAB装了Image Processing Toolbox全套代码就能跑通。检查工具箱是否安装在命令窗口运行% 检查工具箱是否可用 license(test, image_toolbox)返回1就说明Image Processing Toolbox可用。如果是0需要先安装工具箱或者改用自己实现的GLCM代码。2.2 输入图像的标准预处理流程纹理特征提取对输入图像的质量要求比较高预处理做不好后面提取的特征就不稳定。我总结了一套标准预处理流程% 读取并预处理图像 img imread(texture_sample.jpg); if size(img, 3) 3 grayImg rgb2gray(img); % 彩色图转灰度 else grayImg img; end grayImg im2double(grayImg); % 转double类型便于计算 % 可选直方图均衡化增强对比度 grayImg histeq(grayImg); % 可选去除噪声 grayImg imgaussfilt(grayImg, 1); % 高斯滤波sigma1这里有几个细节要特别注意。第一如果原始图像是彩色图一定要先转灰度否则GLCM的灰度级统计会出错。第二建议统一转为double类型因为后续很多运算包括差分、矩计算、滤波对uint8和double的处理逻辑不一样混用容易得到错误结果。第三直方图均衡化是否使用取决于任务如果特征是用于分类模型均衡化通常能提升稳定性但如果是做纹理清晰度评估均衡化反而会抹掉一些细微差异。还有一个容易忽略的问题是灰度级压缩。如果图像是16位深度直接计算GLCM会导致共生矩阵巨大计算效率极低。通常需要先把灰度级压缩到8位或者16级、32级。这个在GLCM部分我会重点说明。3. 六种纹理特征方法的原理与MATLAB实现3.1 GLCM灰度共生矩阵统计纹理的实际主力GLCM的原理是统计图像中满足特定空间位置关系的两个像素灰度值对出现的频次。比如水平方向、距离为1的共生矩阵统计的就是每个像素与其右侧相邻像素的灰度组合情况。MATLAB直接调用实现如下function glcmFeatures extractGLCM(grayImg) % 输入grayImg - 灰度图像矩阵取值0-255 % 输出glcmFeatures - 包含对比度、相关性、能量、同质性等 % 压缩灰度级到8级减少计算量 levels 8; grayQ round(grayImg * (levels - 1)); % 计算四个方向的共现矩阵 offsets [0 1; -1 1; -1 0; -1 -1]; % 0度、45度、90度、135度 glcms graycomatrix(grayQ, NumLevels, levels, Offset, offsets, Symmetric, true); % 提取统计特征 stats graycoprops(glcms, {Contrast, Correlation, Energy, Homogeneity}); % 组装特征向量 glcmFeatures [stats.Contrast, stats.Correlation, stats.Energy, stats.Homogeneity]; end这里我用了Symmetric参数设为true表示矩阵对称化把方向信息合并这样特征对旋转的敏感度会降低。如果任务本身需要区分方向比如检测横向纹理和纵向纹理的差异就不应该对称化而是分别提取每个方向的特征。自己实现GLCM的代码也不复杂核心逻辑如下function glcm computeGLCM(grayImg, offset) % 手动实现GLCM [rows, cols] size(grayImg); maxLevel max(grayImg(:)) 1; glcm zeros(maxLevel, maxLevel); dx offset(2); dy offset(1); for i 1:rows for j 1:cols ni i dy; nj j dx; if ni 1 ni rows nj 1 nj cols glcm(grayImg(i,j) 1, grayImg(ni,nj) 1) ... glcm(grayImg(i,j) 1, grayImg(ni,nj) 1) 1; end end end glcm glcm / sum(glcm(:)); % 归一化 end手动实现的价值在于你可以灵活改造比如修改偏移量为(2, 1)去捕捉更长的纹理周期。我一般在研究新方法时会先手写一遍彻底理解原理后再用官方函数提速。3.2 GLDS灰度差分统计快速高效的小个头GLDS的思路比GLCM简单直接它统计的是图像中相距一定距离的两个像素灰度差的分布情况。如果图像纹理粗糙灰度差整体偏大如果纹理细腻灰度差普遍偏小。灰度差直方图的均值、对比度、角度二阶矩、熵等统计量就构成了特征向量。function gldsFeatures extractGLDS(grayImg) % 输入grayImg - double类型的灰度图像 % 输出gldsFeatures - 灰度差分统计特征 [rows, cols] size(grayImg); d 1; % 差分距离 % 计算水平和垂直方向的差分 diffH zeros(rows, cols-d); for i 1:rows for j 1:cols-d diffH(i,j) abs(grayImg(i,j) - grayImg(i,jd)); end end diffV zeros(rows-d, cols); for i 1:rows-d for j 1:cols diffV(i,j) abs(grayImg(i,j) - grayImg(id,j)); end end % 合并差分结果并量化 diffAll [diffH(:); diffV(:)]; diffQ round(diffAll * 255); % 映射到0-255 % 计算直方图 histogram histcounts(diffQ, 0:256) / length(diffQ); % 提取统计特征 meanVal mean(diffQ); contrastVal sum(histogram.^2); entropyVal -sum(histogram .* log(histogram 1e-10)); gldsFeatures [meanVal, contrastVal, entropyVal]; end这段代码用双重循环实现思路清晰但效率一般。实际工程中可以用矩阵运算替代循环diffH abs(grayImg(:, 1:end-d) - grayImg(:, 1d:end)); diffV abs(grayImg(1:end-d, :) - grayImg(1d:end, :));两行代码搞定速度能提升一个数量级。在写MATLAB代码时向量化思维非常重要后面对GMRF和LBP的实现也会采用这种思路。GLDS的缺点在于它只考虑了灰度差的一阶统计量丢失了空间排列信息。所以它更适合作为快速筛选特征或者跟其他特征拼接使用。我自己在做线上实时检测时经常用GLDS做第一道粗筛快速排除掉大量明显不合格的样本。3.3 LBP局部二值模式光照不变的局部纹理描述LBP的核心思想很巧妙对每个像素以它为中心取一个半径R的圆圆上有P个采样点将中心像素灰度值与各采样点灰度值比较大于等于记1小于记0得到一个P位的二进制数这个二进制数就是该像素的LBP编码。function lbpHist extractLBP(grayImg) % 输入grayImg - double类型灰度图像 % 输出lbpHist - 256维LBP直方图 [rows, cols] size(grayImg); lbpImg zeros(rows, cols); % 使用3x3邻域8个采样点 for i 2:rows-1 for j 2:cols-1 center grayImg(i, j); code 0; % 按顺时针顺序比较8个邻域像素 neighbors [grayImg(i-1, j-1), grayImg(i-1, j), grayImg(i-1, j1), ... grayImg(i, j1), grayImg(i1, j1), grayImg(i1, j), ... grayImg(i1, j-1), grayImg(i, j-1)]; for k 1:8 if neighbors(k) center code code 2^(k-1); end end lbpImg(i, j) code; end end % 统计直方图 lbpHist histcounts(lbpImg, 0:256) / ((rows-2)*(cols-2)); end但这个基础版的LBP对噪声比较敏感而且8邻域只有256种模式模式太多不好统计。实际项目中我常用的是Uniform LBP只统计跳变次数不超过2的模式其余归为一类这样直方图维度从256降到59特征更鲁棒。Uniform LBP的实现function lbpUniformHist extractLBPUniform(grayImg) % 计算Uniform LBP特征 % 判断一个二进制串是否uniform循环相邻位之间跳变次数2 [rows, cols] size(grayImg); lbpImg zeros(rows, cols); for i 2:rows-1 for j 2:cols-1 center grayImg(i, j); neighbors [grayImg(i-1, j-1), grayImg(i-1, j), grayImg(i-1, j1), ... grayImg(i, j1), grayImg(i1, j1), grayImg(i1, j), ... grayImg(i1, j-1), grayImg(i, j-1)]; code 0; for k 1:8 if neighbors(k) center code code 2^(k-1); end end lbpImg(i, j) code; end end % 构建映射表 mapping zeros(1, 256); label 1; for code 0:255 binStr dec2bin(code, 8) - 0; transitions sum(binStr ~ circshift(binStr, 1)); if transitions 2 mapping(code 1) label; label label 1; end end % 映射并统计直方图 lbpMapped mapping(lbpImg 1); lbpUniformHist histcounts(lbpMapped, 1:(label1)) / ((rows-2)*(cols-2)); endLBP最让我喜欢的一点是灰度不变性。在光照变化大的场景下比如室外拍照识别、不同时间段的监控画面GLCM的特征值会漂移但LBP因为只做相对比较受光照影响很小。提取完图像的LBP特征后常见做法是先把图像分块比如分成4x4的网格对每个子块分别提取LBP直方图然后拼接起来这样能保留一定的空间位置信息。这个技巧在纹理分类中非常实用。3.4 GMRF高斯马尔可夫随机场模型参数化的纹理描述GMRF和前面的统计方法思路完全不同它假设图像纹理是一个高斯马尔可夫随机场某个像素点的灰度值可以通过其邻域像素的灰度值线性组合再加上一个高斯噪声来预测。模型参数就是纹理特征。GMRF模型可以写成f(s) sum_{r in N} theta(r) * f(sr) e(s)其中N是邻域系统theta是模型参数e是高斯噪声。参数theta表达了像素之间的空间依赖关系不同纹理的依赖模式不同参数值也就不同。我用最小二乘法估计GMRF参数的代码如下function gmrfParams extractGMRF(grayImg) % 输入grayImg - double类型灰度图像 % 输出gmrfParams - GMRF模型参数 img grayImg; [rows, cols] size(img); % 定义五阶邻域系统上、下、左、右、两个对角 % 这里使用二阶邻域即4个邻域像素 offsets [0 1; 0 -1; 1 0; -1 0]; % 下、上、右、左 numPts rows * cols; X zeros(numPts, length(offsets)); y zeros(numPts, 1); idx 1; for i 2:rows-1 for j 2:cols-1 y(idx) img(i, j); for k 1:length(offsets) X(idx, k) img(i offsets(k, 1), j offsets(k, 2)); end idx idx 1; end end % 截断多余行 X X(1:idx-1, :); y y(1:idx-1); % 最小二乘估计theta (XX)^(-1) Xy theta (X * X) \ (X * y); % 计算残差方差 residual y - X * theta; sigmaSq residual * residual / length(y); gmrfParams [theta, sigmaSq]; endGMRF的邻域阶数和方向选择对效果影响很大。一阶邻域只考虑上下左右四个点二阶邻域再加上对角方向三阶邻域范围更大。我建议根据图像的纹理尺度来选择阶数纹理颗粒细腻的用一阶就够纹理粗大的需要到三阶以上。不过GMRF有个明显的短板就是计算量大。代码中的双重循环加矩阵求逆在图像较大时非常耗时。我的建议是先用分块处理降低图像尺寸或者只在关键区域提取参数。在医学图像分析中我通常把图像裁剪成64x64的小块再提取GMRF参数特征值稳定且速度可接受。3.5 FD分形维数用分数维度度量纹理粗糙度分形维数的物理意义比较直观一条曲线在平面上弯曲缠绕得越复杂它的分形维数就越接近2越平直就越接近1。图像可以理解为一个三维空间中的粗糙曲面灰度值就是第三维的高度越粗糙的纹理表面其分形维数越大。常用的估计方法是差分盒计数法思路是用不同尺度的盒子去覆盖这个曲面统计覆盖所需的盒子数然后在双对数坐标下拟合直线斜率就是分形维数。function fd extractFD(grayImg) % 输入grayImg - double类型灰度图像建议尺寸为2的幂次 % 输出fd - 分形维数 [rows, cols] size(grayImg); % 将图像缩放为正方形尺寸为2的幂次 L 2^floor(log2(min(rows, cols))); img imresize(grayImg, [L, L]); % 实际使用对数计算避免过大的图像尺寸带来的计算压力 Nr 16; % 灰度级层数 scales 2.^(1:log2(L)); % 盒子尺度 counts zeros(size(scales)); for k 1:length(scales) s scales(k); numBoxes L / s; count 0; % 遍历每个盒子块 for i 1:numBoxes for j 1:numBoxes % 取当前块 block img((i-1)*s1 : i*s, (j-1)*s1 : j*s); minVal min(block(:)); maxVal max(block(:)); % 盒子数 count count ceil((maxVal - minVal 1) / (Nr / L * s)); end end counts(k) count; end % 拟合直线求斜率 logScales log(1 ./ scales); logCounts log(counts); p polyfit(logScales, logCounts, 1); fd p(1); % 斜率即为分形维数 end差分盒计数法有几个容易出错的地方。第一图像尺寸最好规范化为2的幂次这样盒子才能完整覆盖。第二灰度级的划分要跟盒子尺度联动如果固定灰度级数Nr那么每个盒子的实际尺寸对应的灰度跨度应该是Nr/L*s这个关系不能弄错。第三拟合时去掉最小尺度噪声影响大和最大尺度边界效应明显的点得到的斜率更稳定。纹理越粗糙分形维数越大。木板纹理的分形维数通常在2.3到2.5之间而光滑陶瓷表面可能在2.1左右。这个特征数值范围固定、物理意义明确很适合做多特征融合时的一个稳定锚点。3.6 Gabor变换多尺度多方向的频域纹理描述Gabor滤波器本质上是加了高斯窗口的傅里叶变换能够在频域的指定位置、指定方向上提取局部频带的信息。它的频率和方向选择性非常接近人类视觉皮层的感受野特性所以在指纹识别、织物检测、医学影像分析里用得非常多。MATLAB里直接调用imgaborfilt最省事function gaborFeatures extractGabor(grayImg) % 输入grayImg - double类型灰度图像 % 输出gaborFeatures - 多尺度多方向的Gabor特征 % 定义多个波长和方向 wavelengths [4, 8, 16]; % 像素周期 orientations [0, 45, 90, 135]; % 角度 features []; for w 1:length(wavelengths) for o 1:length(orientations) g gabor(wavelengths(w), orientations(o)); [mag, ~] imgaborfilt(grayImg, g); % 提取响应的均值和标准差作为特征 features [features, mean(mag(:)), std(mag(:))]; end end gaborFeatures features; end如果是老版本MATLAB没有imgaborfilt可以用gaborfilter配合conv2自己实现function gaborFiltered applyGabor(grayImg, wavelength, orientation) % 手动构造Gabor核并滤波 sigma wavelength; % 高斯包络的标准差 theta orientation * pi / 180; [x, y] meshgrid(-sigma*3:sigma*3, -sigma*3:sigma*3); xr x * cos(theta) y * sin(theta); yr -x * sin(theta) y * cos(theta); % Gabor核 高斯函数 * 复正弦函数 gaborKernel exp(-(xr.^2 yr.^2) / (2 * sigma^2)) .* cos(2*pi*xr / wavelength); gaborKernel gaborKernel - mean(gaborKernel(:)); % 去除直流分量 gaborFiltered conv2(grayImg, gaborKernel, same); endGabor特征最大的问题是维数爆炸。比如上面用3个波长和4个方向每个滤波器提取2个统计量总共就是24维。如果波长取8个、方向取6个特征维度立刻跳到96维。实际使用中需要结合特征选择方法比如PCA降维或ReliefF特征选择选出真正有效的维度。波长参数的选择也很有讲究。波长太小滤波器主要响应噪声和细节波长太大会丢失局部纹理差异。我一般根据图像中纹理颗粒的尺寸来定波长取纹理周期的一半作为最小波长纹理周期的2到3倍作为最大波长。4. 完整流程封装与特征融合实战4.1 统一接口的纹理特征提取函数前面各个方法都是独立函数实际应用中需要把它们封装成统一的接口方便批量处理样本。我习惯写一个主函数输入图像路径和需要的特征类型输出拼接后的特征向量function features extractTextureFeatures(imagePath, methodList) % 统一纹理特征提取接口 % methodList 示例{glcm, lbp, gabor} img imread(imagePath); if size(img, 3) 3 grayImg rgb2gray(img); else grayImg img; end grayImg im2double(grayImg); features []; if any(strcmp(methodList, glcm)) f extractGLCM(grayImg); features [features, f]; end if any(strcmp(methodList, glds)) f extractGLDS(grayImg); features [features, f]; end if any(strcmp(methodList, lbp)) f extractLBPUniform(grayImg); features [features, f]; end if any(strcmp(methodList, gmrf)) f extractGMRF(grayImg); features [features, f]; end if any(strcmp(methodList, fd)) f extractFD(grayImg); features [features, f]; end if any(strcmp(methodList, gabor)) f extractGabor(grayImg); features [features, f]; end features features(:); % 确保是行向量 end这样封装之后批量处理图片就非常简单了。读入一个文件夹下的所有图片分别提取特征存成特征矩阵后续可以直接喂给SVM、随机森林或者神经网络分类器。4.2 特征向量归一化与降维的必要性直接拼接不同方法的特征有一个隐藏问题量纲不一致。比如GLCM的对比度值范围可能是0到几百而LBP直方图的每个元素范围是0到1GMRF的参数可能集中在0.1到0.5。如果不做归一化量纲大的特征会在距离计算中占据主导地位量纲小的特征等于白算。归一化我推荐Z-score方式% 假设featuresMat是N x D的特征矩阵N个样本D维特征 mu mean(featuresMat, 1); sigma std(featuresMat, 0, 1); sigma(sigma 0) 1; % 防止除零 featuresNorm (featuresMat - mu) ./ sigma;这里有个细节计算均值和标准差应该在训练集上计算然后同样的参数应用到测试集上避免测试集信息泄露到训练过程中。很多初学者在特征处理环节容易忽略这一点直接在整个数据集上做归一化会导致模型评估结果虚高。特征降维也是生产环境中的必经步骤。Gabor和GLCM组合起来可能上百维如果样本量只有几十个分类器很容易过拟合。我通常先用PCA看累计贡献率保留95%以上能量的主成分再用交叉验证评估降维后的分类准确率。5. 常见问题与参数调优实录5.1 典型问题速查表问题现象可能原因解决方案GLCM计算极慢灰度级没压缩共生矩阵过大将灰度级压缩到8或16级LBP直方图全部集中在某一模式图像对比度极低或噪声过大先做直方图均衡化加大滤波器预处理Gabor特征区分度差波长和方向选择不当分析图像频谱峰值确定有效频率范围GMRF参数估计出现NaN邻域矩阵奇异或样本量不足增加最小二乘的正则项检查邻域定义的合法性分形维数始终接近2盒子尺度选择不当或图像太小调整尺度范围确保图像尺寸大于16x16不同图片的同类特征差异极大图像尺寸、灰度范围不一致统一缩放图像尺寸和灰度范围5.2 参数选择的实操心得参数调优这件事很受场景影响没有银弹但我可以分享几条能少走弯路的原则。第一无论是GLCM的灰度级还是LBP的邻域点数原则都是够用就行。8级灰度、8邻域往往就有不错的效果盲目加大参数只会让特征维数膨胀计算变慢模型泛化能力反而下降。第二多尺度信息对纹理识别非常重要。LBP可以结合多半径R1, 2, 3的直方图Gabor可以选多组波长GLCM的偏移距离也建议试[1, 2, 3]。单一尺度的特征就像只看一个距离观察纹理容易漏掉关键信息。第三方向设置要跟任务相关。面料纹理如果是经纬交叉0度、90度方向就够了如果是自然纹理比如木材、火焰方向分布相对均匀用4个方向的Gabor很合适。第四特征融合不是越多越好。我在一个遥感图像分类项目里试过六种方法全上特征是多了但分类准确率比只用GLCM加Gabor还低了两个百分点。原因是GMRF和FD的特征跟GLCM高度相关引入了冗余信息。建议先用相关性分析筛掉相关系数超过0.9的特征对。第五调试阶段务必打印特征向量的数值范围。如果发现某个特征在所有样本上几乎不变说明它对当前任务没有区分力直接删掉。这个方法看着简单却能有效控制特征维度。6. 从特征到应用的落地路径纹理特征提取不是终点后面还要接分类器或者相似度检索。以分类任务为例一个典型的完整流程是预处理、特征提取、归一化、特征选择、训练分类器、评估性能。拿SVM做分类器的话RBF核通常是首选。纹理特征向量的分布一般不是高斯分布但SVM通过核函数映射后通常能取得不错的分类效果。如果样本量大、特征维度高也可以考虑用随机森林它对特征量纲不敏感训练速度快。如果你做的是图像检索可以用特征向量的余弦距离或欧氏距离来衡量纹理相似度。这里有个小技巧LBP直方图适合用卡方距离或直方图交集距离GLCM统计量适合用欧氏距离。选对相似度度量方式检索精度能提升不少。完整的分类代码示例如下% 批量提取特征并训练SVM分类器 trainFiles dir(train/*.png); featuresMat []; labels []; for i 1:length(trainFiles) imgPath fullfile(train, trainFiles(i).name); featuresMat [featuresMat; extractTextureFeatures(imgPath, {glcm, gabor})]; labels [labels; floor((i-1) / 10)]; % 假设每10张一类 end % 训练SVM svmModel fitcecoc(featuresMat, labels, Learners, svm); % 使用Coding设计防止多分类时的类别不平衡问题 % 测试阶段同样提取特征并预测 testFeatures extractTextureFeatures(test/sample1.png, {glcm, gabor}); predictedLabel predict(svmModel, testFeatures);这里用fitcecoc而不是fitcsvm是因为它天然支持多分类。如果你只有两分类任务直接用fitcsvm就行速度会快很多。在我做过的几个项目里把GLCM、LBP、Gabor三种特征融合后进入SVM分类器纹理分类准确率基本能稳定在90%以上。如果单独用一种特征准确率往往只有75%到85%。融合的价值在这种对照中体现得非常明显。最后再分享一个小技巧纹理特征提取在调试阶段建议用一个只有两种类别的简单数据集跑通全流程确认输出特征确实有区分度之后再上完整数据集。这能帮你快速定位问题出在特征提取阶段还是分类器阶段避免在错误的方向上浪费大量时间。本文还有配套的精品资源点击获取