首页 > 解决方案 > 在图像数组上使用 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 函数。我还尝试了其他哈希函数并得到了相同的结果。

标签: pythonopencv

解决方案


您收到的原始图像的错误消息已经说明了一切:

ValueError: ndarray is not C-contiguous

散列函数仅适用于连续的内存区域,但 ndarrays(和一般的 Python 缓冲区)可以是不连续的。许多创建新 ndarray 的函数会将其创建为连续的,因此您始终可以使用其中一个函数来获取可散列的 ndarray。

但是,您应该知道,图像上的散列很少有用,除非您想识别像素精确的副本。只要图像被稍微修改过,例如通过压缩为 jpeg 和解压缩,它就会具有完全不同的哈希值,即使它看起来相同。


推荐阅读