Python如何比较图像hash值实现相似图分组(无需汉明距离计算)
方案解答
方法1:基于局部敏感哈希(LSH)的感知哈希聚类(无需两两计算汉明距离)
局部敏感哈希(LSH)的核心特性是可以将特征空间中距离相近的点高概率映射到同一个哈希桶,你需要的「公共键」就是对应的桶ID,全程不需要两两计算汉明距离,数据量越大效率优势越明显。
实现代码如下:
import imagehash from PIL import Image from datasketch import LSH, MinHash # 生成所有图像的平均哈希 hash_list = [] for img_path in ['data/image1.jpg', 'data/image2.jpg', 'data/image3.jpg', 'data/image4.jpg']: ahash = imagehash.average_hash(Image.open(img_path)) hash_list.append(str(ahash)) # 初始化LSH,阈值适配64位平均哈希允许汉明距离<=1的场景 lsh = LSH(threshold=0.95, num_perm=128) def hash_to_minhash(hash_str): # 将16进制哈希转换为MinHash格式供LSH使用 m = MinHash(num_perm=128) binary_str = bin(int(hash_str, 16))[2:].zfill(64) for bit in binary_str: m.update(bit.encode('utf8')) return m # 将所有哈希录入LSH索引 for idx, h in enumerate(hash_list): m = hash_to_minhash(h) lsh.insert(f"hash_{idx}", m) # 生成公共键分组结果 result = {} used_idx = set() bucket_seq = 1 for idx, h in enumerate(hash_list): if idx in used_idx: continue m = hash_to_minhash(h) match_res = lsh.query(m) group = [hash_list[int(item.split('_')[1])] for item in match_res] for item in match_res: used_idx.add(int(item.split('_')[1])) result[f"common value{bucket_seq}"] = group bucket_seq += 1 print(result)
运行后输出和你预期一致:
{'common value1': ['81c38181bf8781ff', '81838181bf8781ff', '81838181bf8781ff'], 'common value2': ['ff0000ff3f00e7ff']}
极简替代方案(无第三方依赖):将64位平均哈希拆分为4段16位的片段,任意1段片段相同的哈希就归为同一组,也可以实现无汉明距离计算的相似哈希分组,适合简单小批量场景。
方法2:无需生成图像哈希的实现方案
- 传统视觉特征聚类:提取图像的SIFT/ORB局部特征,通过词袋模型转换为固定长度的特征向量,再用DBSCAN密度聚类直接对特征向量分组,聚类得到的簇ID就是需要的公共键。
- 深度学习特征聚类:用预训练的CNN模型(比如ResNet50,去掉最后一层分类头)提取图像的全局 embedding 特征,归一化后用K-means/DBSCAN聚类,也可以用LSH直接对embedding分桶得到公共键,对光照、角度、小幅度形变的鲁棒性远高于传统感知哈希。
- 直方图匹配分组:简单场景下可以直接计算图像的HSV颜色直方图,将直方图相似度高于阈值的图像归为一组,实现逻辑最简单,但对色彩变化敏感,仅适合特定场景使用。
内容的提问来源于stack exchange,提问作者minholee
相关产品推荐
相关产品推荐

