图片对比 平均哈希法(aHash)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了图片对比 平均哈希法(aHash)相关的知识,希望对你有一定的参考价值。

■环境         
    Python 3.6.0                                                                                                                                                                                                    
    Pycharm 2017.1.3                                                                                                                                                                                            

■库、库的版本                                                                                                                                                                                                     
    PIL version: 1.1.7                                                                                                                                                                                              
    Pillow version: 3.4.2                                                                                                                                                                                       

■参考                                                                                                                                                                                                     
    https://segmentfault.com/a/1190000004467183                                                                                             
    https://www.cnblogs.com/tomato0906/articles/5616692.html                                                    

■逻辑                                                                                                                                                                                                     
    平均哈希法(aHash)                                                                                                                                                                                        
    1. 打开图片                                                                                                                                                                                                 
    2. 修改图片大小,12*12(图片越大,精度越高)。                                                                                                                                                                                                 
    3. 转成灰度图,使用Image的对象的方法convert(‘L‘)。                                                                                                                                                                                                 
    4. 计算灰度图的所有像素平均值。                                                                                                                                                                                                   
    5. 获取图片指纹:遍历灰度图的所有像素,比平均值大则记录为1,否则记录为0。                                                                                                                                                                                                 
    6. 对比两张图片的灰度图所有像素,得到汉明距离。                                                                                                                                                                                                   
    7. 汉明距离等于0说明两张图片完全一样。                                                                                                                                                                                                   

