首页 > 编程语言 >Python计算两图相似性-哈希算法(Hash)

Python计算两图相似性-哈希算法(Hash)

时间:2024-02-20 10:55:17浏览次数:30  
标签:Hash str Python cv2 直方图 两图 算法 哈希 hash

1、简介

aHash:平均值哈希。速度比较快,但是常常不太精确。
pHash:感知哈希。精确度比较高,但是速度方面较差一些。
dHash:差异值哈希。精确度较高,

均值哈希算法、差值哈希算法和感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的hash值有多少不同。
三直方图和单通道直方图的值为0-1,值越大,相似度越高。

 

2、代码

原文链接:https://zhuanlan.zhihu.com/p/93893211

# -*- coding:UTF-8 -*-

"""

哈希算法计算图片的相似度

aHash:平均值哈希。速度比较快,但是常常不太精确。
pHash:感知哈希。精确度比较高,但是速度方面较差一些。
dHash:差异值哈希。精确度较高,

均值哈希算法、差值哈希算法和感知哈希算法都是值越小,相似度越高,取值为0-64,即汉明距离中,64位的hash值有多少不同。
三直方图和单通道直方图的值为0-1,值越大,相似度越高。

"""

# 解决 requests InsecureRequestWarning: Unverified HTTPS 报错
import urllib3
urllib3.disable_warnings()

import cv2
import numpy as np
from PIL import Image
import requests
from io import BytesIO
import matplotlib

matplotlib.use('TkAgg')
import matplotlib.pyplot as plt


def aHash(img):
    # 均值哈希算法
    # 缩放为8*8
    img = cv2.resize(img, (8, 8))
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # s为像素和初值为0,hash_str为hash值初值为''
    s = 0
    hash_str = ''
    # 遍历累加求像素和
    for i in range(8):
        for j in range(8):
            s = s + gray[i, j]
    # 求平均灰度
    avg = s / 64
    # 灰度大于平均值为1相反为0生成图片的hash值
    for i in range(8):
        for j in range(8):
            if gray[i, j] > avg:
                hash_str = hash_str + '1'
            else:
                hash_str = hash_str + '0'
    return hash_str


def dHash(img):
    # 差值哈希算法
    # 缩放8*8
    img = cv2.resize(img, (9, 8))
    # 转换灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    hash_str = ''
    # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if gray[i, j] > gray[i, j + 1]:
                hash_str = hash_str + '1'
            else:
                hash_str = hash_str + '0'
    return hash_str


def pHash(img):
    # 感知哈希算法
    # 缩放32*32
    img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBIC

    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 将灰度图转为浮点型,再进行dct变换
    dct = cv2.dct(np.float32(gray))
    # opencv实现的掩码操作
    dct_roi = dct[0:8, 0:8]

    hash = []
    avreage = np.mean(dct_roi)
    for i in range(dct_roi.shape[0]):
        for j in range(dct_roi.shape[1]):
            if dct_roi[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)
    return hash


def calculate(image1, image2):
    # 灰度直方图算法
    # 计算单通道的直方图的相似值
    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
    # 计算直方图的重合度
    degree = 0
    for i in range(len(hist1)):
        if hist1[i] != hist2[i]:
            degree = degree + \
                     (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    return degree


def classify_hist_with_split(image1, image2, size=(256, 256)):
    # RGB每个通道的直方图相似度
    # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
    image1 = cv2.resize(image1, size)
    image2 = cv2.resize(image2, size)
    sub_image1 = cv2.split(image1)
    sub_image2 = cv2.split(image2)
    sub_data = 0
    for im1, im2 in zip(sub_image1, sub_image2):
        sub_data += calculate(im1, im2)
    sub_data = sub_data / 3
    return sub_data


def cmpHash(hash1, hash2):
    # Hash值对比
    # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
    # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
    # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
    n = 0
    # hash长度不同则返回-1代表传参出错
    if len(hash1) != len(hash2):
        return -1
    # 遍历判断
    for i in range(len(hash1)):
        # 不相等则n计数+1,n最终为相似度
        if hash1[i] != hash2[i]:
            n = n + 1
    return n


def getImageByUrl(url):
    # 根据图片url 获取图片对象
    html = requests.get(url, verify=False)
    image = Image.open(BytesIO(html.content))
    return image


def runAllImageSimilaryFun(para1, para2):
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1

    # t1,t2   14;19;10;  0.70;0.75
    # t1,t3   39 33 18   0.58 0.49
    # s1,s2  7 23 11     0.83 0.86  挺相似的图片
    # c1,c2  11 29 17    0.30 0.31

    if para1.startswith("http"):
        # 根据链接下载图片,并转换为opencv格式
        img1 = getImageByUrl(para1)
        img1 = cv2.cvtColor(np.asarray(img1), cv2.COLOR_RGB2BGR)

        img2 = getImageByUrl(para2)
        img2 = cv2.cvtColor(np.asarray(img2), cv2.COLOR_RGB2BGR)
    else:
        # 通过imread方法直接读取物理路径
        img1 = cv2.imread(para1)
        img2 = cv2.imread(para2)

    hash1 = aHash(img1)
    hash2 = aHash(img2)
    n1 = cmpHash(hash1, hash2)
    print('均值哈希算法相似度aHash:', n1)

    hash1 = dHash(img1)
    hash2 = dHash(img2)
    n2 = cmpHash(hash1, hash2)
    print('差值哈希算法相似度dHash:', n2)

    hash1 = pHash(img1)
    hash2 = pHash(img2)
    n3 = cmpHash(hash1, hash2)
    print('感知哈希算法相似度pHash:', n3)

    n4 = classify_hist_with_split(img1, img2)
    print('三直方图算法相似度:', n4)

    n5 = calculate(img1, img2)
    print("单通道的直方图", n5)
    print("%d %d %d %.2f %.2f " % (n1, n2, n3, round(n4[0], 2), n5[0]))
    print("%.2f %.2f %.2f %.2f %.2f " % (1 - float(n1 / 64), 1 -
                                         float(n2 / 64), 1 - float(n3 / 64), round(n4[0], 2), n5[0]))

    plt.subplot(121)
    plt.imshow(Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)))
    plt.subplot(122)
    plt.imshow(Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)))
    plt.show()


