图像检索这个方向我前前后后做了差不多两年时间。最开始是在某高校实验室做遥感影像的快速检索课题后来又在某公司的算法团队里做电商场景的以图搜图。期间用过不少工具最顺手的反而是MATLAB——虽然工业界落地多用C或者Python但在做原型验证、特征策略对比、哪怕是给非技术同事演示检索效果的时候MATLAB的交互式环境都让我省了太多时间。如果你也正在摸索图像检索想快速把想法跑通、想看清不同特征怎么影响检索结果那这篇东西应该能帮你省不少弯路。我会把自己踩过的坑、验证过的套路、还有完整的可运行代码都交代出来。1. 图像检索到底在解决什么问题图像检索不是一个新概念。早在互联网图片还不多的时候就有大量研究在讨论怎么从数据库里找出“看起来像”的图片。到今天无论是淘宝拍照搜同款、百度识图还是手机相册按人脸聚类底层都离不开图像检索技术。按技术路线图像检索大体分两类基于文本的图像检索TBIR早期最常见的方案靠人工给图片打标签然后从标签文本里检索。问题很明显——人工标注成本高而且文字描述很难覆盖图像的丰富语义比如“一只趴在窗台上的橘猫”要怎么打标签才算完整基于内容的图像检索CBIR直接分析图像本身的视觉内容比如颜色、纹理、形状、空间布局等从图像计算出特征向量再通过向量相似度来检索。这就是我们现在聊的主体。CBIR的优点在于不需要任何人工标注完全靠图像自身的信息进行匹配。它的核心难题也从“文字怎么匹配”变成了“用什么特征来描述图像最有效”以及“怎么衡量两张图的特征相似度”。用MATLAB来做CBIR理由其实很实际。一来它的图像处理工具箱函数齐全从读图、预处理到特征提取都有现成接口不需要自己从底层像素级造轮子二来脚本化的操作方式非常适合做算法实验改一个特征参数看结果效果几秒钟就能完成一轮迭代。特别是做研究的阶段效率的重要性比运行性能更高。2. 搭建检索系统前的核心思路在写第一行代码之前先想清楚整个检索系统的框架。实际工作中我见过太多人一上来就调函数调参跑出一个貌似能用的效果但换一批图测试就崩得不像样。原因就是没理清系统结构。一个标准的CBIR系统逻辑上分成两条链路1. 入库链路离线部分对数据库里的每一张图片做特征提取把提取出来的特征向量对数据库的每张图来说是固定维度的数值数组保存下来建立索引。这个环节通常是离线的耗时无所谓关键是特征要稳定、可复现。2. 查询链路在线部分用户输入一张查询图片系统用同样的特征提取逻辑算出查询图的特征向量然后遍历数据库里存的每个特征向量计算相似度按相关度排序返回Top-K张结果。这两条链路提取特征用的必须是同一套代码和参数否则得到的特征不在同一个空间相似度计算就没有意义了。这是CBIR最容易犯的低级错误我身边就不止一个人因为查询时忘了做同样的预处理步骤导致结果全乱。选相似度度量方式之前先看一个概念——特征空间。把每张图的特征向量想象成高维空间里的一个点图像检索就是在这个空间里找与查询点“距离最近”或“夹角最小”的点。不同的度量方式在这个空间里的几何含义完全不同直接影响检索效果。常见的度量方式有以下几种度量方式适用场景含义欧氏距离连续数值特征各维度尺度相近空间直线距离L2 范数曼哈顿距离高维稀疏特征各维度差异绝对值之和余弦相似度直方图、文本向量等高维但方向敏感的特征向量夹角忽略整体幅值直方图相交距离颜色直方图统计直方图共同部分的累积占比巴氏距离直方图特征两类分布的相似程度范围 0 到 1经验之谈颜色直方图这类特征用巴氏距离或直方图相交距离的效果普遍好于欧氏距离。原因很简单直方图描述的是颜色的分布而非量级两张图颜色比例接近但总体亮度不同欧氏距离会被亮度差异带偏而巴氏距离更关注分布形状的吻合程度。3. 第一个能跑的版本颜色直方图检索早期做CBIR的人几乎都是拿颜色特征练手的。颜色特征的理解门槛最低而且对图像的缩放、旋转、平移不太敏感是一种很基础的“全球特征”。我第一个能跑通的原型就是基于HSV颜色直方图。3.1 为什么用HSV而非RGB我们日常接触的数字图像通常以RGB模式存储但RGB三个通道之间的相关性很强而且对光照变化很敏感——同一件衣服在暗处和白天的RGB数值差异可能非常大。HSV模式把颜色分解为色调Hue、饱和度Saturation、明度Value更贴近人对颜色的感知逻辑。其中H分量表示色调也就是我们说的“这图偏红、偏蓝”S表示颜色的纯度V表示明亮程度。检索时通常把H和S两个分量量化后组合成直方图V分量则可以根据实际场景决定是否保留。实验时我习惯把V分量也一起纳入因为有些场景需要区分不同亮度级别的同一色调区域。如果应用场景光照比较稳定、又想让特征更集中地表达色度信息就可以舍弃V分量只统计H和S。3.2 特征提取代码实现下面这段代码是我在原型阶段用的一套基础特征提取方案。function hist extractHSVHist(img, hBin, sBin, vBin) % 提取HSV颜色直方图特征 % 输入 % img - RGB图像矩阵 % hBin - 色调通道量化级数默认16 % sBin - 饱和度通道量化级数默认8 % vBin - 明度通道量化级数默认8 % 输出 % hist - 一维特征向量长度为 hBin*sBin*vBin if nargin 2 hBin 16; sBin 8; vBin 8; end hsvImg rgb2hsv(img); % MATLAB中HSV分量取值范围均为0~1 hBinIdx min(floor(hsvImg(:,:,1) * hBin) 1, hBin); sBinIdx min(floor(hsvImg(:,:,2) * sBin) 1, sBin); vBinIdx min(floor(hsvImg(:,:,3) * vBin) 1, vBin); % 组合三个分量形成一维索引 idx sub2ind([hBin, sBin, vBin], hBinIdx(:), sBinIdx(:), vBinIdx(:)); hist zeros(hBin * sBin * vBin, 1); for i 1:numel(idx) hist(idx(i)) hist(idx(i)) 1; end % 归一化使直方图不受图像尺寸影响 hist hist / sum(hist); end这套代码有几个细节值得注意rgb2hsv后HSV三个分量都在0到1范围内所以量化时用分量乘以级数再取整直接映射到分箱编号。sub2ind在这里用来把三维下标转换为一维索引这样后面的累积统计就简单了。归一化是必须的否则同一场景不同分辨率的图片直方图数值会按像素总数放大相似度计算就失真了。3.3 批量入库与查询检索数据库入库环节核心就是遍历目录下所有图片每张图调用特征提取函数把结果存到一个矩阵变量里。MATLAB里最方便的做法是存成.mat文件。function buildDatabase(imageDir, dbPath) % 遍历图像目录提取特征并保存到数据库文件 % 输入 % imageDir - 存放图片的文件夹路径 % dbPath - 保存的特征数据库.mat路径 imgFiles dir(fullfile(imageDir, *.jpg)); numImages length(imgFiles); featureMat zeros(numImages, 16*8*8); imgPaths cell(numImages, 1); for i 1:numImages imgPath fullfile(imageDir, imgFiles(i).name); img imread(imgPath); if size(img, 3) 1 img repmat(img, [1 1 3]); % 灰度图转伪RGB end featureMat(i, :) extractHSVHist(img); imgPaths{i} imgPath; fprintf(已处理 %d / %d\n, i, numImages); end save(dbPath, featureMat, imgPaths); end灰度图转为伪RGB这一步容易被忽视。有些图像库的图片是单通道不走RGB读入后面rgb2hsv就会报错。统一转成三通道是个省事的兜底方案。查询部分的代码大致如下function [resultPaths, scores] searchImage(featureMat, imgPaths, queryPath, topK) % 查询图像检索 % 输入 % featureMat - 数据库特征矩阵每行是一张图的特征 % imgPaths - 数据库图片路径元胞数组 % queryPath - 查询图片路径 % topK - 返回前K张结果默认10 % 输出 % resultPaths - 检索结果图片路径 % scores - 对应的相似度得分 if nargin 4 topK 10; end queryImg imread(queryPath); if size(queryImg, 3) 1 queryImg repmat(queryImg, [1 1 3]); end queryHist extractHSVHist(queryImg); % 计算巴氏距离注意dtw中d0代表完全匹配 distances zeros(size(featureMat, 1), 1); for i 1:size(featureMat, 1) distances(i) bhattacharyya(queryHist, featureMat(i, :)); end [~, sortedIdx] sort(distances, ascend); topIdx sortedIdx(1:min(topK, length(sortedIdx))); resultPaths imgPaths(topIdx); scores 1 - distances(topIdx); % 转成相似度越大越相似 end function d bhattacharyya(p, q) % 计算两个概率分布之间的巴氏距离 % p、q 需要是列向量且各自和均为1 d 1 - sum(sqrt(p .* q)); end我刻意没有用MATLAB内置的pdist2来算相似度主要是想强调自定义度量方式更灵活。实际工程中完全可以用pdist2配合合适的距离类型替代内层循环。注意巴氏距离的原始定义是d -log(BC)其中BC sum(sqrt(p*q))。这里我用的是简化版1 - BC目的只是让距离范围映射到0~1之间。如果需要更严格的概率意义建议使用原始的对数形式。4. 进阶特征让检索“看懂”纹理颜色特征能解决一部分问题但局限很明显——两件颜色相同但材质不同的衣服颜色直方图会算出几乎一样的特征草地和绿色的迷彩布颜色特征也难以区分。这时候就需要引入纹理特征。打个生活化的比方颜色特征回答的是“这张图里有什么色彩”而纹理特征回答的是“这些色彩的颗粒感、方向感、粗糙度如何”。看一个人的照片你可以靠肤色识别出脸部区域但要区分头发和毛衣的质感区别就得依赖纹理信息。4.1 灰度共生矩阵GLCM与特征统计量灰度共生矩阵是纹理特征里最经典的做法之一。核心思想是统计图像中相距一定距离、成一定角度的两像素灰度的联合分布。MATLAB里的graycomatrix和graycodisc可以直接实现function glcmFeature extractGLCMFeature(img) % 提取灰度共生矩阵的统计特征 % 输入 % img - RGB图像灰度图直接输入 % 输出 % glcmFeature - 4维特征向量 [对比度, 相关性, 能量, 同质性] if size(img, 3) 3 grayImg rgb2gray(img); else grayImg img; end % 计算0度方向、距离为1的GLCM glcm graycomatrix(grayImg, Offset, [0 1], NumLevels, 64, Symmetric, true); stats graycodisc(glcm); % graycodisc返回的是结构体包含Contrast, Correlation, Energy, Homogeneity等字段 glcmFeature [stats.Contrast, stats.Correlation, stats.Energy, stats.Homogeneity]; end单独4维的GLCM统计量信息量有限。实践中更常用的做法是把多个方向0°、45°、90°、135°的GLCM统计量拼接起来形成16维左右的特征向量或者把GLCM本身直接当作矩阵特征送入后续处理。我自己的经验是GLCM对规则纹理如砖墙、布料纹理区分度很好但对自然场景中的不规则纹理比如树叶、云层就不太给力。后者往往更依赖小波变换或Gabor滤波这类多尺度分析工具。4.2 Gabor滤波器组的应用Gabor滤波可以理解为一种能“扫描”图像特定方向和频率纹理的探针。用多个不同方向和频率的Gabor滤波器分别对图像滤波得到的响应幅值统计特征均值、方差就能组成纹理特征向量。MATLAB里写Gabor滤波器组相对简洁function gaborFeature extractGaborFeature(img, scales, orientations) % 提取Gabor纹理特征 % 输入 % img - RGB图像或灰度图 % scales - 尺度数量比如4 % orientations - 方向数量比如6 % 输出 % gaborFeature - 特征向量长度为 scales*orientations*2 if size(img, 3) 3 grayImg double(rgb2gray(img)) / 255; else grayImg double(img) / 255; end g gabor(scales, orientations); gaborMag imgaborfilt(grayImg, g); % 返回的是幅度响应 gaborFeature zeros(1, length(g) * 2); for i 1:length(g) % 对每个滤波响应统计均值和方差作为特征 gaborFeature(2*i-1) mean(gaborMag(:,:,i), all); gaborFeature(2*i) var(double(gaborMag(:,:,i)), 0, all); end endMATLAB从R2015b之后内置了gabor函数和imgaborfilt函数这极大简化了Gabor特征提取的复杂度。早年我做叶子图像分类的时候还得自己写Gabor核的公式生成函数现在一行调用就解决了。4.3 LBP局部二值模式LBP局部二值模式是另一个异常好用的纹理特征思路更直白——对图像中每个像素比较它和周围邻域像素的大小关系把比较结果编码成一个二进制数然后统计这些二进制数的分布直方图。LBP的伟大之处在于它的灰度不变性光照变化导致所有像素值整体抬升或降低时局部邻域的“大小关系”基本不变所以LBP对照明变化有很强的鲁棒性。回想之前说RGB颜色特征对光照敏感LBP的做法完全绕开了这个问题。function lbpHist extractLBPFeature(grayImg, radius, neighbors) % 提取LBP直方图特征 % 输入 % grayImg - 灰度图 % radius - 采样半径常用1或2 % neighbors - 邻域点数常用8或16 % 输出 % lbpHist - LBP直方图按模式数归一化 if nargin 3 radius 1; neighbors 8; end % 利用MATLAB的局部特征描述子接口 lbp extractLBPFeatures(grayImg, Radius, radius, NumNeighbors, neighbors, Upright, false); lbpHist lbp / sum(lbp); % 归一化 end这里直接用了Computer Vision Toolbox里的extractLBPFeatures输出的是统计直方图。如果没这个工具箱也可以自己实现不难但容易踩边界像素处理的坑。建议初学阶段先用内置函数跑通流程再研究内部实现。实际使用中LBP配合颜色特征做融合效果提升比单纯加GLCM明显得多。原因在于LBP捕获的是局部微观纹理和颜色特征形成了互补。5. 让特征更全面形状与边缘信息颜色、纹理都处理完还有一个信息维度不能丢——形状。人们对“像不像”的直觉判断很大程度取决于物体的轮廓结构。形状特征的做法有很多流派有基于轮廓的描述子如傅里叶描述子、曲率尺度空间也有基于区域的描述子如Hu矩、Zernike矩。但在图像检索的实际工程中直接在原图上做精确的形状特征提取并不讨好因为自然图像里的前景背景分割本身就很难。一个更务实的思路是边缘方向直方图EDH。它不追求对物体轮廓的精确数学描述而是统计图像中边缘像素的方向分布。比如“这张图里竖直方向的边缘很多”本质上反映了图像中高耸建筑物的存在。function edgeHist extractEdgeOrientationHistogram(img, numBins) % 提取边缘方向直方图特征 % 输入 % img - RGB图像 % numBins - 方向分箱数常用18每20度一箱 % 输出 % edgeHist - 归一化的边缘方向直方图 if nargin 2 numBins 18; end grayImg rgb2gray(img); % Canny边缘检测阈值可以自适应调整 edgeMap edge(grayImg, Canny); % 计算梯度方向和幅值 [gradMag, gradDir] imgradient(grayImg); % 只统计边缘像素的梯度方向 edgePixels find(edgeMap); dirs gradDir(edgePixels); dirs(dirs 0) dirs(dirs 0) 180; % 方向归一到0~180度无向 edgeHist histcounts(dirs, numBins, BinLimits, [0, 180]); edgeHist edgeHist / sum(edgeHist); end梯度方向取0到180度的“无向”版本是有讲究的。在形状感知里一条竖直边缘的方向究竟是“从左到右的竖边”还是“从右到左的竖边”并不重要重要的是它是不是竖边。把方向压缩到180度区间反而增强了特征的稳定性。这个特征有个明显缺点——它对背景噪声敏感。如果图像的背景纹理比较丰富边缘检测会把很多背景纹路也当成形状信息统计进来干扰真正的物体轮廓。解决办法有两个方向一是先用分割或显著性检测把前景抠出来再做边缘提取二是把边缘方向直方图和颜色、纹理特征做融合靠其他特征去弥补误判。6. 多特征融合与动态调优单一特征总有过不去的坎。颜色特征区分不了材质纹理特征区分不了大面积色块形状特征又依赖前景分割质量。解决思路很朴素把多个特征串起来构成一个更高维的特征向量。6.1 最简串行拼接法最直接的办法就是把颜色直方图特征、LBP特征、边缘方向直方图特征拼接成一个向量function combinedFeature extractCombinedFeature(img) % 多特征串行拼接 hsvHist extractHSVHist(img, 16, 8, 8); % 1024维 grayImg rgb2gray(img); lbpHist extractLBPFeature(grayImg, 1, 8); % 59维均匀模式 edgeHist extractEdgeOrientationHistogram(img); % 18维 combinedFeature [hsvHist(:); lbpHist(:); edgeHist(:)]; end简单归简单这做法有一个大坑——不同特征的数值范围不一样。HSV直方图的每个分量是归一化后的频率值LBP直方图同理但边缘方向直方图的某些分量可能很大直接拼接后会导致相似度计算被数值大的维度主导。因此拼接之前必须对每个特征子块做单独的归一化甚至可以考虑标准化减去均值除以标准差。实践中我通常对每个特征子块做L2归一化function vec l2norm(vec) n norm(vec, 2); if n 0 vec vec / n; end end把每个子块归一化到单位L2范数之后再拼接在一起相似度计算才不会被某一类特征“带节奏”。6.2 特征加权与参数选择拼接完成后还可以为每个特征子块设置权重系数。这个在工程上极其常见因为不同应用场景对不同特征维度的依赖程度不同。比如在服装检索场景颜色权重可以高一些在布料纹理检索场景纹理权重就更关键。加权的方式可以简单粗暴地乘一个常数也可以更精细地通过训练数据学习最优权重。前者适合快速验证后者适合追求检索精度的正式项目。表不同场景下的推荐权重分配经验值应用场景颜色特征权重纹理特征权重形状特征权重通用相册检索0.50.30.2服装图片检索0.60.250.15织物纹理检索0.20.70.1遥感图像检索0.40.30.3这里没有“万能答案”。最可靠的做法是自己建一个验证集跑不同的权重组合看检索准确率变化用网格搜索或随机搜索来找最优权重。6.3 降维处理与索引加速串行拼接的特征维数往往上千维这时不仅存储开销大查询时的相似度计算也非常耗时。可以入手的方向有两个——降维和索引结构。降维最常见的方法是PCA主成分分析。MATLAB里% 数据库全部特征矩阵 featureMat每行一个样本 [coeff, score, ~, ~, explained] pca(featureMat); % 保留贡献率达到95%的主成分 cumRatio cumsum(explained); nPC find(cumRatio 95, 1); featureMatReduced score(:, 1:nPC);PCA适合在数据库特征整体离线的场景下做因为需要统计全库的协方差结构。换一个视角降维也是去除冗余信息、增强特征鲁棒性的手段。检索加速方面最经典的做法是构建KD树或倒排索引。不过MATLAB自带的knnsearch己经支持KDTree搜索了可以直接用。数据库规模在几十万级别以内时暴力线性扫描加向量化计算也完全能接受因为MATLAB矩阵运算本身就比较高效。7. 真实场景效果提升的实战技巧理论讲完来说说实操中我总结的几招。7.1 预处理宁可多一步也不省图像的输入质量对检索效果影响非常大。同一个检索系统输入原始照片和输入经过归一化的照片Top-1准确率可能差20%以上。基础的预处理包括统一尺寸缩放避免直方图统计受到分辨率干扰、去噪高斯滤波或中值滤波、光照均衡直方图均衡化。我自己的习惯是在特征提取函数前统一加上尺寸缩放和转灰度按需这样无论输入什么图都能稳定得到特征。7.2 构建自己的评测集要留一手做检索系统最容易陷入“自己调参自己满意”的陷阱。务必从数据库里选出一部分图片作为查询样例人为构造相关的“标准答案”。这个标准答案怎么来简单做法是从同一场景的不同角度、不同光照条件下拍摄的照片作为相关对。如果没有办法获取多视角图也可以用另一种思路按类别文件组织图片库从每个类别随机挑一张作为查询其他同类图片作为期望结果。检索的准确率指标就用“检索结果中属于同类别图片的占比”来衡量。虽然粗暴但能反映相对变化。7.3 特征组合的动态选择不同查询图对应的最优特征组合往往不一样。举个我遇到的真实例子查询是一个纯色背景上的红色汽车颜色特征占主导但查询是一幅黑白街拍建筑颜色特征基本没有判别力这时候纹理和边缘特征才是主力。可以设计一个简单的启发式逻辑根据查询图的颜色丰富度颜色直方图的有效分箱数动态决定颜色特征对最终相似度的贡献。颜色分布越集中说明颜色信息越有代表性适当调高权重反之则调低。这种方式虽然不是最严谨的自适应方法但工程收益很高尤其适合小规模查询场景。7.4 应对大面积遮挡和裁剪真实场景里的查询图经常有物体被遮挡或包含大面积无关背景。这时候全图特征的表现力会明显下降。更稳健的方案是分块特征Block-based Feature。把图像均匀切成若干块每块提取特征然后用块与块之间的局部匹配来算全局相似度。这相当于把目光从“整张图像不像”聚焦到“局部区域能不能对上”。实现并不复杂把前面的特征提取函数改成对子图像调用即可function blockFeature extractBlockHSV(img, gridRows, gridCols) % 分块HSV直方图特征 % 将图像分成 gridRows * gridCols 块对每块提取直方图并拼接 [height, width, ~] size(img); blockFeature []; for i 1:gridRows for j 1:gridCols rStart round((i-1) * height / gridRows) 1; rEnd round(i * height / gridRows); cStart round((j-1) * width / gridCols) 1; cEnd round(j * width / gridCols); subImg img(rStart:rEnd, cStart:cEnd, :); blockFeature [blockFeature; extractHSVHist(subImg)]; end end end分块的代价是特征维度成倍增加比如把图分成3x3块后单是HSV直方图特征就是原来的9倍。所以分块之后一般配合PCA做降维或者改用更紧凑的特征类型。8. 常见问题与排查技巧实录我在代码分享、教学指导和项目迭代过程中遇到过不少反复出现的坑。整理一份速查表出来应该能帮你省不少排查时间。问题现象可能原因排查与解法检索结果全是乱序的“相似”图特征提取时忘了同一套预处理检查查询图和入库图的预处理流程是否完全一致相似度计算结果全是同一个值特征没有归一化数值差异被淹没确认每个特征子块做L2归一化后再拼接灰度图入库时总是报错单通道图像直接进rgb2hsv统一用repmat扩展为三通道颜色特征不变的场景检索很差特征维度覆盖不到的细节差异增加纹理特征或LBP特征做融合数据库大了以后查询很慢全库线性扫描耗时增长用KDTree或降维后建倒排索引有关联结果但排序不对相似度度量不适合该特征换成直方图相交距离或余弦相似度对比一下除了表格里的问题我再补充几个不容易看出来的细节。第一个是MATLAB的数据类型坑。imread读入的如果是uint8类型的图像直接进行除法或乘小数结果会被强行取整。在特征提取里计算归一化直方图时如果不先转换成double统计结果会匪夷所思。我建议在特征提取函数开头统一加上img double(img)或对灰度图转double后除以255。第二个是边界处理问题。提取LBP或梯度特征时图像边缘像素周围可能没有完整的邻域。MATLAB内置函数一般会自动处理边界但如果自己实现相关算法很容易在边界处计算出错误特征值导致后续相似度累计出微小偏差。排查时可以对比一下去掉边界像素前后的检索效果如果变化不大就说明边界处理不是关键因素。第三个是特征维数选择。HSV直方图的bin数不是越多越好。我用16x8x8的参数跑过很多数据集效果都算稳定。如果bin数太多比如64x64x64特征对噪声更敏感相似度计算也更耗时bin数太少又难以区分相近颜色。同理LBP的采样半径和邻域点数也需要根据图像分辨率做调整高分辨率图可以适当加大半径。最后分享一下我在实际项目里的几个体会。第一个体会是特征工程的投入产出比很高。很多人看了一些SOTA模型的论文总觉得换一个“先进模型”就能解决所有问题。但在图像检索的落地环节特征设计、预处理、度量方式这些“老一套”反而是效果提升最稳定的部分。做好基础比盲目追新更可靠。第二个体会是MATLAB在做检索算法原型验证时交互式脚本和可视化能力确实无可替代。我可以在几个小时之内对比十几组特征组合在评测集上的效果然后用一张曲线图直观看出哪个方案最好再拿最优方案到C工程里复现。这种流程在别的环境里很难复制。第三个体会是不要忽略检索结果的人性化呈现。算法排名给出Top-10之后用户看到一个折线排开的图片列表脑子里会自动补一条“从最像到最不像”的判断。所以在开发过程中别光盯着评估指标也要花心思做结果可视化方便调试也方便向同事介绍。如果你刚开始接触MATLAB图像检索我的建议非常简单先拿二十张图搭一个最小的完整系统颜色特征起步把入库、查询、可视化结果跑通然后再逐步加纹理特征、形状特征、融合权重调优。路虽长但每一步都能看到效果的变化这个过程本身就很值得。
阅读完成 · 觉得有帮助?