■代码                                                                                                                                                     
    from PIL import Image                                                                                                                                                                                                   
    import os                                                                                                                                                                                                   
    import datetime                                                                                                                                                                                                 

    def get_img_gray_list(image_gray):                                                                                                                                                                                                  
        """                                                                                                                                                                                                 
        获取灰度图像素集合                                                                                                                                                                                                   
        :param image_gray: 灰度图                                                                                                                                                                                                  
        :return: 灰度图像素集合                                                                                                                                                                                                    
        """                                                                                                                                                                                                 
        gray_list = []                                                                                                                                                                                                  
        for h in range(0, image_gray.size[1]):                                                                                                                                                                                                  
            for w in range(0, image_gray.size[0]):                                                                                                                                                                                                  
                gray_list.append(image_gray.getpixel((w, h)))                                                                                                                                                                                                   
        return gray_list                                                                                                                                                                                                    

    def get_img_gray_avg(gray_list):                                                                                                                                                                                                    
        """                                                                                                                                                                                                 
        获取灰度图像素平均值                                                                                                                                                                                                  
        :param gray_list: 灰度图像素集合                                                                                                                                                                                                   
        :return: 灰度图像素平均值                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        return sum(gray_list) / len(gray_list)                                                                                                                                                                                                  

    def get_img_fingerprints(image_gray, image_gray_avg):                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        获取图片指纹:遍历灰度图的所有像素,比平均值大则记录为1,否则记录为0。                                                                                                                                                                                                    
        :param image_gray: 灰度图                                                                                                                                                                                                  
        :param image_gray_avg: 灰度图像素平均值                                                                                                                                                                                                 
        :return: 图片指纹集合                                                                                                                                                                                                 
        """                                                                                                                                                                                                 
        img_fingerprints = ‘‘                                                                                                                                                                                                   
        for h in range(1, image_gray.size[1]):                                                                                                                                                                                                  
            for w in range(1, image_gray.size[0]):                                                                                                                                                                                                  
                if image_gray.getpixel((w, h)) > image_gray_avg:                                                                                                                                                                                                    
                    img_fingerprints += ‘1‘                                                                                                                                                                                                 
                else:                                                                                                                                                                                                   
                    img_fingerprints += ‘0‘                                                                                                                                                                                                 
        return img_fingerprints                                                                                                                                                                                                 

    def get_img_gray_bit(image, resize=(12, 12)):                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        获取图片指纹                                                                                                                                                                                                  
        :param image: 图片                                                                                                                                                                                                    
        :param resize: Resize的图片大小                                                                                                                                                                                                  
        :return: 图片指纹                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        # 修改图片大小                                                                                                                                                                                                    
        image_resize = image.resize(resize)                                                                                                                                                                                                 
        # 修改图片成灰度图                                                                                                                                                                                                  
        image_gray = image_resize.convert("L")                                                                                                                                                                                                  
        # 获取灰度图像素集合                                                                                                                                                                                                 
        gray_list = get_img_gray_list(image_gray)                                                                                                                                                                                                   
        # 获取灰度图像素平均值                                                                                                                                                                                                    
        image_gray_avg = get_img_gray_avg(gray_list)                                                                                                                                                                                                    
        # 获取图片指纹                                                                                                                                                                                                    
        img_fingerprints = get_img_fingerprints(image_gray, image_gray_avg)                                                                                                                                                                                                 
        return img_fingerprints                                                                                                                                                                                                 

    def get_mh(img_fingerprints1, img_fingerprints2):                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        获取汉明距离                                                                                                                                                                                                  
        :param img_fingerprints1: 比较对象1的指纹                                                                                                                                                                                                  
        :param img_fingerprints2: 比较对象2的指纹                                                                                                                                                                                                  
        :return: 汉明距离                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        hm = 0                                                                                                                                                                                                  
        for i in range(0, len(img_fingerprints1)):                                                                                                                                                                                                  
            if img_fingerprints1[i] != img_fingerprints2[i]:                                                                                                                                                                                                    
                hm += 1                                                                                                                                                                                                 
        return hm                                                                                                                                                                                                   

    def is_image_file(file_name):                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        判断文件是否是图片                                                                                                                                                                                                   
        :param file_name: 文件名称(包含后缀信息)                                                                                                                                                                                                  
        :return: 1:图片,0:非图片                                                                                                                                                                                                 
        """                                                                                                                                                                                                 
        ext = (os.path.splitext(file_name)[1]).lower()                                                                                                                                                                                                  
        if ext == ".jpg" or ext == ".jpeg" or ext == ".bmp" or ext == ".png":                                                                                                                                                                                                   
            return 1                                                                                                                                                                                                    
        return 0                                                                                                                                                                                                    

    def get_all_img_list(root_path):                                                                                                                                                                                                    
        """                                                                                                                                                                                                 
        获取目标文件夹下所有图片路径集合                                                                                                                                                                                                    
        :param root_path: 目标文件夹                                                                                                                                                                                                 
        :return: 图片集合                                                                                                                                                                                                   
        """                                                                                                                                                                                                 
        img_list = []                                                                                                                                                                                                   
        # 获取目标文件夹下所有元组                                                                                                                                                                                                  
        root = os.walk(root_path)                                                                                                                                                                                                   
        # 循环元组,获取目标文件夹下所有图片路径集合                                                                                                                                                                                                 
        for objects in root:                                                                                                                                                                                                    
            for obj in objects:                                                                                                                                                                                                 
                if "/" in str(obj):                                                                                                                                                                                                 
                    # 记录文件夹路径                                                                                                                                                                                                   
                    path = str(obj)                                                                                                                                                                                                 
                elif len(obj) > 0:                                                                                                                                                                                                  
                    # 如果是文件,判断是否是图片。如果是图片则保存进                                                                                                                                                                                                   
                    for file in obj:                                                                                                                                                                                                    
                        if "." in str(file) and is_image_file(file) == 1:                                                                                                                                                                                                   
                            full_path = path + "/" + str(file)                                                                                                                                                                                                  
                            img_list.append(full_path)                                                                                                                                                                                                  
        return img_list                                                                                                                                                                                                 

    def compare_img(root_path):                                                                                                                                                                                                 
        """                                                                                                                                                                                                 
        比较图片 (Main)                                                                                                                                                                                                 
        :param root_path: 目标文件夹                                                                                                                                                                                                 
        """                                                                                                                                                                                                 
        # 获取目标文件夹下所有图片路径集合                                                                                                                                                                                                  
        img_list = get_all_img_list(root_path)                                                                                                                                                                                                  
        # 遍历目标文件夹下所有图片进行两两比较                                                                                                                                                                                                    
        for files1 in img_list:                                                                                                                                                                                                 
            im1 = Image.open(files1)                                                                                                                                                                                                    
            im1_size = im1.size                                                                                                                                                                                                 
            img_fingerprints1 = get_img_gray_bit(im1)                                                                                                                                                                                                   
            for files2 in img_list:                                                                                                                                                                                                 
                if files1 != files2:                                                                                                                                                                                                    
                    im2 = Image.open(files2)                                                                                                                                                                                                    
                    im2_size = im2.size                                                                                                                                                                                                 
                    # 如果两张图片大小一样再判断汉明距离                                                                                                                                                                                                 
                    if im1_size == im2_size:                                                                                                                                                                                                    
                        img_fingerprints2 = get_img_gray_bit(im2)                                                                                                                                                                                                   
                        compare_result = get_mh(img_fingerprints1, img_fingerprints2)                                                                                                                                                                                                   
                        # 汉明距离等于0,说明两张图片完全一样                                                                                                                                                                                                    
                        if compare_result == 0:                                                                                                                                                                                                 
                            print("图片相同:" + files1 + "::::::" + files2)                                                                                                                                                                                                 

    start_time = datetime.datetime.now()                                                                                                                                                                                                    
    start_time = start_time.strftime(‘%Y-%m-%d %H:%M:%S‘)                                                                                                                                                                                                   
    print("start time: " + start_time)                                                                                                                                                                                                  

    compare_img("C:/Users/x230/Desktop/test")                                                                                                                                                                                                   

    end_time = datetime.datetime.now()                                                                                                                                                                                                  
    end_time = end_time.strftime(‘%Y-%m-%d %H:%M:%S‘)                                                                                                                                                                                                   
    print("end time: " + end_time)                                                                                                                                                                                                  

    d1 = datetime.datetime.strptime(start_time, ‘%Y-%m-%d %H:%M:%S‘)                                                                                                                                                                                                    
    d2 = datetime.datetime.strptime(end_time, ‘%Y-%m-%d %H:%M:%S‘)                                                                                                                                                                                                  
    print("耗时: " + str((d2 - d1).seconds))                                                                                                                                                                                                  

技术分享图片

以上是关于图片对比 平均哈希法(aHash)的主要内容,如果未能解决你的问题,请参考以下文章

代码手记笔录——哈希法

第十五周 项目2--用哈希法组织关键字

负载均衡算法--源地址哈希法(Hash)

图片相似度识别:aHash算法

基于Dubbo实现一致哈希法与最少活跃优先法结合

C# Dictionary源码剖析---哈希处理冲突的方法有:开放定址法再哈希法链地址法建立一个公共溢出区等