用Python实现通过哈希算法检测图片重复的教程
Iconfinder 是一个图标搜索引擎,为设计师、开发者和其他创意工作者提供精美图标,目前托管超过 34 万枚图标,是全球最大的付费图标库。用户也可以在 Iconfinder 的交易板块上传出售原创作品。每个月都有成千上万的图标上传到Iconfinder,同时也伴随而来大量的盗版图。Iconfinder 工程师 Silviu Tantos 在本文中提出一个新颖巧妙的图像查重技术,以杜绝盗版。
我们将在未来几周之内推出一个检测上传图标是否重复的功能。例如,如果用户下载了一个图标然后又试图通过上传它来获利(曾发生过类似案例),那么通过我们的方法,就可以检测出该图标是否已存在,并且标记该账户欺诈。在大量文件中检测某文件是否已经存在的一个常用方法是,通过计算数据集中每一个文件的哈希值,并将该哈希值存储在数组库中。当想要查找某特定文件时,首先计算该文件哈希值,然后在数据库中查找该哈希值。
选择一个哈希算法
加密哈希算法是一个常用的哈希算法。类似MD5,SHA1,SHA256这种在任何一种语言都可以找到可调用的标准库,它们对于简单的用例非常有效。
例如,在Python中先导入hashlib模块,然后调用函数就可以生成某一个字符串或者文件的哈希值。
>>> import hashlib # Calculating the hash value of a string. >>> hashlib.md5('The quick brown fox jumps over the lazy dog').hexdigest() '9e107d9d372bb6826bd81d3542a419d6' # Loading an image file into memory and calculating it's hash value. >>> image_file = open('data/cat_grumpy_orig.png').read() >>> hashlib.md5(image_file).hexdigest() '3e1f6e9f2689d59b9ed28bcdab73455f'
这个算法对于未被篡改的上传文件非常有效,如果输入数据有细微变化,加密哈希算法都会导致雪崩效应,从而造成新文件的哈希值完全不同于原始文件哈希值。
比如下面这个例子,它在句子的结尾多加了一个句号。
# Original text. >>> hashlib.md5('The quick brown fox jumps over the lazy dog').hexdigest() '9e107d9d372bb6826bd81d3542a419d6' # Slight modification of the text. >>> hashlib.md5('The quick brown fox jumps over the lazy dog.').hexdigest() 'e4d909c290d0fb1ca068ffaddf22cbd0'
如果图像背景色被改变,图像被裁剪,旋转或者某一个像素被修改,那么都无法在图像哈希库中匹配。可见传统哈希算法并不具有实用性。正如你在上面例子中看到的,哈希值9 e107d9d372bb6826bd81d3542a419d6 和e4d909c290d0fb1ca068ffaddf22cbd0几乎是不同的(除了几个字符)。
例如,修改图像中猫咪鼻子的颜色后,图像的哈希值将改变。
# Load the original image into memory and calculate it's hash value. >>> image_file = open('data/cat_grumpy_orig.png').read() >>> hashlib.md5(image_file).hexdigest() '3e1f6e9f2689d59b9ed28bcdab73455f' # Load the modified image into memory and calculate it's hash value. >>> image_file_modified = open('data/cat_grumpy_modif.png').read() >>> hashlib.md5(image_file_modified).hexdigest() '12d1b9409c3e8e0361c24beaee9c0ab1'
目前已有许多感知哈希算法,本文将要提出一个新的dhash(差异哈希)算法,该算法计算相邻像素之间的亮度差异并确定相对梯度。对于以上的用例,感知哈希算法将非常有效。感知哈希算法从文件内容的各种特征中获得一个能够灵活分辨不同文件微小区别的多媒体文件指纹。
dHash
深入学习dHash算法前,先介绍一些基础知识。一个彩色图像是由RGB三原色组成,可以看成一个红绿蓝三原色的颜色集。比如利用用Python图像库(PIL)加载一个图像,并打印像素值。
Test image
>>> from PIL import Image >>> test_image = Image.open('data/test_image.jpg') # The image is an RGB image with a size of 8x8 pixels. >>> print 'Image Mode: %s' % test_image.mode Image Mode: RGB >>> print 'Width: %s px, Height: %s px' % (test_image.size[0], test_image.size[1]) Width: 4 px, Height: 4 px # Get the pixel values from the image and print them into rows based on # the image's width. >>> width, height = test_image.size >>> pixels = list(test_image.getdata()) >>> for col in xrange(width): ... print pixels[col:col+width] ... [(255, 0, 0), (0, 255, 0), (0, 0, 255), (255, 255, 255)] [(0, 0, 0), (212, 45, 45), (51, 92, 154), (130, 183, 47)] [(206, 210, 198), (131, 78, 8), (131, 156, 180), (117, 155, 201)] [(104, 133, 170), (215, 130, 20), (153, 155, 155), (104, 142, 191)]
现在我们回到dHash算法,该算法有四个步骤,本文详细说明每一步并验证它在原始图像和修改后图像的效果。前三个像素的红绿蓝颜色强度值分别为255,其余两个颜色强度值分别为0,纯黑色像素三原色为0,纯白色像素三原色为255。其它颜色像素则是由不同强度三原色值组成的。
1.图像灰度化
通过灰度化图像,将像素值减少到一个发光强度值。例如,白色像素(255、255、255)成为255而黑色像素(0,0,0)强度值将成为0。
2.将图像缩小到一个常见大小
将图像缩减到一个常见基础尺寸,比如宽度大高度一个像素值的9*8像素大小(到第三步你就能明白为什么是这个尺寸)。通过这个方法将图像中的高频和细节部分移除,从而获得一个有72个强度值的样本。由于调整或者拉伸图像并不会改变它的哈希值,所以将所有图像归一化到该大小。
3.比较邻域像素
前两步实现后得到一个强度值列表,比较该二进制值数组的每一行的相邻像素。
>>> from PIL import Image >>> img = Image.open('data/cat_grumpy_orig_after_step_2.png') >>> width, height = img.size >>> pixels = list(img.getdata()) >>> for col in xrange(width): ... print pixels[col:col+width] ... [254, 254, 255, 253, 248, 254, 255, 254, 255] [254, 255, 253, 248, 254, 255, 254, 255, 255] [253, 248, 254, 255, 254, 255, 255, 255, 222] [248, 254, 255, 254, 255, 255, 255, 222, 184] [254, 255, 254, 255, 255, 255, 222, 184, 177] [255, 254, 255, 255, 255, 222, 184, 177, 184] [254, 255, 255, 255, 222, 184, 177, 184, 225] [255, 255, 255, 222, 184, 177, 184, 225, 255]
第一个值254和第二个254做比较,第二个值和第三个值比,以此类推,从而每行得到8个布尔值。
>>> difference = [] >>> for row in xrange(height): ... for col in xrange(width): ... if col != width: ... difference.append(pixels[col+row] > pixels[(col+row)+1]) ... >>> for col in xrange(width-1): ... print difference[col:col+(width-1)] ... [False, False, True, True, False, False, True, False] [False, True, True, False, False, True, False, False] [True, True, False, False, True, False, False, False] [True, False, False, True, False, False, False, True] [False, False, True, False, False, False, True, True] [False, True, False, False, False, True, True, False] [True, False, False, False, True, True, False, False] [False, False, False, True, True, False, False, True]
4.转换为二值
为了方便哈希值存储和使用,将8个布尔值转换为16进制字符串。Ture变成1,而False变成0。
Python实现
下面是完整Python实现的完成算法:
def dhash(image, hash_size = 8): # Grayscale and shrink the image in one step. image = image.convert('L').resize( (hash_size + 1, hash_size), Image.ANTIALIAS, ) pixels = list(image.getdata()) # Compare adjacent pixels. difference = [] for row in xrange(hash_size): for col in xrange(hash_size): pixel_left = image.getpixel((col, row)) pixel_right = image.getpixel((col + 1, row)) difference.append(pixel_left > pixel_right) # Convert the binary array to a hexadecimal string. decimal_value = 0 hex_string = [] for index, value in enumerate(difference): if value: decimal_value += 2**(index % 8) if (index % 8) == 7: hex_string.append(hex(decimal_value)[2:].rjust(2, '0')) decimal_value = 0 return ''.join(hex_string)
最常见情况,图片稍有不同,哈希值很可能是相同的,所以我们可以直接比较。
>>> from PIL import Image >>> from utility import dhash, hamming_distance >>> orig = Image.open('data/cat_grumpy_orig.png') >>> modif = Image.open('data/cat_grumpy_modif.png') >>> dhash(orig) '4c8e3366c275650f' >>> dhash(modif) '4c8e3366c275650f' >>> dhash(orig) == dhash(modif) True 如果有一
个保存哈希值的SQL数据库, 可以这样简单判断哈希值“4 c8e3366c275650f ”是否存在:
SELECT pk, hash, file_path FROM image_hashes WHERE hash = '4c8e3366c275650f';
现在,对于一些有较大差别的图像,它们的哈希值可能是不相同的,那么需要计算由一个字符串变成另一个字符串所需替换的最少字符数,即汉明距离。
维基百科上有一些计算两个字符串之间的汉明距离的Python示例代码。但是也可以直接基于MySQL数据库上的计算和查询来实现。
SELECT pk, hash, BIT_COUNT( CONV(hash, 16, 10) ^ CONV('4c8e3366c275650f', 16, 10) ) as hamming_distance FROM image_hashes HAVING hamming_distance < 4 ORDER BY hamming_distance ASC;
对所查询的值与数据库中的哈希值进行异或操作,计数不同位数。由于BIT_COUNT只能操作整数,所以要将所有十六进制的哈希值转成十进制。
结束语
本文使用Python实现了所介绍的算法,当然了读者可以使用任何编程语言实现算法。
在简介中提过,本文算法将应用到Iconfinder上去防止重复提交图标,可以预想,感知哈希算法还有更多实际应用。因为有相似特征的图像的哈希值也是相似的,所以它可以帮助图像推荐系统寻找相似图像。

