数据处理四 基于图像hash进行数据整理(删除重复图片、基于模版查找图片)

一、背景知识

1.1 什么是hash

Hash,一般翻译做“散列”,也有直接音译为“哈希”的,基本原理就是把任意长度的输入,通过Hash算法变成固定长度的输出。这个映射的规则就是对应的Hash算法,而原始数据映射后的二进制串就是哈希值。与指纹一样,就是以较短的信息来保证文件的唯一性的标志,这种标志与文件的每一个字节都相关,而且难以找到逆向规律。 活动开发中经常使用的MD5和SHA都是历史悠久的Hash算法。

hash算法的特点:

  • 从hash值不可以反向推导出原始的数据 不可逆
  • 输入数据的微小变化会得到完全不同的hash值,相同的数据会得到相同的值 唯一对应
  • hash算法的冲突概率要小 冲突概率小
  • 哈希算法的执行效率要高效,长的文本也能快速地计算出哈希值 高效计算

由于hash的原理是将输入空间的值映射成hash空间内,而hash值的空间远小于输入空间(输入空间是无限长度,而hash空间是有限的)。根据抽屉原理,一定会存在不同的输入被映射成相同输出的情况。那么作为一个好的hash算法,就需要这种冲突的概率尽可能小。
以上内容参考自:https://zhuanlan.zhihu.com/p/309675754

一般使用hash算法是为了校验文件是否被篡改或有传输损失。例如:某网站提供了文件下载地址和文件hash,我们下载文件后可以通过校验hash,确认文件没有发生传输损失(我下载的文件hash值,与网站公布的hash值一致)。又例如:某计算机考试,让学生提交作业文档和文档hash值给老师,确保作业未被篡改。

1.2 图片hash

哈希相似度算法(Hash algorithm),它的作用是对每张图片生成一个固定位数的Hash 值(指纹 fingerprint)字符串,然后比较不同图片的指纹,结果越接近,就说明图片越相似。图像Hash算法准确的说有三种,分别为平均哈希算法(aHash)、感知哈希算法你(pHash)和差异哈哈希算法(dHash)。

