python - 在图像数组上使用 cv2.resize() 可以让我在不转换为字节的情况下对其进行散列
问题描述
hashlib.md5() 不能将 ndarray 作为参数,因此我必须使用 .tobytes() 将 ndarray 转换为字节。如果我不这样做,我会收到以下错误:
ValueError: ndarray is not C-contiguous
但是,如果我在 ndarray 上使用 cv2.resize(),即使 cv2.resize() 的输出仍然是 ndarray,我也可以在不转换为字节的情况下对其进行散列:
import cv2
image = cv2.imread("img.png")
r_img = cv2.resize(image, (0, 0), fx=1, fy=1)
print(type(r_img))
给出输出:
<class 'numpy.ndarray'>
这是我的完整代码:
import timeit
import cv2
import hashlib
image = cv2.imread("img.png")
def hash_without_resize(img):
b_img = img.tobytes()
return hashlib.md5(b_img).hexdigest()
def hash_with_resize(img):
# Resize the image with scale factor 1 in both directions (the image stays exactly the same)
r_img = cv2.resize(img, (0, 0), fx=1, fy=1)
return hashlib.md5(r_img).hexdigest()
print(timeit.timeit('hash_without_resize(image)', 'from __main__ import hash_without_resize, image', number=1000)
print(timeit.timeit('hash_with_resize(image)', 'from __main__ import hash_with_resize, image', number=1000)
print(hash_without_resize(image), hash_with_resize(image))
给出输出:
0.4001011
0.40305579999999985
62da8968d9cb37790811ff16624d8cc7 62da8968d9cb37790811ff16624d8cc7
如您所见,尽管它仍然是一个 ndarray,但在散列调整大小的 ndarray 时不会引发错误。此外,哈希值是相同的,因此图像根本不会因调整大小而改变。有人可以解释为什么会这样,因为我很困惑。它也适用于使用 cv2.flip() 和其他 opencv 函数。我还尝试了其他哈希函数并得到了相同的结果。
解决方案
您收到的原始图像的错误消息已经说明了一切:
ValueError: ndarray is not C-contiguous
散列函数仅适用于连续的内存区域,但 ndarrays(和一般的 Python 缓冲区)可以是不连续的。许多创建新 ndarray 的函数会将其创建为连续的,因此您始终可以使用其中一个函数来获取可散列的 ndarray。
但是,您应该知道,图像上的散列很少有用,除非您想识别像素精确的副本。只要图像被稍微修改过,例如通过压缩为 jpeg 和解压缩,它就会具有完全不同的哈希值,即使它看起来相同。
推荐阅读
- typescript - 将数组转换为对象的正确 fp-ts 方法
- sql - 所需预期报告的 SQL 分组
- html - 自动将滚动条添加到具有固定位置祖先的 div
- java - SpringBoot - 尽管 spring.profiles.active=local 正确,但选择了错误的配置文件和错误的 bean
- reactjs - 将 Firebase 与 Github Pages 一起使用并遇到“net::ERR_ABORTED 404”
- flutter - 将边框半径和边框应用于底部导航栏中的容器后,如何删除多余的空白?
- tensorflow - 在tensorflow中用张量乘法替换for循环
- python-3.x - matplotlib Y轴间距调整
- python - 如何使用 try 和 except
- python-3.x - 从某些列 Pandas Series 中删除 NaN 值