Outils d'IA chauds

Undresser.AI Undress
Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover
Outil d'IA en ligne pour supprimer les vêtements des photos.

Undress AI Tool
Images de déshabillage gratuites

Clothoff.io
Dissolvant de vêtements AI

AI Hentai Generator
Générez AI Hentai gratuitement.

Article chaud

Outils chauds

Bloc-notes++7.3.1
Éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise
Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1
Puissant environnement de développement intégré PHP

Dreamweaver CS6
Outils de développement Web visuel

SublimeText3 version Mac
Logiciel d'édition de code au niveau de Dieu (SublimeText3)

MySQL a une version communautaire gratuite et une version d'entreprise payante. La version communautaire peut être utilisée et modifiée gratuitement, mais le support est limité et convient aux applications avec des exigences de stabilité faibles et des capacités techniques solides. L'Enterprise Edition fournit une prise en charge commerciale complète pour les applications qui nécessitent une base de données stable, fiable et haute performance et disposées à payer pour le soutien. Les facteurs pris en compte lors du choix d'une version comprennent la criticité des applications, la budgétisation et les compétences techniques. Il n'y a pas d'option parfaite, seulement l'option la plus appropriée, et vous devez choisir soigneusement en fonction de la situation spécifique.

L'article présente le fonctionnement de la base de données MySQL. Tout d'abord, vous devez installer un client MySQL, tel que MySQLWorkBench ou le client de ligne de commande. 1. Utilisez la commande MySQL-UROot-P pour vous connecter au serveur et connecter avec le mot de passe du compte racine; 2. Utilisez Createdatabase pour créer une base de données et utilisez Sélectionner une base de données; 3. Utilisez CreateTable pour créer une table, définissez des champs et des types de données; 4. Utilisez InsertInto pour insérer des données, remettre en question les données, mettre à jour les données par mise à jour et supprimer les données par Supprimer. Ce n'est qu'en maîtrisant ces étapes, en apprenant à faire face à des problèmes courants et à l'optimisation des performances de la base de données que vous pouvez utiliser efficacement MySQL.

