相关文件路径 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. // ... existing code ...
  2. // 2. 比较特征相似度并分组
  3. group.notify(queue: processingQueue) {
  4. progressHandler("正在比较相似度...", 0.6)
  5. // 近似度
  6. let similarityThreshold: Float = 0.7
  7. var similarGroups: [[PHAsset]] = []
  8. // 使用并行处理来加速比较
  9. let processingGroup = DispatchGroup()
  10. let processingQueue = DispatchQueue(label: "com.yourapp.similarity.processing", attributes: .concurrent)
  11. let resultsQueue = DispatchQueue(label: "com.yourapp.similarity.results")
  12. let semaphore = DispatchSemaphore(value: 8) // 控制并发数量
  13. // 创建一个线程安全的数据结构来存储结果
  14. var processedIndices = Atomic<Set<Int>>(Set<Int>())
  15. var groupResults = Atomic<[Int: [PHAsset]]>([:])
  16. // 分批处理,每批处理一部分数据
  17. let batchSize = min(100, imageFeatures.count)
  18. let batches = Int(ceil(Float(imageFeatures.count) / Float(batchSize)))
  19. for batchIndex in 0..<batches {
  20. let startIndex = batchIndex * batchSize
  21. let endIndex = min(startIndex + batchSize, imageFeatures.count)
  22. for i in startIndex..<endIndex {
  23. // 检查是否已处理
  24. if processedIndices.value.contains(i) { continue }
  25. semaphore.wait()
  26. processingGroup.enter()
  27. processingQueue.async {
  28. // 再次检查,因为可能在等待期间被其他线程处理
  29. if processedIndices.value.contains(i) {
  30. semaphore.signal()
  31. processingGroup.leave()
  32. return
  33. }
  34. var similarAssets: [PHAsset] = [imageFeatures[i].asset]
  35. processedIndices.mutate { $0.insert(i) }
  36. for j in (i + 1)..<imageFeatures.count {
  37. // 检查是否已处理
  38. if processedIndices.value.contains(j) { continue }
  39. do {
  40. var distance: Float = 0
  41. try imageFeatures[i].feature.computeDistance(&distance, to: imageFeatures[j].feature)
  42. let similarity = 1 - distance
  43. if similarity >= similarityThreshold {
  44. similarAssets.append(imageFeatures[j].asset)
  45. processedIndices.mutate { $0.insert(j) }
  46. }
  47. } catch {
  48. print("相似度计算失败: \(error)")
  49. }
  50. }
  51. // 只保存有多个相似图像的组
  52. if similarAssets.count > 1 {
  53. resultsQueue.async {
  54. groupResults.mutate { $0[i] = similarAssets }
  55. }
  56. }
  57. // 更新进度
  58. let progress = Float(processedIndices.value.count) / Float(imageFeatures.count)
  59. DispatchQueue.main.async {
  60. progressHandler("正在比较相似度...", 0.6 + progress * 0.4)
  61. }
  62. semaphore.signal()
  63. processingGroup.leave()
  64. }
  65. }
  66. }
  67. processingGroup.wait()
  68. // 整理结果
  69. similarGroups = Array(groupResults.value.values)
  70. // 按照照片数量降序排序
  71. similarGroups.sort { $0.count > $1.count }
  72. DispatchQueue.main.async {
  73. completion(similarGroups)
  74. }
  75. }
  76. // ... existing code ...