图像相似度计算【python】

一.利用直方图距离计算图片相似度

计算公式:

其中,G和S为两张图片的图像颜色分布直方图,N为颜色空间样点数。这里使用分块的方法计算相似度,用以提高各部分的特征,防止图片颜色相似导致计算的相似度高。

import matplotlib.pyplot as plt

# 正则化图像
def regularizeImage(img, size = (256, 256)):
    return img.resize(size).convert('RGB')

# 画出直方图图像
def drawHistogram(hg1, hg2):
    plt.plot(range(len(hg1)), hg1, color='blue', linewidth=1.5, label='img1')
    plt.plot(range(len(hg2)), hg2, color='red', linewidth=1.5, label='img2')
    plt.legend(loc='upper left')
    plt.title('Histogram Similarity')
    plt.show()

# 分块图像4x4
def splitImage(img, part_size = (64, 64)):
    w, h = img.size
    pw, ph = part_size
    data = []
    for i in range(0, w, pw):
        for j in range(0, h, ph):
            data.append(img.crop((i, j, i + pw, j + ph)).copy())
    return data

# 利用单块图片的直方图距离计算相似度
def calSingleHistogramSimilarity(hg1, hg2):
    if len(hg1) != len(hg2):
        raise Exception('样本点个数不一样')
    sum = 0
    for x1, x2 in zip(hg1, hg2):
        if x1 != x2:
            sum += 1 - float(abs(x1 - x2) / max(x1, x2))
        else:
            sum += 1
    return sum / len(hg1)

# 利用分块图片的直方图距离计算相似度
def calMultipleHistogramSimilarity(img1, img2):
    answer = 0
    for sub_img1, sub_img2 in zip(splitImage(img1), splitImage(img2)):
        answer += calSingleHistogramSimilarity(sub_img1.histogram(), sub_img2.histogram())
    return float(answer / 16.0)

—————————————————————————————————————————————————————————————————

二.利用平均哈希算法计算图片相似度

计算步骤:

1.缩放图片:一般大小为8*8,64个像素值
2.简化色彩,转化为灰度图:可以使用Image的convert('L')方法
3.计算平均值:计算出灰度图所有像素点的像素值的平均值
4.比较像素灰度值:遍历灰度图的每一个像素值与上一步计算的平均值,大于平均值记录为1,否则为0
5.得到64位图像指纹
6.记录两张图片的图像指纹的汉明距离,计算图片相似度
# 正则化图像
def regularizeImage(img, size = (8, 8)):
    return img.resize(size).convert('L')

# 计算hash值
def getHashCode(img, size = (8, 8)):

    pixel = []
    for i in range(size[0]):
        for j in range(size[1]):
            pixel.append(img.getpixel((i, j)))

    mean = sum(pixel) / len(pixel)

    result = []
    for i in pixel:
        if i > mean:
            result.append(1)
        else:
            result.append(0)
    
    return result

# 比较hash值
def compHashCode(hc1, hc2):
    cnt = 0
    for i, j in zip(hc1, hc2):
        if i == j:
            cnt += 1
    return cnt

# 计算平均哈希算法相似度
def calaHashSimilarity(img1, img2):
    img1 = regularizeImage(img1)
    img2 = regularizeImage(img2)
    hc1 = getHashCode(img1)
    hc2 = getHashCode(img2)
    return compHashCode(hc1, hc2)

__all__ = ['calaHashSimilarity']

—————————————————————————————————————————————————————————————————

三.利用感知哈希算法计算图片相似度

计算步骤:

3.1 缩放图片:一般大小为32*32,这样方便DCT计算
3.2 简化色彩,转化为灰度图:可以使用Image的convert('L')方法
3.3 计算DCT【离散余弦变换】
3.3.1 获得图像的二维数据矩阵f(x,y)
3.3.2 求离散余弦变换的系数矩阵[A]
3.3.3 求系数矩阵对应的转置矩阵[A]T
3.3.4 根据公式[F(u,v)]=[A][f(x,y)][A]T 计算离散余弦变换
3.4 缩小DCT:DCT计算后的矩阵是3232,保留左上角的88,这些代表的图片的最低频率
3.5 计算平均值:计算缩小DCT后的所有像素点的平均
3.6 进一步减小DCT:大于平均值记录为1,否则为0
3.7 得到64位信息指纹
3.8 记录两张图片的图像指纹的汉明距离,计算图片相似度
import math
import unittest

# 正则化图像
def regularizeImage(img, size = (32, 32)):
    return img.resize(size).convert('L')

# 获得图像像素矩阵
def getMatrix(img):
    matrix = []
    size = img.size
    for i in range(size[1]):
        pixel = []
        for j in range(size[0]):
            pixel.append(img.getpixel((j, i)))
        matrix.append(pixel)
    return matrix

