在计算机视觉中如何识别两张图片是否相似,可以通过图像的像素值,根据颜色特征来识别是否为相似图片
计算图片的相似度方法
- 1.像素方差
- 1.1缩放图片
- 1.2灰度处理
- 1.3计算图像每行的平均值
- 1.4计算方差
- 1.5比较方差
- 2.哈希值计算
- 2.1平均值哈希
- 2.1.1图片缩放成8*8
- 2.1.2灰度化图像G
- 2.1.3计算整个灰度图像的像素平均值avg
- 2.1.4计算hash图像H
- 2.2感知哈希
- 2.2.1图片缩放32*32
- 2.2.2灰度化图像
- 2.2.3计算得到图像G的离散余弦变换的图像
- 2.2.4取
左上角8*8子图像
,计算这个图像中所有像素的平均值,假设其值为a
- 2.2.5计算hash图像H
- 2.3差异值哈希
- 2.3.1缩放图片9*8
- 2.3.2灰度化
- 2.3.3差异值计算
- 2.3.4计算hash图像H
- 2.3汉明距离计算
- 3.余弦距离计算
- 4.直方图计算
1.像素方差
1.1缩放图片
1.2灰度处理
1.3计算图像每行的平均值
1.4计算方差
计算所有行的平均值,并以此计算所有行的方差和
其中
1.5比较方差
代码中先使用yolov模型对图片进行了目标检测,提取出检测部分的图像,然后在对图像做相似度处理。
import cv2 as cv
import matplotlib.pyplot as plt
from yolo.yolo import yolo_detect
def detect(data):
x,y,w,h=yolo_detect(data)
image=cv.imread(data,cv.IMREAD_UNCHANGED)
print(x,y,w,h)
img=image[x:x+w,y:y+h]
return img
def imgavg(img):
sidelength=30
#缩放
img=cv.resize(img,(sidelength,sidelength),interpolation=cv.INTER_CUBIC)
#灰度化
gray=cv.cvtColor(img,cv.COLOR_BGR2GRAY)
#每行平均值
avglist=[]
for i in range(sidelength):
avg=sum(gray[i])/len(gray[i])
avglist.append(avg)
return avglist
def variance(avglist):
avg=sum(avglist)/len(avglist)
s=0
for i in avglist:
s+=(i-avg)*(i-avg)/len(avglist)
return s
data1='data/car1.jpg'
image1=cv.imread(data1,cv.IMREAD_UNCHANGED)
data2='data/car2.jpg'
image2=cv.imread(data2,cv.IMREAD_UNCHANGED)
img1=detect(data1)
img2=detect(data2)
avg1=imgavg(img1)
avg2=imgavg(img2)
print("两图片方差:%s"%(abs(variance(avg1)-variance(avg2))))
x=range(30)
plt.figure("兰博基尼")
plt.subplot(2,2,1)
plt.imshow(image1)
plt.subplot(2,2,2)
plt.plot(x,avg1,marker="*",label="$car1$")
plt.plot(x,avg2,marker="*",label="$car2$")
plt.legend()
plt.subplot(2,2,3)
plt.imshow(image2)
plt.legend()
plt.show()
2.哈希值计算
2.1平均值哈希
2.1.1图片缩放成8*8
image=cv.resize(img,(8,8),interpolation=cv.INTER_CUBIC)
2.1.2灰度化图像G
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
2.1.3计算整个灰度图像的像素平均值avg
s=0
for i in range(8):
for j in range(8):
s=s+gray[i,j]
avg=s/64
2.1.4计算hash图像H
初始化一张尺寸大小与灰度图像一样的hash图像,其中所有值为0,一行一行遍历图像。
如果图像中像素,则hash图像
。
如果图像中像素,则hash图像
。
得到图片的hash值后,一行行展开,得到一个二进制数,将二进制数转化为十六进制数,比较两张图片的十六七进制数的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。
汉明距离:两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数
hash_str=''
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'
result = ''
for i in range(0, 64, 4):
result += ''.join('%x' % int(hash_str[i: i + 4], 2))
# print("hash值:",result)
return result
2.2感知哈希
2.2.1图片缩放32*32
image=cv.resize(img,(32,32),interpolation=cv.INTER_CUBIC)
2.2.2灰度化图像%22%20aria-hidden%3D%22true%22%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-47%22%20x%3D%220%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-31%22%20x%3D%221112%22%20y%3D%22-213%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%3C%2Fsvg%3E)
gray=cv.cvtColor(image,cv.COLOR_BGR2GRAY)
2.2.3计算得到图像G的离散余弦变换的图像%22%20aria-hidden%3D%22true%22%3E%0A%20%3Cuse%20xlink%3Ahref%3D%22%23E1-MJMATHI-47%22%20x%3D%220%22%20y%3D%220%22%3E%3C%2Fuse%3E%0A%20%3Cuse%20transform%3D%22scale(0.707)%22%20xlink%3Ahref%3D%22%23E1-MJMAIN-32%22%20x%3D%221112%22%20y%3D%22-213%22%3E%3C%2Fuse%3E%0A%3C%2Fg%3E%0A%3C%2Fsvg%3E)
h, w = img.shape[:2]
vis0 = np.zeros((h, w), np.float32)
vis0[:h, :w] = image
# DCT二维变换
# 离散余弦变换,得到dct系数矩阵
img_dct = cv.dct(cv.dct(vis0))
2.2.4取
左上角8*8子图像
,计算这个图像中所有像素的平均值,假设其值为a
img_dct.resize(8, 8)
# 把list变成一维list
img_list = np.array().flatten(img_dct.tolist())
#均值计算
avg=cv.mean(img_list)
2.2.5计算hash图像H
初始化一张尺寸大小与灰度图像一样的hash图像,其中所有值为0,一行一行遍历图像。
如果图像中像素,则hash图像
。
如果图像中像素,则hash图像
。
得到图片的hash值后,一行行展开,得到一个二进制数,将二进制数转化为十六进制数,比较两张图片的十六七进制数的汉明距离,通常认为汉明距离小于10的一组图片为相似图片。
汉明距离:两个等长字符串之间的汉明距离是两个字符串对应位置的不同字符的个数
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, 64, 4)])
2.3差异值哈希
2.3.1缩放图片9*8
image = cv.resize(image, (9, 8), interpolation=cv2.INTER_CUBIC)
2.3.2灰度化
gray = cv.cvtColor(image, cv.COLOR_RGB2GRAY)
2.3.3差异值计算
当前行像素值与前一行像素值比较,如果大于前一行值,则,,反之为0 从第二到第九行共8行,又因为矩阵有8列,所以得到一个8x8差分矩阵
dhash_str = ''
for i in range(8):
for j in range(8):
if gray[i, j] > gray[i, j + 1]:
dhash_str = dhash_str + '1'
else:
dhash_str = dhash_str + '0'
2.3.4计算hash图像H
同上一样
result = ''
for i in range(0, 64, 4):
result += ''.join('%x' % int(dhash_str[i: i + 4], 2))
# print("hash值",result)
return result
2.3汉明距离计算
def campHash(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
3.余弦距离计算
把图像看成是一个矩阵向量,通过计算矩阵之间的余弦距离来表达两张图片的相似度。
4.直方图计算
- 通过cv2.calcHist()计算图像的直方图
- 通过cv2.compareHist()来比较以下两张图之间的相似度
import matplotlib.pyplot as plt
import cv2
import numpy as py
img = cv2.imread("data/car1.jpg")
img1 = cv2.imread("data/car2.jpg")
# 计算图img的直方图
H1 = cv2.calcHist([img], [1], None, [256],[0,256])
H1 = cv2.normalize(H1, H1, 0, 1, cv2.NORM_MINMAX, -1) # 对图片进行归一化处理
# 计算图img2的直方图
H2 = cv2.calcHist([img1], [1], None, [256],[0,256])
H2 = cv2.normalize(H2, H2, 0, 1, cv2.NORM_MINMAX, -1)
# 利用compareHist()进行比较相似度
similarity = cv2.compareHist(H1, H2,0)
print(similarity)
# img和img1直方图展示
H=[H1,H2]
for i in range(2):
plt.subplot(2,1,1+i)
plt.plot(H[i])
plt.show()
相似度:
0.14550932178252954