Python3.0以上版本在對比圖片類似中的應用

在網上找的代碼,用了方法一,效果很棒!python

Python 3.4   以及 Pillow (4.0.0)  第三方包。git

方法1、github

#!/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")

方法2、 # 原做者發佈在GitHub上的一些列圖片對比的方法。
有興趣研究的能夠訪問連接以下: # https://github.com/MashiMaroLjc/Learn-to-identify-similar-imagesapp

# 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)


對比方法一和方法二,在執行的效率上基本一致,可是在對比的準確度上,方法二要優於方法一。
相關文章
相關標籤/搜索