首先聲明一下,代碼是從網上找到的,只是本人作以簡單的修改。
請大家尊重原創。
我本地用到的是
Python 3.4 以及 Pillow (4.0.0) 第三方包。
方法一、
#!/usr/bin/python
# coding : utf-8
import glob
import os
import sys
from functools import reduce
from PIL import Image
# EXTS = 'jpg', 'jpeg', 'JPG', 'JPEG', 'gif', 'GIF', 'png', 'PNG'
EXTS = 'jpg', 'jpeg', 'gif', 'png'
# 通過計算哈希值來得到該張圖片的“指紋”
def avhash(im):
# 判斷參數im,是不是Image類的一個參數
try:
if not isinstance(im, Image.Image):
im = Image.open(im)
except OSError as ose:
print("打不開圖片:{}".format(im))
return "ng"
# resize,格式轉換,把圖片壓縮成8*8大小,ANTIALIAS是抗鋸齒效果開啟,“L”是將其轉化為
# 64級灰度,即一共有64種顏色
im = im.resize((8, 8), Image.ANTIALIAS).convert('L')
# 遞歸取值,這里是計算所有
# 64個像素的灰度平均值
avg = reduce(lambda x, y: x + y, im.getdata()) / 64.
print(reduce(func_reduce_param, enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())), 0))
# 比較像素的灰度,將每個像素的灰度與平均值進行比較,>=avg:1;<avg:0
return reduce(func_reduce_param,
enumerate(map(lambda i: 0 if i < avg else 1, im.getdata())), 0)
def func_reduce_param(x, a):
if type(a) == tuple:
y = a[0]
z = a[1]
return x | (z << y)
# 比較指紋,等同於計算“漢明距離”(兩個字符串對應位置的字符不同的個數)
def hamming(h1, h2):
if h1 == "ng" or h2 == "ng":
return "獲取指紋失敗。"
h, d = 0, h1 ^ h2
while d:
h += 1
d &= d - 1
return h
def compare(img1, img2):
if os.path.isfile(img1):
print("源圖為:{}".format(img1))
else:
print("給定的源圖片:{} 不存在".format(img1))
return "img1"
if os.path.isfile(img2):
print("對比圖為:{}".format(img2))
else:
print("給定的對比圖片:{} 不存在".format(img2))
return "img2"
ham = hamming(avhash(img2), avhash(img1))
if type(ham) == int:
if ham == 0:
print("源圖:{} 與對比圖:{} 一樣。{}".format(img1, img2, ham))
elif ham <= 3:
print("源圖:{} 與對比圖:{} 存在差異。{}".format(img1, img2, ham))
elif ham <= 5:
print("源圖:{} 與對比圖:{} 對比明顯存在差異。{}".format(img1, img2, ham))
elif ham <= 8:
print("源圖:{} 與對比圖:{} 還能看到一點兒相似的希望。{}".format(img1, img2, ham))
elif ham <= 10:
print("源圖:{} 與對比圖:{} 這兩張圖片有相同點,但少的可憐啊。{}".format(img1, img2, ham))
elif ham > 10:
print("源圖:{} 與對比圖:{} 不一樣。{}".format(img1, img2, ham))
else:
print("未知的結果,無法完成對比。")
return ""
def compare_many_pic(img, abs_dir):
if os.path.isfile(img):
print("源圖為:{}".format(img))
else:
print("給定的源圖片:{} 不存在".format(img))
print("Usage: image.jpg [dir]")
return "img"
if os.path.isdir(abs_dir):
print("給定目錄為:{}".format(abs_dir))
else:
print("給定的目錄:{} 不存在".format(abs_dir))
print("Usage: image.jpg [dir]")
return "dir"
h = avhash(img)
os.chdir(abs_dir)
images = []
for ext in EXTS:
images.extend(glob.glob('*.%s' % ext))
print(images)
seq = []
prog = int(len(images) > 50 and sys.stdout.isatty())
for f in images:
seq.append((f, hamming(avhash(f), h)))
if prog:
perc = 100. * prog / len(images)
x = int(2 * perc / 5)
print('\rCalculating... [' + '#' * x + ' ' * (40 - x) + ']')
print('%.2f%%' % perc, '(%d/%d)' % (prog, len(images)))
sys.stdout.flush()
prog += 1
if prog: print("")
for f, ham in sorted(seq, key=lambda i: i[1]):
print("{}\t{}".format(ham, f))
return ""
if __name__ == '__main__':
compare(img1="./images/1.png", img2="./images/4.png")
此方法的詳細描述,已經在代碼中給出,不做贅述。
方法二、
# 原作者發布在GitHub上的一些列圖片對比的方法。有興趣研究的可以訪問鏈接如下:
# https://github.com/MashiMaroLjc/Learn-to-identify-similar-images
# coding : utf-8
from PIL import Image
def calculate(image1, image2):
g = image1.histogram()
s = image2.histogram()
assert len(g) == len(s), "error"
data = []
for index in range(0, len(g)):
if g[index] != s[index]:
data.append(1 - abs(g[index] - s[index]) / max(g[index], s[index]))
else:
data.append(1)
return sum(data) / len(g)
def split_image(image, part_size):
pw, ph = part_size
w, h = image.size
sub_image_list = []
assert w % pw == h % ph == 0, "error"
for i in range(0, w, pw):
for j in range(0, h, ph):
sub_image = image.crop((i, j, i + pw, j + ph)).copy()
sub_image_list.append(sub_image)
return sub_image_list
def classfiy_histogram_with_split(image1, image2, size=(256, 256), part_size=(64, 64)):
'''
'image1' 和 'image2' 都是Image 對象.
可以通過'Image.open(path)'進行創建。
'size' 重新將 image 對象的尺寸進行重置,默認大小為256 * 256 .
'part_size' 定義了分割圖片的大小.默認大小為64*64 .
返回值是 'image1' 和 'image2'對比后的相似度,相似度越高,圖片越接近,達到100.0說明圖片完全相同。
'''
img1 = image1.resize(size).convert("RGB")
sub_image1 = split_image(img1, part_size)
img2 = image2.resize(size).convert("RGB")
sub_image2 = split_image(img2, part_size)
sub_data = 0
for im1, im2 in zip(sub_image1, sub_image2):
sub_data += calculate(im1, im2)
x = size[0] / part_size[0]
y = size[1] / part_size[1]
pre = round((sub_data / (x * y)), 6)
print(pre * 100)
return pre * 100
if __name__ == '__main__':
image1 = Image.open("./images/1.png")
image2 = Image.open("./images/brain.jpg")
classfiy_histogram_with_split(image1, image2)
對比方法一和方法二,在執行的效率上基本一致,但是在對比的准確度上,方法二要優於方法一。