# 计算系数矩阵
def getCoefficient(length):
    matrix = []
    sqr = 1.0 / math.sqrt(length)
    value = []
    for i in range(length):
        value.append(sqr)
    matrix.append(value)
    for i in range(1, length):
        value = []
        for j in range(0, length):
            value.append(math.sqrt(2.0 / length) * math.cos(i * math.pi * (j + 0.5) / length))
        matrix.append(value)
    return matrix

# 计算矩阵转秩
def getTranspose(matrix):
    new_matrix = []
    for i in range(len(matrix)):
        value = []
        for j in range(len(matrix[i])):
            value.append(matrix[j][i])
        new_matrix.append(value)
    return new_matrix

# 计算矩阵乘法
def getMultiply(matrix1, matrix2):
    new_matrix = []
    for i in range(len(matrix1)):
        value = []
        for j in range(len(matrix2[i])): 
            ans = 0.0
            for h in range(len(matrix1[i])):
                ans += matrix1[i][h] * matrix2[h][j]
            value.append(ans)
        new_matrix.append(value)
    return new_matrix

# 计算DCT
def DCT(matrix):
    length = len(matrix)
    A = getCoefficient(length)
    AT = getTranspose(A)
    temp = getMultiply(A, matrix)
    DCT_matrix = getMultiply(matrix, AT)
    return DCT_matrix

# 计算左上角8*8并转化为list
def submatrix_list(matrix, size = (8, 8)):
    value = []
    for i in range(size[0]):
        for j in range(size[1]):
            value.append(matrix[i][j])
    return value

# 计算hash值
def getHashCode(sub_list):
    length = len(sub_list)
    mean = sum(sub_list) / length
    
    result = []
    for i in sub_list:
        if i > mean:
            result.append(1)
        else:
            result.append(0)

    return result

# 比较hash值
def compHashCode(hc1, hc2):
    cnt = 0
    for i, j in zip(hc1, hc2):
        if i == j:
            cnt += 1
    return cnt

# 计算感知哈希算法相似度
def calpHashSimilarity(img1, img2):
    img1 = regularizeImage(img1)
    img2 = regularizeImage(img2)

    matrix1 = getMatrix(img1)
    matrix2 = getMatrix(img2)

    DCT1 = DCT(matrix1)
    DCT2 = DCT(matrix2)
    
    sub_list1 = submatrix_list(DCT1)
    sub_list2 = submatrix_list(DCT2)

    hc1 = getHashCode(sub_list1)
    hc2 = getHashCode(sub_list2)
    return compHashCode(hc1, hc2)

# 单元测试
class TestpHash(unittest.TestCase):
    def test_getHashCode(self):
        self.assertEqual(getHashCode([1, 2, 3]), [0, 0, 1])

if __name__ == '__main__':
    unittest.main()

__all__ = ['calpHashSimilarity']

—————————————————————————————————————————————————————————————————

四.利用差异哈希算法计算图片相似度

计算步骤:

4.1 缩放图片:一般大小为9*8,以留下多一行的像素数据进行差异计算
4.2 简化色彩,转化为灰度图:可以使用Image的convert('L')方法
4.3 计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异哈希值
4.4 得到64位信息指纹:如果左边的像素比右边的更亮,则记录为1,否则为0
4.5 记录两张图片的图像指纹的汉明距离,计算图片相似度
# 正则化图像
def regularizeImage(img, size = (9, 8)):
    return img.resize(size).convert('L')

# 计算hash值
def getHashCode(img, size = (9, 8)):

    result = []
    for i in range(size[0] - 1):
        for j in range(size[1]):
            current_val = img.getpixel((i, j))
            next_val = img.getpixel((i + 1, j))
            if current_val > next_val:
                result.append(1)
            else:
                result.append(0)
    
    return result

# 比较hash值
def compHashCode(hc1, hc2):
    cnt = 0
    for i, j in zip(hc1, hc2):
        if i == j:
            cnt += 1
    return cnt

# 计算差异哈希算法相似度
def caldHashSimilarity(img1, img2):
    img1 = regularizeImage(img1)
    img2 = regularizeImage(img2)
    hc1 = getHashCode(img1)
    hc2 = getHashCode(img2)
    return compHashCode(hc1, hc2)

__all__ = ['caldHashSimilarity']

转自另一位大佬,忘记地址了

©著作权归作者所有,转载或内容合作请联系作者
禁止转载,如需转载请通过简信或评论联系作者。
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,163评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,301评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,089评论 0 352
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,093评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,110评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,079评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,005评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,840评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,278评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,497评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,667评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,394评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,980评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,628评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,649评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,548评论 2 352

推荐阅读更多精彩内容