python opencv 图像对比_Python-OpenCV 14. 比较图片相似度

一、图片相似比较

本文介绍的几种实现方式:

暴力方式:1.按像素比较,n越小相似度越高;2.矩阵相减,用来判断两个图是不是完全一样;hashlib.md5判断两个图是否完全一样

哈希算法:1.感知哈希算法;2.均值哈希算法;3.差值哈希算法

灰度直方图:1.单通道直方图;2. 三通道直方图

二、暴力方式

1. 按像素比较

# -*- coding: utf-8 -*-

# !/usr/bin/python

import cv2

n = 0

img1 = cv2.imread('test.jpg', cv2.IMREAD_GRAYSCALE)

img2 = cv2.imread('test.png', cv2.IMREAD_GRAYSCALE)

height, width = img1.shape

for line in range(height):

for pixel in range(width):

if img1[line][pixel] != img2[line][pixel]:

n = n + 1

print(n)

2. OpenCV2 矩阵相减

两个图片完全一样时返回值为true

如果把一个图片转了格式,则结果可能不一样,因为转格式的过程中可能会进行算法处理

3. 通过hashlib.md5判断图片是否完全一样

import hashlib

a = open("test.png", "rb")

a_cp = open("test.jpg", 'rb')

cmd5 = hashlib.md5(a.read()).hexdigest()

ccmd5 = hashlib.md5(a_cp.read()).hexdigest()

print(cmd5)

if cmd5 == ccmd5:

print(True)

else:

print(False)

三、哈希算法

算法值越小,则越相似,相同图片值为0。

pHash:感知哈希。精确度比较高,但是速度方面较差一些。

aHash:平均值哈希。速度比较快,但是常常不太精确。

dHash:差异值哈希。精确度较高,且速度也非常快

1. 感知哈希算法(Perceptual hash algorithm)

步骤:

缩小图片

转为灰度图(256阶)

计算DCT:把图片分享成分率的集合,结果是32*32的矩阵

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

计算缩小DCT后的像素点均值

大于均值记为1,反之记为0,组合64个信息位

7 比较图片指纹,获得汉明距离,即两个64位的hash值有多少位是不一样的,不相同位数越少,图片越相似。

代码

import cv2

import numpy as np

from itertools import chain

def pHash(img_name):

"""

get image pHash value

"""

# 加载并调整图片为32x32灰度图片

img = cv2.imread(img_name, 0)

img = cv2.resize(img, (64, 64), interpolation=cv2.INTER_CUBIC)

# 创建二维列表

h, w = img.shape[:2]

vis0 = np.zeros((h, w), np.float32)

vis0[:h, :w] = img # 填充数据

# 二维Dct变换

vis1 = cv2.dct(cv2.dct(vis0))

vis1.resize((32, 32), refcheck=False)

# 把二维list变成一维list

img_list = list(chain.from_iterable(vis1))

# 计算均值

avg = sum(img_list) * 1. / len(img_list)

avg_list = ['0' if i < avg else '1' for i in img_list]

# 得到哈希值

return ''.join(['%x' % int(''.join(avg_list[x:x + 4]), 2) for x in range(0, 32 * 32, 4)])

def hammingDist(s1, s2):

"""

计算两张图片的汉明距离

"""

assert len(s1) == len(s2)

return sum([ch1 != ch2 for ch1, ch2 in zip(s1, s2)])

if __name__ == '__main__':

HASH1 = pHash('test.jpg')

HASH2 = pHash('test.png')

distance = hammingDist(HASH1, HASH2)

print('汉明距离=%f' % distance)

out_score = 1 - distance * 1. / (32 * 32 / 4)

print('相似度=%f' % out_score)

2. 均值哈希算法

缩放图片为8*8

转换为256阶灰度图。

计算灰度图所有像素的平均值。

比较:像素值大于平均值记作1,相反记作0,总共64位。

大于均值记为1,反之记为0,组合64个信息位

比较图片指纹,获得汉明距离,即两个64位的hash值有多少位是不一样的,不相同位数越少,图片越相似。

import cv2

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 cmpHash(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__":

# 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0

img1 = cv2.imread("test.jpg")

img2 = cv2.imread("test.png")

hash1 = aHash(img1)

hash2 = aHash(img2)

n1 = cmpHash(hash1, hash2)

print('均值哈希算法相似度aHash:', n1)

3. 差值哈希算法

在比较的一步:像素值大于后一个像素值记作1,相反记作0。本行不与下一行对比,每行9个像素,八个差值,有8行,总共64位

import cv2

# 差值感知算法

def dHash(img):

# 缩放8*8

img = cv2.resize(img, (9, 8), interpolation=cv2.INTER_CUBIC)

# 转换灰度图

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 cmpHash(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__":

# 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0

img1 = cv2.imread("test.jpg")

img2 = cv2.imread("test.png")

hash1 = dHash(img1)

hash2 = dHash(img2)

n1 = cmpHash(hash1, hash2)

print('均值哈希算法相似度aHash:', n1)

四、灰度直方图

1. 单通道的直方图相似比较

# -*- coding: utf-8 -*-

# !/usr/bin/python

import cv2

# 计算单通道的直方图的相似值

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

if __name__ == '__main__':

img1 = cv2.imread('test.jpg')

img2 = cv2.imread('test.png')

degree = calculate(img1, img2)

print(degree)

2. 计算每个通道的直方图来计算相似度

# -*- coding: utf-8 -*-

# !/usr/bin/python

import cv2

# 计算单通道的直方图的相似值

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

if __name__ == '__main__':

img1 = cv2.imread('test.jpg')

img2 = cv2.imread('test.png')

degree = classify_hist_with_split(img1, img2)

print(degree)

你可能感兴趣的:(python,opencv,图像对比)