图像hash与上文中描述的hash算法目的不同,图像hash主要可用于判断或查找相似的图片,我们要尽可能的是图像hash值具有意义,与内容相关。他应当具备以下特点:

  • 1、高效计算,能适应于不同尺寸的图像(图像hash都要进行resize(8x8)

  • 2、存在相似性,使相似的图像hash值相似(根据图像的内容生成hash值

    三种Hash算法都是通过获取图片的hash值,再比较两张图片hash值的汉明距离来度量两张图片是否相似。两张图片越相似,那么两张图片的hash数的汉明距离越小。

平均哈希算法(aHash)

平均哈希算法是三种Hash算法中最简单的一种,它通过下面几个步骤来获得图片的Hash值,这几个步骤分别是(1) 缩放图片;(2)转灰度图; (3) 算像素均值;(4)根据相似均值计算指纹。具体算法如下所示:
在这里插入图片描述
得到图片的ahash值后,比较两张图片ahash值的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。汉明距离:字符串差异计算,相同位置下字符不同,则距离值加1

感知哈希算法(pHash)

感知哈希算法是三种Hash算法中较为复杂的一种,它是基于DCT(离散余弦变换)来得到图片的hash值,其算法几个步骤分别是(1) 缩放图片;(2)转灰度图; (3) 计算DCT;(4)缩小DCT; (5)算平均值;(6) 计算指纹。具体算法如下所示:
在这里插入图片描述

得到图片的phash值后,比较两张图片phash值的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。

差异哈希算法(dHash)

相比pHash,dHash的速度要快的多,相比aHash,dHash在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。其算法几个步骤分别是(1) 缩放图片;(2)转灰度图; (3) 算差异值;(4) 计算指纹。具体算法如下所示:
在这里插入图片描述
得到图片的phash值后,比较两张图片phash值的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。
以上内容参考自:https://www.cnblogs.com/Yumeka/p/11260808.html

二、图片hash的运用

2.1 删除重复图片

要删除文件夹内重复的图片,可以使用 imagededup库。 imagededup是一个基于Python的图片查重工具库,它简化了在图像集合中查找精确重复和近似重复的任务。可以使用CNN(卷积神经网络)、PHash、DHash、WHash(小波散列)、以及AHash这几种方法之一对图像生成编码,然后根据编码进行比对图像是否重复,并提供一些工具生成图片重复项快照​。

在这里插入图片描述
通过 pip 安装
安装命令

 pip install imagededup
具体使用案例

对一个文件夹内相同图片进行去重操作。本博文运用的是PHash(感知hash算法)。原始文件夹内的数据如下图所示:
在这里插入图片描述
注意如果是windows系统的话要加上if name==‘main’: ,因为它会默认使用多线程进行处理,不加的话会报错。
完整代码:

import os
from imagededup.methods import PHash
 
def process_file(img_path):
    """
    处理图片去重
    :return:
    """
    try:
        phasher = PHash()#WHash、AHash
        # 生成图像目录中所有图像的二值hash编码
        encodings = phasher.encode_images(image_dir=img_path)
        #print(encodings)
        # 对已编码图像寻找重复图像
        duplicates = phasher.find_duplicates(encoding_map=encodings)
        print(duplicates)
        only_img = []  # 唯一图片
        like_img = []  # 相似图片

        for img, img_list in duplicates.items():
            if img not in only_img and img not in like_img:
                only_img.append(img)
                like_img.extend(img_list)

        # 删除文件
        for like in like_img:
            print("like:  ",like)
            like_src = os.path.join(img_path, like)
            if os.path.exists(like_src):
                os.remove(like_src)

    except Exception as e:
        print(e)


if __name__ == "__main__":
    img_path = "D:/实战项目/图像清理/1123"
    process_file(img_path)

代码运行输出如下所示:like即为找出的相似图片
在这里插入图片描述

代码运行后,文件夹内的图片如下所示,将大部分重复的图像进行删除。
在这里插入图片描述
这个方法的核心步骤是通过计算图片的哈希值进行比较,因为哈希值在一定程度上能够反映出图片的内容特征,所以相同或相似的图片的哈希值也会相对接近。通过利用哈希值进行比较,能够快速找出重复的图片并删除。
需要注意的是,由于哈希值是通过将图片文件转化为数值进行计算得出的,所以不能保证100%的准确性。在实际操作中,可能会存在一些不同的图片被误判为重复图片,或者相同的图片被误判为不同图片的情况。因此,在删除重复图片之前,建议先备份图片并进行人工审核,确保没有误删重要的图片。

2.2 基于模板查找图片

基于模板查找图片是在给定模版图片的情况下,到图像数据库下查找出类似的图片。在本次任务重,模版图片为没有钢卷的图像(图像数据库的图像基本分为有钢卷和无钢卷)。

根据实际数据情况,将数据分为有钢卷和没钢卷,因为钢卷在图像的中心,所以不需要计算周围的相似区域(相似区域会混淆hash值)。故此,我们定义chash函数,其步骤如下,具体如下图所示。
1、将图像resize到固定尺寸
2、截取出图像的中心区域
3、计算图像中心区域的ahash值(可以根据效果调整,选择其他的hash算法
在这里插入图片描述
根据模版图片删除相似图片的步骤如下:

  • 1、获取文件夹内所有图片 => all_list
  • 2、读取模版图片 => temp_mat
  • 3、计算模版图片chash值 => temp_hash 根据个人数据情况使用hash算法,如ahash、dhash、phash等
  • 4、计算每一个图片hash值 =>img_hash
  • 5、将all_list里面的图片hash值(img_hash)和模版图片hash值(temp_hash)进行对比,相同则移动到temp文件夹内

完整代码如下


import cv2,os
import numpy as np
# 均值哈希算法
def ahash(image):
    # 将图片缩放为8*8的
    image =  cv2.resize(image, (8,8), interpolation=cv2.INTER_CUBIC)
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    # s为像素和初始灰度值,hash_str为哈希值初始值
    s = 0
    ahash_str = ''
    # 遍历像素累加和
    for i in range(8):
        for j in range(8):
            s = s+gray[i, j]
    # 计算像素平均值
    avg = s/64
    # 灰度大于平均值为1相反为0,得到图片的平均哈希值,此时得到的hash值为64位的01字符串
    ahash_str  = ''
    for i in range(8):
        for j in range(8):
            if gray[i,j]>avg:
                ahash_str = ahash_str + '1'
            else:
                ahash_str = ahash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x' % int(ahash_str[i: i + 4], 2))
    # print("ahash值:",result)
    return result
 
# 差异值哈希算法
def dhash(image):
    # 将图片转化为8*8
    image = cv2.resize(image,(9,8),interpolation=cv2.INTER_CUBIC )
    # 将图片转化为灰度图
    gray = cv2.cvtColor(image, cv2.COLOR_RGB2GRAY)
    dhash_str = ''
    for i in range(8):
        for j in range(8):
            if gray[i,j]>gray[i, j+1]:
                dhash_str = dhash_str + '1'
            else:
                dhash_str = dhash_str + '0'
    result = ''
    for i in range(0, 64, 4):
        result += ''.join('%x'%int(dhash_str[i: i+4],2))
    # print("dhash值",result)
    return result
 
# 计算hash值
def phash(img):
    img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
    img=img.astype(np.float32)

    #step2:离散余弦变换
    img=cv2.dct(img)
    img=img[0:8,0:8]
    sum=0.
    hash_str=''

    #step3:计算均值
    # avg = np.sum(img) / 64.0
    for i in range(8):
        for j in range(8):
            sum+=img[i,j]
    avg=sum/64

    #step4:获得哈希
    for i in range(8):
        for j in range(8):
            if img[i,j]>avg:
                hash_str=hash_str+'1'
            else:
                hash_str=hash_str+'0'
    return hash_str

# 中心hash算法 
def crop_center(image):
    image =  cv2.resize(image, (900,900))
    image=image[300:600,300:600]
    #image=image[350:550,350:550]
    return image
def chash(image):
    cimage=crop_center(image)
    hash_value=ahash(cimage)
    return hash_value

# 计算两个哈希值之间的差异
def campHash(hash1, hash2):
    n = 0
    # hash长度不同返回-1,此时不能比较
    if len(hash1) != len(hash2):
        return -1
    # 如果hash长度相同遍历长度
    for i in range(len(hash1)):
        if hash1[i] != hash2[i]:
            n = n+1
    return n



if __name__ == "__main__":
    #读取并计算模版图片中心的ahash值
    temp_mat='temp.jpg' #模版路径
    temp=cv2.imread(temp_mat)
    temp_hash = chash(temp)
    print('temp的ahash值',temp_hash)

    #创建temp文件夹,用于保存和模版相似的图片
    del_path="temp/"
    os.makedirs(del_path,exist_ok=True)

    #读取并计算文件夹内图片中心的ahash值
    img_path = "图片路径/"
    all_list=os.listdir(img_path)
    for p in all_list:
        img=cv2.imread(img_path+p)
        img_hash = chash(img)
        #计算图片和模版图片hash值的差异,并将差异小于10的图片移动到temp文件夹内
        dif= campHash(temp_hash,img_hash)
        #print('img的ahash值',dif,p)
        #continue
        if dif<10:
            print('img的ahash值',dif,p)
            os.rename(img_path+p,del_path+p)

图片路径中图片如下
在这里插入图片描述
temp.jpg 模版图片如下所示
在这里插入图片描述
代码执行完后找到的重复图像如下
在这里插入图片描述

代码执行时输出如下所示

img的ahash值 3 T2023-11-15_11-20-44.jpg
img的ahash值 2 T2023-11-15_12-23-59.jpg
img的ahash值 6 T2023-11-16_13-28-01.jpg
img的ahash值 7 T2023-11-16_21-48-58.jpg
img的ahash值 8 T2023-11-17_06-24-17.jpg
img的ahash值 7 T2023-11-18_11-00-37.jpg
img的ahash值 9 T2023-11-18_11-00-43.jpg
img的ahash值 6 T2023-11-18_11-55-30.jpg
img的ahash值 5 T2023-11-18_11-56-24.jpg
img的ahash值 9 T2023-11-18_11-57-40.jpg
img的ahash值 5 T2023-11-18_12-51-23.jpg
img的ahash值 5 T2023-11-18_12-52-17.jpg
img的ahash值 6 T2023-11-18_22-57-15.jpg
img的ahash值 8 T2023-11-18_23-11-26.jpg
img的ahash值 6 T2023-11-21_00-24-43.jpg
img的ahash值 5 T2023-11-21_13-37-37.jpg
img的ahash值 6 T2023-11-22_02-51-48.jpg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/298135.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

如何使用免费的ZeroSSL证书保护您的网站

使用 ZeroSSL 在您的站点上轻松实施 SSL。我们的指南涵盖了免费证书设置&#xff0c;确保安全和加密的用户连接。 如今&#xff0c;保护您的网站不仅是一种建议&#xff0c;而且是一种必需品。这就是SSL证书发挥作用的地方。它们对用户浏览器和网站之间传输的数据进行加密&…

Golang高质量编程与性能调优实战

1.1 简介 高质量&#xff1a;编写的代码能否达到正确可靠、简洁清晰的目标 各种边界条件是否考虑完备异常情况处理&#xff0c;稳定性保证易读易维护 编程原则 简单性 消除多余的重复性&#xff0c;以简单清晰的逻辑编写代码不理解的代码无法修复改进 可读性 代码是写给人看…

云原生学习系列之基础环境准备(单节点安装kubernetes)

一、环境要求 操作系统CentOS 7.x-86_x64 硬件配置&#xff1a;内存2GB或2G&#xff0c;CPU 2核或CPU 2核&#xff0c;需要在虚拟机中提前设置好&#xff0c;不然后续会报错 二、系统初始化 1、设置主机名 # 在master节点执行 hostnamectl set-hostname master01 2、配置主…

时间序列预测 — LSTM实现多变量多步负荷预测(Tensorflow):多输入多输出

目录 1 数据处理 1.1 导入库文件 1.2 导入数据集 ​1.3 缺失值分析 2 构造训练数据 3 LSTM模型训练 4 LSTM模型预测 4.1 分量预测 4.2 可视化 1 数据处理 1.1 导入库文件 import time import datetime import pandas as pd import numpy as np import matplotlib.p…

Kafka消息阻塞:拯救面试的八大终极解决方案!

大家好&#xff0c;我是小米&#xff0c;一个对技术充满热情的90后程序员。最近在准备社招面试的过程中&#xff0c;遇到了一个超级有挑战性的问题&#xff1a;“Kafka消息阻塞怎么解决&#xff1f;”今天&#xff0c;我就来和大家一起深入剖析这个问题&#xff0c;分享我在解决…

Python从入门到网络爬虫(MySQL链接)

前言 在实际数据分析和建模过程中&#xff0c;我们通常需要从数据库中读取数据&#xff0c;并将其转化为 Pandas dataframe 对象进行进一步处理。而 MySQL 数据库是最常用的关系型数据库之一&#xff0c;因此在 Python 中如何连接 MySQL 数据库并查询数据成为了一个重要的问题…

【MySQL四大引擎,数据库管理,数据表管理,数据库账号管理】

一. MySQL四大引擎 查看存储引擎 SHOW ENGINES support 字段说明 defaulti的为默认的引擎 为YES表示可以使用 为NO表示不能使用 四大引擎 InnoDB InnoDB表类型可以看作是对MyISAM的进一步更新产品&#xff0c;它提供了事务、行级锁机制和外键约束的功能&#xff0c;也是目前…

Python中的cls语法

在Python中&#xff0c;cls 是一个用于指代类本身的约定性名称&#xff0c;通常用作类方法&#xff08;class method&#xff09;中的第一个参数。cls 类似于 self&#xff0c;它是对类的引用&#xff0c;而不是对实例的引用。cls 通常在类方法中用于访问类级别的属性和方法。举…

智能门锁人脸识别好用监控不好用是怎么回事?

智能门锁的人脸识别和监控所用的主要硬件都是摄像头&#xff0c;如果二个功能都共用同一摄像头的话&#xff0c;所拍出来的图像清晰度应该是一样的&#xff0c;但有些智能锁可能并非如此&#xff0c;况且它们是两个不同的功能&#xff0c;所以成像的清晰度可能并不一样&#xf…

栅极驱动芯片三种隔离技术

栅极驱动芯片三种隔离技术 1.栅极驱动器概述2.隔离栅极驱动芯片2.1隔离驱动器重要指标 3.三种常见隔离技术3.1光隔离3.2变压器隔离/磁隔3.3电容隔离 4.三种隔离器性能对比 1.栅极驱动器概述 栅极驱动器&#xff0c;在任何功率水平为任何应用高效可靠地驱动任何功率开关。 比如M…

虾皮长尾词工具:如何使用关键词工具优化Shopee产品的长尾关键词

在Shopee&#xff08;虾皮&#xff09;平台上&#xff0c;卖家们都希望能够吸引更多的潜在买家&#xff0c;提高产品的曝光率和转化率。而要实现这一目标&#xff0c;了解和使用长尾关键词是非常重要的。本文将介绍长尾关键词的定义、重要性以及如何使用关键词工具来优化Shopee…

Spring Data JPA入门到放弃

参考文档&#xff1a;SpringData JPA&#xff1a;一文带你搞懂 - 知乎 (zhihu.com) 一、 前言 1.1 概述 Java持久化技术是Java开发中的重要组成部分&#xff0c;它主要用于将对象数据持久化到数据库中&#xff0c;以及从数据库中查询和恢复对象数据。在Java持久化技术领域&a…

leetcode经典【双指针】例题

删除有序数组中的重复项&#xff1a; https://leetcode.cn/problems/remove-duplicates-from-sorted-array/ 解题思路&#xff1a; 首先注意数组是有序的&#xff0c;那么重复的元素一定会相邻。 注: 要求删除重复元素&#xff0c;实际上就是将不重复的元素移到数组的左侧。 考…

18.标题统计

题目 import java.util.Scanner;public class Main {public static void main(String[] args) {Scanner sc new Scanner(System.in);String str sc.nextLine();int res 0;for(int i0;i<str.length();i) {char c str.charAt(i);if(c! && c!\n) {res;}}System.o…

BUUCTF--pwnable_start1

查看保护&#xff1a; 32位程序保护全没开&#xff0c;黑盒测试下效果&#xff1a; 存在栈溢出&#xff0c;那么这题的想法就是直接ret2shellcode了。IDA中看看具体流程&#xff1a; 出奇的少&#xff0c;这题不能看反汇编的代码&#xff0c;直接去看汇编&#xff1a; 主要就2个…

sql——窗口范围之partition by 与 order by

partition by 关键字 partition by 在开窗函数中&#xff0c;常用于表示某个分区&#xff0c;规则了数据的范围 order by 关键字 order by 常用于对分区内的数据进行排序&#xff0c;常见的情况下&#xff0c;order by还能规定sql语句的影响范围。 rows between unbounded …

kannegiesser触摸屏维修CTT-11 4PP420.1043-K37

贝加莱触摸屏维修4PP420.1043-K37 kannegiesser工控机触摸屏维修CTT-11 工控机触摸屏维修常见故障现象 1、工控机开机有显示&#xff0c;但是屏幕很暗&#xff0c;用调亮度功能键调试无任何变化&#xff1b; 2、工控机开机触摸屏白屏或花屏&#xff0c;但是外接显示器正常&a…

机器学习(四) -- 模型评估(3)

系列文章目录 机器学习&#xff08;一&#xff09; -- 概述 机器学习&#xff08;二&#xff09; -- 数据预处理&#xff08;1-3&#xff09; 机器学习&#xff08;三&#xff09; -- 特征工程&#xff08;1-2&#xff09; 机器学习&#xff08;四&#xff09; -- 模型评估…

【JAVA】volatile 关键字的作用

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 volatile 的作用&#xff1a; 结语 我的其他博客 前言 在多线程编程中&#xff0c;保障数据的一致性和线程之间的可见性是…

优化|PLSA理论与实践

PLSA又称为概率潜在语义分析&#xff0c;是一种利用概率生成模型对文本集合进行话题分析的无监督学习方法。该模型最大的特点是加入了主题这一隐变量&#xff0c;文本生成主题&#xff0c;主题生成单词&#xff0c;从而得到单词-文本共现矩阵。本文将对包含物理学、计算机科学、…