+
80
-

python如何实现图片相似度检测?

python如何实现图片相似度检测?

网友回复

+
0
-

可以通过直方图

#!/usr/local/python3/bin/python3
# -*- coding: utf-8 -*
from PIL import Image
 
# 将图片转化为RGB
def make_regalur_image(img, size=(64, 64)):
    gray_image = img.resize(size).convert('RGB')
    return gray_image
 
# 计算直方图
def hist_similar(lh, rh):
    assert len(lh) == len(rh)
    hist = sum(1 - (0 if l == r else float(abs(l-r))/max(l,r))for l, r in zip(lh, rh))/len(lh)
    return hist
 
# 计算相似度
def calc_similar(li, ri):
    calc_sim = hist_similar(li.histogram(), ri.histogram())
    return calc_sim
 
if __name__ == '__main__':
    image1 = Image.open('/data/wwwroot/default/asset/testimg1.png')
    image1 = make_regalur_image(image1)
    image2 = Image.open('/data/wwwroot/default/asset/testimg2.png')
    image2 = make_regalur_image(image2)
    print("相似度",calc_similar(image1, image2))
 
 

+
0
-

有以下几种方式实现图片相似度检测

直方图计算法 在python中可以依靠Image对象的histogram()方法获取其直方图数据,但这个方法返回的结果是一个列表,如果想得到下图可视化数据,需要另外使用 matplotlib,这里因为主要介绍算法思路,matplotlib的使用这里不做介绍。 是的,我们可以明显的发现,两张图片的直方图是近似重合的。所以利用直方图判断两张图片的是否相似的方法就是,计算其直方图的重合程度即可。 计算方法如下:

其中gi和si是分别指两条曲线的第i个点。 最后计算得出的结果就是就是其相似程度。 不过,这种方法有一个明显的弱点,就是他是按照颜色的全局分布来看的,无法描述颜色的局部分布和色彩所处的位置。 也就是假如一张图片以红色为主,内容是面旗帜,而另外一张图片也是红色为主,但是内容却是妹子穿了红色裙子,那么这个算法也很可能认为这两张图片的相似的。 缓解这个弱点有一个方法就是利用Image的crop方法把图片等分,然后再分别计算其相似度,最后综合考虑。 图像指纹与汉明距离

在介绍下面其他判别相似度的方法前,先补充一些概念。第一个就是图像指纹 图像指纹和人的指纹一样,是身份的象征,而图像指纹简单点来讲,就是将图像按照一定的哈希算法,经过运算后得出的一组二进制数字。 说到这里,就可以顺带引出汉明距离的概念了。 假如一组二进制数据为101,另外一组为111,那么显然把第一组的第二位数据0改成1就可以变成第二组数据111,所以两组数据的汉明距离就为1 简单点说,汉明距离就是一组二进制数据变成另一组数据所需的步骤数,显然,这个数值可以衡量两张图片的差异,汉明距离越小,则代表相似度越高。汉明距离为0,即代表两张图片完全一样。 如何计算得到汉明距离,情况下面三种哈希算法 平均哈希法(aHash)

此算法是基于比较灰度图每个像素与平均值来实现的 一般步骤 1.缩放图片,可利用Image对象的resize(size)改变,一般大小为8*8,64个像素值。

2.转化为灰度图

转灰度图的算法。

1.浮点算法:Gray=Rx0.3+Gx0.59+Bx0.11

2.整数方法:Gray=(Rx30+Gx59+Bx11)/100

3.移位方法:Gray =(Rx76+Gx151+Bx28)>>8;

4.平均值法:Gray=(R+G+B)/3;

5.仅取绿色:Gray=G;

在python中,可用Image的对象的方法convert('L')直接转换为灰度图

3.计算平均值:计算进行灰度处理后图片的所有像素点的平均值。

4.比较像素灰度值:遍历灰度图片每一个像素,如果大于平均值记录为1,否则为0.

5.得到信息指纹:组合64个bit位,顺序随意保持一致性。

最后比对两张图片的指纹,获得汉明距离即可。 感知哈希算法(pHash)

平均哈希算法过于严格,不够精确,更适合搜索缩略图,为了获得更精确的结果可以选择感知哈希算法,它采用的是DCT(离散余弦变换)来降低频率的方法 一般步骤: 缩小图片:32 * 32是一个较好的大小,这样方便DCT计算

转化为灰度图:把缩放后的图片转化为256阶的灰度图。(具体算法见平均哈希算法步骤)

计算DCT:DCT把图片分离成分率的集合

缩小DCT:DCT是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率

计算平均值:计算缩小DCT后的所有像素点的平均值。

进一步减小DCT:大于平均值记录为1,反之记录为0.

得到信息指纹:组合64个信息位,顺序随意保持一致性。

最后比对两张图片的指纹,获得汉明距离即可。 这里给出别人的DCT的介绍和计算方法(离散余弦变换的方法) 相比pHash,dHash的速度要快的多,相比aHash,dHash在效率几乎相同的情况下的效果要更好,它是基于渐变实现的。 步骤: 缩小图片:收缩到9*8的大小,一遍它有72的像素点

转化为灰度图:把缩放后的图片转化为256阶的灰度图。(具体算法见平均哈希算法步骤)

计算差异值:dHash算法工作在相邻像素之间,这样每行9个像素之间产生了8个不同的差异,一共8行,则产生了64个差异值

获得指纹:如果左边的像素比右边的更亮,则记录为1,否则为0.

最后比对两张图片的指纹,获得汉明距离即可。

完整代码

