图片去重
需求分析
针对海量图片去重通常是如下思路
- 根据某种方法提取图片特征或者说指纹
- 根据提取出来的特征计算图片间的距离
- 根据距离调整阈值判断图片是否相似
1、提取指纹
常用的有如下方法:
- ahash
- phash
- dhash
ahash
- 将图片灰度
- 将图片resize为(w, h)大小
- 取图片均值mean
- 将图片中每个像素值与mean比较,大于为1否则为0
- 得(w, h)大小的图片指纹
phash
- 将图片灰度
- 对灰度后的图片取DCT变换
- 对DCT变换后的图片取左上角(w, h)大小的区域,即为新的图片
- 对图取mean
- 将图中每个元素与mean比较,大于为1否则为0
- 得(w, h)大小的图片指纹
dhash
- 将图片resize成(w, h+1, h)大小
- 将图片灰度
- 对于图像中的每一行,相邻的两个元素后面的减去前面的元素,若大于则为1否则为0
- 得到(w, h)大小的图片指纹
二、实现代码如下:
import os
import traceback
from PIL import Image
import numpy as np
from scipy.fftpack import dct
from scipy.spatial.distance import pdist
class ImgHash():
def __init__(self, path, hash_size=(8, 8)):
self.hash_size = hash_size
self.img = np.asarray(Image.open(path))
self.gray = self.img2gray(self.img)
@staticmethod
def img2gray(img):
r = img[:, :, 0]
g = img[:, :, 1]
b = img[:, :, 2]
gray = 0.2989*r + 0.5807*g + 0.1140*b
return gray
def ahash(self):
img = np.resize(self.gray, new_shape=self.hash_size)
mean = np.mean(img)
hashed = (img > mean).astype(int)
return hashed
def phash(self):
img = dct(x=self.gray)[:self.hash_size[0], :self.hash_size[1]]
mean = np.mean(img)
hashed = (img > mean).astype(int)
return hashed
def dhash(self):
new_shape = (self.hash_size[0], self.hash_size[1]+1, self.img.shape[-1])
img = np.resize(self.img, new_shape)
img = self.img2gray(img)
hashed = (img[:, 1:] - img[:, :new_shape[1]-1] > 0).astype(int)
return hashed
参考: