图片相似度计算

计算图片的相似度方法1 + hash_img

计算方法

1、图片缩放为10×10(缩放比例因图片大小而异)
2、读取每一点灰度化后的像素
3、计算每一行的像素平均值
4、生成特征序列
每一点的像素所在行的像素平均值作比较

  • 如果大于像素平均值,则特征序列+‘1’,反之**+‘0’**
  • 最后得到的特征序列,是由 1 和 0 组成的字符串(如:11001101101111001)

5、对比两张图片的特征序列

  • 相同的位数越多,图片相似度越高
  • 把相似度定义为:相似度 = 特征序列相同的位数➗特征序列长度

代码实现

from PIL import Image

def hash_img(img):#计算图片的特征序列
    a=[]#存储图片的像素
    hash_img=''#特征序列
    width,height=10,10#图片缩放大小
    img=img.resize((width,height))#图片缩放为width×height
    
    for y in range(img.height):
        b=[]
        for x in range(img.width):
            pos=x,y
            color_array = img.getpixel(pos)#获得像素
            color=sum(color_array)/3#灰度化
            b.append(int(color))
        a.append(b)
        
    for y in range(img.height):
        avg=sum(a[y])/len(a[y])#计算每一行的像素平均值
        for x in range(img.width):
            if a[y][x]>=avg:#生成特征序列,如果此点像素大于平均值则为1,反之为0
                hash_img+='1'
            else:
                hash_img+='0'
                
    return hash_img
    
    
def similar(img1,img2): #求相似度
    hash1=hash_img(img1) #计算img1的特征序列
    hash2=hash_img(img2) #计算img2的特征序列
    
    differnce=0
    for i in range(len(hash1)):
        differnce+=abs(int(hash1[i])-int(hash2[i]))
    similar=1-(differnce/len(hash1))
    
    return similar

img1=Image.open('1.png')
img2=Image.open('2.png')
print('%.1f%%' % (similar(img1,img2) * 100))
  • 示例:
img1=Image.open('1.png')
img2=Image.open('2.png')
print('%.1f%%' % (similar(img1,img2) * 100))
img3=Image.open('3.png')
img4=Image.open('4.png')
print('%.1f%%' % (similar(img3,img4) * 100))

输出:

61.0%
89.0%

1.png和2.png的相似度为61%
3.png和4.png的相似度为89%


计算图片的相似度方法2 + 比较每个像素点的RGB值是否在阈值范围内

  • 记录相同像素点个数
  • 记录不同像素点个数
  • 记录所有像素点个数
    - 相同像素点比例
  • 不同像素点比例

判断两个像素是否相同

  • 取两个图片像素点
  • 比较每个像素点的RGB值是否在阈值范围
  1. abs(piex1[0] - piex2[0]) < threshold
  2. abs(piex1[1]- piex2[1]) < threshold
  3. abs(piex1[2] - piex2[2]) < threshold
  • 若两张图片的RGB值都在某一阈值内,则认为它的像素点是一样的

代码实现

from PIL import Image
import time

def pixel_equal(image1, image2, x, y):
    """
    判断两个像素是否相同
    :param image1: 图片1
    :param image2: 图片2
    :param x: 位置x
    :param y: 位置y
    :return: 像素是否相同
    """
    # 取两个图片像素点
    piex1 = image1.load()[x, y]
    piex2 = image2.load()[x, y]
    threshold = 10
    # 比较每个像素点的RGB值是否在阈值范围内,若两张图片的RGB值都在某一阈值内,则我们认为它的像素点是一样的
    if abs(piex1[0] - piex2[0]) < threshold and abs(piex1[1]- piex2[1]) < threshold and abs(piex1[2] - piex2[2]) < threshold:
        return True
    else:
        return False

def compare(image1, image2):
    """
    进行比较
    :param image1:图片1
    :param image2: 图片2
    :return:
    """
    left = 0		# 坐标起始位置
    right_num = 0	# 记录相同像素点个数
    false_num = 0	# 记录不同像素点个数
    all_num = 0		# 记录所有像素点个数
    for i in range(left, image1.size[0]):
        for j in range(image1.size[1]):
            if pixel_equal(image1, image2, i, j):
                right_num += 1
            else:
                false_num += 1
            all_num += 1
    same_rate = right_num / all_num		# 相同像素点比例
    nosame_rate = false_num / all_num	# 不同像素点比例
    print("same_rate: ", same_rate)
    print("nosame_rate: ", nosame_rate)



if __name__ == "__main__":
    t1 = time.time()
    image1 = Image.open("./out0321_320.jpg")
    image2 = Image.open("./out0321_640.jpg")
    compare(image1, image2)
    t2 = time.time()
    print("t=", t2-t1)


结构性相似度SSIM

  • ssim结合了亮度,对比度,结构信息
  • 算法相对复杂,可以使用skimage进行使用
def ssim(img1, img2):
    width = img1.shape[1]
    win_size = int(width/2-((width/2) % 2)+1)
    out = structural_similarity(img1, img2, win_size=win_size, multichannel=True)
    return out if out > 0 else 0


距离度量(6种)

  1. 欧几里得距离(Euclidean Distance)以及欧式距离的标准化(Standardized Euclidean distance)
  2. 明可夫斯基距离(Minkowski Distance)
  3. 曼哈顿距离(Manhattan Distance)
  4. 切比雪夫距离(Chebyshev Distance)
  5. 马哈拉诺比斯距离(Mahalanobis Distance)
  6. 海明距离(Hamming distance)

相似度度量(9种)

相似度度量(Similarity),即计算个体间的相似程度

  • 与距离度量相反,相似度度量的值越小,说明个体间相似度越小,差异越大
  1. 余弦相似度 (Cosine Similarity)
  2. 调整余弦相似度 (Adjusted Cosine Similarity)
  3. 皮尔森相关系数 (Pearson Correlation Coefficient)
  4. Jaccard相似系数 (Jaccard Coefficient)
  5. Tanimoto系数(广义Jaccard相似系数)
  6. 对数似然相似率
  7. 互信息/信息增益,相对熵/KL散度
  8. 信息检索–词频-逆文档频率(TF-IDF)
  9. 词对相似度–点间互信息

图像相似度比较算法

  1. 全局比较算法
  • 全局比较算法表示算法计算整体图片的特征后,使用此特征进行匹配
  • 常见如hash类算法,hist直方图算法,ssim结构相似度算法

平均hash

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

感知hash

def pHash(img, shape=(10, 10)):
    # 缩放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:10, 0:10]

    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

比较hash指获取相似度

def cmpHash(hash1, hash2, shape=(10, 10)):
    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/(shape[0]*shape[1])


  1. 局部信息相似度比较
  • 局部信息的相似度比较,主要使用sift,orb等关键点的信息进行匹配
  • 具有一定的尺度不变性和旋转不变性
  • 能适应比较图片存在一定位移的情况
  • orb相比sift等拥有更高的性能,ORB
def ORB_siml(img1, img2, params):

    # 初始化ORB检测器
    orb = cv2.ORB_create(nfeatures=200)

    kp1, des1 = orb.detectAndCompute(img1, None)
    kp2, des2 = orb.detectAndCompute(img2, None)

    # 使用汉明距离对特侦点距离进行计算
    bf = cv2.BFMatcher(cv2.NORM_HAMMING)

    # 使用knn算法进行匹配
    matches = bf.knnMatch(des1, trainDescriptors=des2, k=2)

    # 去除模糊的匹配
    good = [(m, n) for (m, n) in matches if m.distance < 0.95 * n.distance and m.distance < 70]

    # 绘制匹配的关键点
    # img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good, img2, flags=2)

    similary = len(good) / len(matches)
    return similary


  1. 语义层面比较
  • 语义层面的比较,指的是基于深度学习预训练模型输出的特征进行比较
  • 因为基于imagenet的预训练模型,对图片有非常强的特征提取能力
  • 对于画面主体类别单一,变化较大但是类别相同的情况能较好的区分

基于moilenetv2模型的转换和使用:

import torch
import torchvision
import onnx
import onnxruntime as ort
from torchvision import transforms
from PIL import Image
import numpy as np

mobilev2 = torchvision.models.mobilenet_v2(pretrained=True)
new_classifier = torch.nn.Sequential(*list(mobilev2.children())[-1][:1])
mobilev2.classifier = new_classifier
mobilev2.eval()
torch.save(mobilev2 , "./mobilev2_1280.pt")
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
mobilev2_1280 = torch.load('mobilev2_1280.pt')
mobilev2_1280.to(device)
mobilev2_1280.eval()
img_dir = r'/home/whh/whh_train/Classification/000000.jpg'
img = Image.open(img_dir)
trans = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
cudaimg = trans(img)
cudaimg.unsqueeze_(dim=0)
cudaimg=cudaimg.cuda()
tensorimg = trans(img)
tensorimg = tensorimg[None,:]
out_1280 = mobilev2_1280(cudaimg)

你可能感兴趣的:(图像处理,深度学习,数据结构,算法)