Le fichier de téléchargement mysql est corrompu, que dois-je faire? Hélas, si vous téléchargez MySQL, vous pouvez rencontrer la corruption des fichiers. Ce n'est vraiment pas facile ces jours-ci! Cet article expliquera comment résoudre ce problème afin que tout le monde puisse éviter les détours. Après l'avoir lu, vous pouvez non seulement réparer le package d'installation MySQL endommagé, mais aussi avoir une compréhension plus approfondie du processus de téléchargement et d'installation pour éviter de rester coincé à l'avenir. Parlons d'abord de la raison pour laquelle le téléchargement des fichiers est endommagé. Il y a de nombreuses raisons à cela. Les problèmes de réseau sont le coupable. L'interruption du processus de téléchargement et l'instabilité du réseau peut conduire à la corruption des fichiers. Il y a aussi le problème avec la source de téléchargement elle-même. Le fichier serveur lui-même est cassé, et bien sûr, il est également cassé si vous le téléchargez. De plus, la numérisation excessive "passionnée" de certains logiciels antivirus peut également entraîner une corruption des fichiers. Problème de diagnostic: déterminer si le fichier est vraiment corrompu

Les principales raisons de la défaillance de l'installation de MySQL sont les suivantes: 1. Problèmes d'autorisation, vous devez s'exécuter en tant qu'administrateur ou utiliser la commande sudo; 2. Des dépendances sont manquantes et vous devez installer des packages de développement pertinents; 3. Conflits du port, vous devez fermer le programme qui occupe le port 3306 ou modifier le fichier de configuration; 4. Le package d'installation est corrompu, vous devez télécharger et vérifier l'intégrité; 5. La variable d'environnement est mal configurée et les variables d'environnement doivent être correctement configurées en fonction du système d'exploitation. Résolvez ces problèmes et vérifiez soigneusement chaque étape pour installer avec succès MySQL.

MySQL a refusé de commencer? Ne paniquez pas, vérifions-le! De nombreux amis ont découvert que le service ne pouvait pas être démarré après avoir installé MySQL, et ils étaient si anxieux! Ne vous inquiétez pas, cet article vous emmènera pour le faire face calmement et découvrez le cerveau derrière! Après l'avoir lu, vous pouvez non seulement résoudre ce problème, mais aussi améliorer votre compréhension des services MySQL et vos idées de problèmes de dépannage, et devenir un administrateur de base de données plus puissant! Le service MySQL n'a pas réussi et il y a de nombreuses raisons, allant des erreurs de configuration simples aux problèmes système complexes. Commençons par les aspects les plus courants. Connaissances de base: une brève description du processus de démarrage du service MySQL Service Startup. Autrement dit, le système d'exploitation charge les fichiers liés à MySQL, puis démarre le démon mysql. Cela implique la configuration

Guide d'optimisation des performances de la base de données MySQL dans les applications à forte intensité de ressources, la base de données MySQL joue un rôle crucial et est responsable de la gestion des transactions massives. Cependant, à mesure que l'échelle de l'application se développe, les goulots d'étranglement des performances de la base de données deviennent souvent une contrainte. Cet article explorera une série de stratégies efficaces d'optimisation des performances MySQL pour garantir que votre application reste efficace et réactive dans des charges élevées. Nous combinerons des cas réels pour expliquer les technologies clés approfondies telles que l'indexation, l'optimisation des requêtes, la conception de la base de données et la mise en cache. 1. La conception de l'architecture de la base de données et l'architecture optimisée de la base de données sont la pierre angulaire de l'optimisation des performances MySQL. Voici quelques principes de base: sélectionner le bon type de données et sélectionner le plus petit type de données qui répond aux besoins peut non seulement économiser un espace de stockage, mais également améliorer la vitesse de traitement des données.

L'optimisation des performances MySQL doit commencer à partir de trois aspects: configuration d'installation, indexation et optimisation des requêtes, surveillance et réglage. 1. Après l'installation, vous devez ajuster le fichier my.cnf en fonction de la configuration du serveur, tel que le paramètre innodb_buffer_pool_size, et fermer query_cache_size; 2. Créez un index approprié pour éviter les index excessifs et optimiser les instructions de requête, telles que l'utilisation de la commande Explication pour analyser le plan d'exécution; 3. Utilisez le propre outil de surveillance de MySQL (ShowProcessList, Showstatus) pour surveiller la santé de la base de données, et sauvegarde régulièrement et organisez la base de données. Ce n'est qu'en optimisant en continu ces étapes que les performances de la base de données MySQL peuvent être améliorées.

MySQL peut s'exécuter sans connexions réseau pour le stockage et la gestion des données de base. Cependant, la connexion réseau est requise pour l'interaction avec d'autres systèmes, l'accès à distance ou l'utilisation de fonctionnalités avancées telles que la réplication et le clustering. De plus, les mesures de sécurité (telles que les pare-feu), l'optimisation des performances (choisissez la bonne connexion réseau) et la sauvegarde des données sont essentielles pour se connecter à Internet.