if __name__ == "__main__":

    p1 = "WD1.png"
    p2 = "WD2.png"

    runAllImageSimilaryFun(p1, p2)

 

标签:Hash,str,Python,cv2,直方图,两图,算法,哈希,hash
From: https://www.cnblogs.com/TSmagic/p/17875387.html

相关文章

  • 4-Redis十大关系之哈希Hash
    Redis十大关系之哈希Hash:Map<String,Map<Object,Object>>HSETkeyfieldvaluefieldvalue...:设置属性值HGETkeyfield:获取对应属性值HGETALLkey:遍历哈希HDELkeyfield:删除field对应的属性HLENkey:获取某个key内的全部数量HEXISTSkeyfield:判断key中有没有fie......
  • PC应用程序自动化(python)
    个人向笔记。看的是BV14Y4y1z7z6这个视频。假期感兴趣看了一点点,感觉和我的日常工作匹配度不太高,所以先记录到这里,后面再补充。 PC自动化--pywinauto0、前置0.1是个后端的访问。application:作用范围是一个进程; desktop:作用范围可以跨进程。 0.2程序检测辅助工具 ......
  • python调用qq邮箱发送邮件
    代码如下,需要qq邮箱开启授权码importsmtplibfromemail.mime.textimportMIMETextfromemail.headerimportHeadermessage=MIMEText('邮件内容')#邮件内容message['From']=Header('[email protected]')#邮件发送者名字message['To']=Header(&#......
  • Java集合篇之set,面试官:请说一说HashSet、LinkedHashSet、TreeSet的区别?
    写在开头Java的集合世界中主要由List,Set,Queue,Map构成,我们在之前的博文中已经学习了List,接下来我们继续学习Set集合。Set特点:存取无序,不可以存放重复的元素,不可以用下标对元素进行操作HashSet作为Set容器的代表子类,HashSet经常被用到,我们通过源码去分析它【源码查看】public......
  • Ubuntu 安装 Python3.6.7
    注意:不要卸载ubuntu自带的python版本;ubuntu下不同版本的python可以共存,可直接安装python3.6。1.升级包索引和软件sudoaptupdatesudoaptupgrade-y2.安装编译所需包sudoaptinstallbuild-essentialzlib1g-devlibbz2-devlibncurses5-devlibgdbm-devlibns......
  • python的类机制
    python的类机制参考:python面向对象概念方法重写/覆盖:若从父类继承的方法不能满足子类的需求,可以对其进行改写。类变量:在实例化对象中是公用的,定义在类中,且在函数体之外,通常不作为实体变量使用。局部变量:定义在方法中的变量,只作用在当前实例。实例变量:在类的声明中,属性是......
  • Python asyncio
    asyncio作用提供了对携程的支持非阻塞:协程允许在等待异步操作的同时执行其他任务,而不会阻塞整个程序。轻量:相对于线程和进程,协程的开销较小,因为它们在单线程中执行。使用async/await语法:asyncdef声明协程函数,await用于等待异步操作的完成。事件循环:协程需要在事件循环......
  • Python生成词云--豆瓣电影短评(初学菜鸡版)
    Python生成词云--豆瓣电影短评(初学菜鸡版)目录Python生成词云--豆瓣电影短评(初学菜鸡版)1.主要涉及的库2.获取数据3.生成词云图1.主要涉及的库主要页面处理selenium数据处理,输出、读取CSVpandas、numpy对所有数据进行分词处理jieba处理图片,生成词云图word......
  • Python异步编程原理篇之IO多路复用模块selector
    selector简介selector是一个实现了IO复用模型的python包,实现了IO多路复用模型的select、poll和epoll等函数。它允许程序同时监听多个文件描述符(例如套接字),并在其中任何一个就绪时进行相应的操作。这样可以有效地管理并发I/O操作,提高程序的性能和资源利用率。本篇主要......
  • Python Paramiko模块-exec_command() 和 invoke_shell() 两种操作方式
    前言Paramiko是Python语言的一个SSH客户端。可以远程连接Linux服务器,通过python对Linux进行操作,可以实现进行对远程服务器进行下载和上传文件操作。exec_command()操作importparamikossh=paramiko.SSHClient()ssh.set_missing_host_key_policy(paramiko.AutoAd......