#- * -coding: utf - 8 -请在python3下运行
import cv2
import numpy as np
import matplotlib.pyplot as plt# 最简单的以灰度直方图作为相似比较的实现
def classify_gray_hist(image1, image2, size = (256, 256)): #先计算直方图# 几个参数必须用方括号括起来# 这里直接用灰度图计算直方图, 所以是使用第一个通道,# 也可以进行通道分离后, 得到多个通道的直方图# bins 取为16
    image1 = cv2.resize(image1, size)
    image2 = cv2.resize(image2, size)
    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])# 可以比较下直方图
    plt.plot(range(256), hist1, 'r')
    plt.plot(range(256), hist2, 'b')
    plt.show()# 计算直方图的重合度
    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 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)):
#将图像resize后, 分离为三个通道, 再计算每个通道的相似值
    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 classify_aHash(image1, image2):
    image1 = cv2.resize(image1, (8, 8))
    image2 = cv2.resize(image2, (8, 8))
    gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)
    hash1 = getHash(gray1)
    hash2 = getHash(gray2)
    return Hamming_distance(hash1, hash2)
def classify_pHash(image1, image2):
    image1 = cv2.resize(image1, (32, 32))
    image2 = cv2.resize(image2, (32, 32))
    gray1 = cv2.cvtColor(image1, cv2.COLOR_BGR2GRAY)
    gray2 = cv2.cvtColor(image2, cv2.COLOR_BGR2GRAY)# 将灰度图转为浮点型, 再进行dct变换
    dct1 = cv2.dct(np.float32(gray1))
    dct2 = cv2.dct(np.float32(gray2))
    # 取左上角的8 * 8, 这些代表图片的最低频率# 这个操作等价于c++中利用opencv实现的掩码操作# 在python中进行掩码操作, 可以直接这样取出图像矩阵的某一部分
    dct1_roi = dct1[0: 8, 0: 8]
    dct2_roi = dct2[0: 8, 0: 8]
    hash1 = getHash(dct1_roi)
    hash2 = getHash(dct2_roi)
    return Hamming_distance(hash1, hash2)# 输入灰度图, 返回hash
def getHash(image):
    avreage = np.mean(image)
    hash = []
    for i in range(image.shape[0]):
        for j in range(image.shape[1]):
            if image[i, j] > avreage:
                hash.append(1)
            else :
                hash.append(0)
    return hash# 计算汉明距离
def Hamming_distance(hash1, hash2):
    num = 0
    for index in range(len(hash1)):
        if hash1[index] != hash2[index]:
            num += 1
    return num
if __name__ == '__main__':
    img1 = cv2.imread('/data/wwwroot/default/asset/testimg1.png')
   #cv2.imshow('img1', img1)
    img2 = cv2.imread('/data/wwwroot/default/asset/testimg2.png')
  #cv2.imshow('img2', img2)
    degree = classify_gray_hist(img1, img2)
    #degree = classify_hist_with_split(img1,img2) 
    #degree = classify_aHash(img1,img2) 
    #degree = classify_pHash(img1,img2) 
    print(degree)
    cv2.waitKey(0)

+
0
-

使用 VGG16 模型从图像中提取特征并计算它们之间的相似度分数。 我们首先导入必要的库,初始化 VGG16 模型,并定义用于加载和处理图像、计算其嵌入以及计算相似性分数的函数。

import numpy as np 
from PIL import Image
from tensorflow.keras.preprocessing import image

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

from keras.applications.vgg16 import VGG16
from sklearn.metrics.pairwise import cosine_similarity

vgg16 = VGG16(weights='imagenet', include_top=False, 
              pooling='max', input_shape=(224, 224, 3))

# print the summary of the model's architecture.
vgg16.summary()
for model_layer in vgg16.layers:
  model_layer.trainable = False

#输入图像预处理

def load_image(image_path):
    """
        -----------------------------------------------------
        Process the image provided. 
        - Resize the image 
        -----------------------------------------------------
        return resized image
    """

    input_image = Image.open(image_path)
    resized_image = input_image.resize((224, 224))

    return resized_image

#、输入图像嵌入向量计算
def get_image_embeddings(object_image : image):
    
    """
      -----------------------------------------------------
      convert image into 3d array and add additional dimension for model input
      -----------------------------------------------------
      return embeddings of the given image
    """

    image_array = np.expand_dims(image.img_to_array(object_image), axis = 0)
    image_embedding = vgg16.predict(image_array)

    return image_embedding

#、余弦相似度计算
def get_similarity_score(first_image : str, second_image : str):
    """
        -----------------------------------------------------
        Takes image array and computes its embedding using VGG16 model.
        -----------------------------------------------------
        return embedding of the image
        
    """

    first_image = load_image(first_image)
    second_image = load_image(second_image)

    first_image_vector = get_image_embeddings(first_image)
    second_image_vector = get_image_embeddings(second_image)
    
    similarity_score = cosine_similarity(first_image_vector, second_image_vector).reshape(1,)

    return similarity_score

#、图像显示
def show_image(image_path):
  image = mpimg.imread(image_path)
  imgplot = plt.imshow(image)
  plt.show()

#、两个图像的比较

# define the path of the images
sunflower = '/content/sunflower.jpeg'
helianthus = '/content/helianthus.jpeg'

tulip = '/content/Tulip.jpeg'

# use the show_image function to plot the images
show_image(sunflower), show_image(helianthus)

然后,我们将这些函数应用于一组图像,并使用各种技术将结果可视化。 总体而言,该项目展示了如何利用 VGG16 等深度学习模型来执行复杂的图像分析任务并从视觉数据中生成见解。
我知道答案,我要回答