Python中如何使用OpenCV比较两张图像的相似度
图像相似度比对优化方案
现有方案的核心问题
- 冗余磁盘IO:预处理后的图像矩阵不需要写入本地临时文件再读取,完全可以在内存中完成格式转换对接后续逻辑,省去文件读写、删除的额外开销,比对速度会有明显提升,也不会出现文件权限错误、残留文件占用磁盘的问题
- 代码逻辑bug:
os.remove仅支持传入单个完整文件路径参数,现有传参方式会直接抛出类型错误- 参考图预处理后保存为
datagray.jpg,哈希计算时读取的是datagray.jpeg,后缀不匹配会触发文件不存在错误 - 参考图做了固定尺寸resize,待比对的采集图没有做相同尺寸对齐,会引入不必要的哈希计算误差
- 硬编码绝对路径做文件删除,换运行环境会直接报错
- 跨库调用冗余:需求明确优先使用OpenCV,可以直接在OpenCV生态内实现哈希计算,不需要额外依赖PIL、imagehash库
优化后实现
方案1:保留感知哈希逻辑,消除冗余IO
不需要写临时文件,OpenCV处理完的矩阵在内存中直接转PIL格式对接imagehash即可,修正后的代码如下:
import cv2 import numpy as np from PIL import Image import imagehash def compareImg(imgWarpColor, threshold=5, ref_img_path="data.jpg", standard_size=(660, 880)): # 预处理参考图 ref_img = cv2.imread(ref_img_path) ref_img = cv2.resize(ref_img, standard_size) ref_img_gray = cv2.cvtColor(ref_img, cv2.COLOR_BGR2GRAY) ref_img_blur = cv2.GaussianBlur(ref_img_gray, (3,3), 0) # 内存中转PIL格式,无需写临时文件 ref_pil = Image.fromarray(cv2.cvtColor(ref_img_blur, cv2.COLOR_BGR2RGB)) hash_ref = imagehash.average_hash(ref_pil) # 预处理待比对图,和参考图做完全一致的尺寸、预处理操作 target_img = cv2.resize(imgWarpColor, standard_size) target_img_gray = cv2.cvtColor(target_img, cv2.COLOR_BGR2GRAY) target_img_blur = cv2.GaussianBlur(target_img_gray, (3,3), 0) target_pil = Image.fromarray(cv2.cvtColor(target_img_blur, cv2.COLOR_BGR2RGB)) hash_target = imagehash.average_hash(target_pil) hash_diff = hash_ref - hash_target print(f"哈希差值:{hash_diff}") return hash_diff < threshold
方案2:纯OpenCV实现(无额外依赖)
如果要完全基于OpenCV实现,可以直接用OpenCV实现均值哈希/差值哈希算法,不需要引入其他第三方库,示例代码如下:
import cv2 import numpy as np def aHash(img, size=(8,8)): # 均值哈希实现 img_resize = cv2.resize(img, size, interpolation=cv2.INTER_CUBIC) img_gray = cv2.cvtColor(img_resize, cv2.COLOR_BGR2GRAY) if len(img_resize.shape)==3 else img_resize pixel_mean = np.mean(img_gray) hash_str = '' for i in range(size[1]): for j in range(size[0]): hash_str += '1' if img_gray[i,j] > pixel_mean else '0' return hash_str def hammingDist(hash1, hash2): # 计算汉明距离 return np.sum([1 for i in range(len(hash1)) if hash1[i]!=hash2[i]]) def compareImg(imgWarpColor, threshold=5, ref_img_path="data.jpg", standard_size=(660, 880)): # 预处理参考图 ref_img = cv2.imread(ref_img_path) ref_img = cv2.resize(ref_img, standard_size) ref_img_gray = cv2.cvtColor(ref_img, cv2.COLOR_BGR2GRAY) ref_img_blur = cv2.GaussianBlur(ref_img_gray, (3,3), 0) hash_ref = aHash(ref_img_blur) # 预处理待比对图 target_img = cv2.resize(imgWarpColor, standard_size) target_img_gray = cv2.cvtColor(target_img, cv2.COLOR_BGR2GRAY) target_img_blur = cv2.GaussianBlur(target_img_gray, (3,3), 0) hash_target = aHash(target_img_blur) hash_diff = hammingDist(hash_ref, hash_target) print(f"哈希差值:{hash_diff}") return hash_diff < threshold
调参建议
- 相似度阈值可以根据实际场景调整:一般汉明距离小于5判定为高度相似,5~10判定为中度相似,大于10基本为不同图像
- 如果采集的图像存在光照偏差,可以把高斯模糊核调大,或者改用感知哈希(pHash)代替平均哈希,抗干扰性更强
- 如果图像存在旋转、裁剪偏移,不建议用哈希算法,可以改用OpenCV的ORB特征点匹配做相似度计算,鲁棒性更好
内容的提问来源于stack exchange,提问作者xkycc
相关产品推荐
相关产品推荐

