如何实现数组中单个元素与其余所有元素的对比(图片相似度计算场景)
核心解决思路
你现在的代码只完成了「第一张图和剩余所有图对比」的逻辑,要实现所有图两两对比,只需要在外层再加一层循环,逐个把每张图当作基准图和其余图对比即可,同时要注意2个初学者容易踩的坑:
- 不要边遍历数组边删除元素,很容易出现索引越界崩溃
- 提前把所有图片的特征值计算好存起来,不用每次对比都重复转PNG、重复计算特征,能大幅提升运行速度
完整实现代码
// 先定义个结构体存每张图的索引和对应的特征值,方便后续处理 struct ImageFeature { let index: Int let feature: FeatureprintObservation // 这里替换成你项目里featureprintObservation的实际类型 } private func findAllSimilarImages() { // 1、先把所有图片的特征值一次性算完存好 var allFeatures = [ImageFeature]() for (index, image) in imageArray.enumerated() { guard let pngData = image.pngData(), let feature = featureprintObservationForImage(data: pngData) else { continue // 某张图计算失败就跳过,不要直接return终止整个流程 } allFeatures.append(ImageFeature(index: index, feature: feature)) } // 用Set存重复图的索引,自动去重 var duplicateIndexSet = Set<Int>() // 2、双层循环两两对比 // 外层循环:每次取第i张图当基准图 for i in allFeatures.indices { // 如果当前图已经被标记为重复了,就不用再当基准图对比了,跳过 if duplicateIndexSet.contains(i) { continue } let baseFeature = allFeatures[i].feature // 内层循环:从i+1开始,只和基准图后面的图对比,避免重复计算 for j in (i+1)..<allFeatures.count { if duplicateIndexSet.contains(j) { continue } let compareFeature = allFeatures[j].feature do { var distance: Float = 0 try compareFeature.computeDistance(&distance, to: baseFeature) print("第\(i)张和第\(j)张的相似度距离:\(distance)") if distance <= 3.0 { // 标记为重复 duplicateIndexSet.insert(j) } } catch { print("计算第\(i)和\(j)张图特征距离失败:\(error)") } } } // 3、统一处理结果 // 所有重复图 similarImages = duplicateIndexSet.compactMap { index in imageArray[index] } // 所有不重复的图 let uniqueImages = imageArray.enumerated() .filter { !duplicateIndexSet.contains($0.offset) } .map { $0.element } print("找到重复图数量:\(similarImages.count)") }
关键逻辑说明
- 内层循环从
i+1开始,是因为第0张和第1张对比过之后,第1张就不用再回头和第0张对比了,能减少一半的计算量 - 用
Set存重复索引,是为了避免同一张图被多次标记为重复 - 提前计算所有特征值,避免同一张图被反复转PNG、反复算特征,性能提升非常明显
内容的提问来源于stack exchange,提问作者Artem Golubinskiy
相关产品推荐
相关产品推荐

