这篇博客将介绍图像哈希,感知哈希以及这些算法如何用于(快速)确定图像的视觉内容是否相同或相似。并实现了差异散列,一个常见的感知散列算法(1)非常快,而(2)非常准确。以此来判断图片是否发生变化。
1. 效果图
2. 原理
图像哈希或者感知哈希的步骤是: 基于图像的内容,构建唯一标识输入图像的散列值。
通过利用图像散列算法,可以在恒定的时间内或最差,O(Log n)时间找到近似相同的图像。
-
为什么传统哈希不起作用
传统的md5、sha等密码散列算法的本质:更改文件中的单个位会导致不同的哈希。 实质上图像哈希希望只有单个像素变化的,认为图像没有变化,或者图像缩放也认为没有变化;
-
差异哈希(DHASH)的好处:
1)输入图像的宽高比更改(由于忽略了纵横比),图像哈希不会改变;
2)调整亮度或对比度(1)不会改变哈希值或(2)只会稍微改变它,确保散列将靠近;
3)差异散列非常快且准确; -
通常使用 汉明距离 来比较哈希值。两个汉明距离很小的哈希意味着两个散列是相同的,并且两个图像也是相同的/感知相似的。
3. 源代码
# USAGE
# python hash.py --images images
# 导入必要的包
from imutils import paths
import argparse
import time
import sys
import cv2
# 设置图像散列为8,表示构建8*8=64位哈希值
def dhash(image, hashSize=8):
# 缩放输入图像,增加一列以计算水平梯度差值
resized = cv2.resize(image, (hashSize + 1, hashSize))
# 计算相邻水平梯度列像素差值
diff = resized[:, 1:] > resized[:, :-1]
# 转换图像差异为hash
return sum([2 ** i for (i, v) in enumerate(diff.flatten()) if v])
# 构建命令行参数及解析
ap = argparse.ArgumentParser()
ap.add_argument("-i", "--images", required=True,
help="dataset of images to search through (i.e., the haytack)")
args = vars(ap.parse_args())
# 获取hastach、needle文件图片
print("[INFO] computing hashes for images...")
hashmapsPaths = list(paths.list_images(args["images"]))
# 移除文件名中的\
if sys.platform != "win32":
hashmapsPaths = [p.replace("\\", "") for p in hashmapsPaths]
# 初始化存放图像名及其hash值的map,并计时
hashmaps = {
}
start = time.time()
# 遍历hashmaps路径
for p in hashmapsPaths:
# 从磁盘加载图像
image = cv2.imread(p)
# 如果图像为None,则跳过
if image is None:
continue
# 转换图像为灰度图,并计算图像hash值
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
imageHash = dhash(image)
# 更新hashmaps字典
l = hashmaps.get(imageHash, [])
l.append(p)
hashmaps[imageHash] = l
# 展示hash耗时及hashmaps照片数,开始计算needles文件夹的图像hash值
print("[INFO] processed {} images in {:.2f} seconds".format(
len(hashmaps), time.time() - start))
print("[INFO] computing hashes for needles...")
for k,v in hashmaps.items():
print("[INFO] {}: {}".format(k,v))