利用多种方法实现,分析利弊
classify_gray_hist方法用来求最简单的灰度直方图来比较相似性,但是受图片颜色,大小影响较大
classify_hist_with_split方法是通过分析每个通道的直方图来比较,缺点同上但精度有所提高
classify_aHash均值哈希,通过灰度平均值来实现比较,但是不太精确,若是图片稍微变灰或者是变亮,再如果是画的背景变成干扰有可能就不准确。
classify_dHash差值哈希,通过比较前一个像素与现在像素的区别形成hash值,基于渐变,准确度提高。
classify_pHash感知哈希,相比起来最准确,采用的是DCT(离散余弦变换)来DCT计算后的矩阵是32 * 32,保留左上角的8 * 8,这些代表的图片的最低频率降低频率的方法,计算缩小DCT后的所有像素点的平均值,效果最好
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @File : more.py
# @Author: 穆洪桥
# @Date : 2018/1/16
# @Desc :
# 利用python实现多种方法来实现图像识别
import cv2
import numpy as np
from matplotlib import 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)
#print(hash1)
#print(hash2)
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 get_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 classify_dHash(image1, image2):
d1=get_dhash(image1)
d2=get_dhash(image2)
return Hamming_distance(d1, d2)
# 计算汉明距离
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('image\\rurenhui7.png')
cv2.imshow('img1', img1)
img2 = cv2.imread('image\\rurenhui8.png')
cv2.imshow('img2', img2)
degree1 = classify_gray_hist(img1, img2)
degree2 = classify_hist_with_split(img1,img2)
degree3 = classify_aHash(img1,img2)
degree4 = classify_pHash(img1,img2)
degree5 = classify_dHash(img1, img2)
print(degree1)
print(degree2)
print(degree3)
print(degree4)
print(degree5)
cv2.waitKey(0)
通过测试,最好的准确度是phash,但是缺少样本,无法确定临界值与准确率之间的对照比例。