Python列表删除重复元素与图像相似度判断及删除实例代码


Posted in Python onMay 07, 2021

发现问题

项目需要,需要删除文件夹中的冗余图片。涉及图像文件名的操作,图像文件名存储在list中

python list删除元素有remove()和pop(),remove()对元素进行操作,pop()对索引进行操作,并会返回pop掉的值。一个只会从列表移除一个数

一.如果已经有了一个列表l,令h=l,对l操作时同时会影响h,貌似原因是内存共享的,正确的方法是h=l.copy()

二.测试时,发现一个问题,如下面代码和结果:

Python列表删除重复元素与图像相似度判断及删除实例代码Python列表删除重复元素与图像相似度判断及删除实例代码

item=2时,并没有把2全部删掉,后面重复的3也没有删去。

**查阅一些资料后发现:list的遍历是基于下标的不是基于元素,你删掉一个元素后,列表就发生了变化,所有的元素都往前移动了一个位置,假设要删除重的2,一个列表中索引为4,对应的值为2,索引为5,对应的值为2,索引为6,对应的值为3,当前循环删掉索引4时对应的值2之后,索引4的值为2,索引5,值为3,下一次循环,本来要再删一个2,但此时索引为5对应的为3,就漏掉了一个2。

解决方案:

(1)倒序循环遍历:

Python列表删除重复元素与图像相似度判断及删除实例代码Python列表删除重复元素与图像相似度判断及删除实例代码

(2)实际用的方法,判断到重复元素后,将那个item复制为0或‘0',相当于用一个标识符占住重复元素的位置,循环时先判断是否为‘0',最后通过

list = list(set(list))

list.remove('0')

即可

附图像去冗余算法,判断图像相似通过,感知哈希算法和三通道直方图,及图像尺寸

from img_similarity import runtwoImageSimilaryFun
import os
from PIL import Image
import shutil
import time
import numpy as np
 
def similar(path1, path2):
    img1 = Image.open(path1)
    img2 = Image.open(path2)
    w1 = img1.size[0] # 图片的宽
    h1 = img2.size[1]  # 图片的高
    w2 = img2.size[0] # 图片的宽
    h2 = img2.size[1]  # 图片的高
    w_err = abs(w1 - w2)/w1
    h_err = abs(h1 - h2)/h1
    if w_err > 0.1 or h_err >0.1:
        return 0
    else:
        phash, color_hist = runtwoImageSimilaryFun(path1, path2)
        if phash <=8 or color_hist >=0.9:
            return 1
        else:
            return 0
 
 
path = './crop_img'
result_imgdirs_path = './removed_repeat_img'
folderlist = os.listdir(path)
folderlist.sort()
for item in folderlist:
    folder_path = path + '/' + item
    new_folder_path = result_imgdirs_path + '/' + item
    os.makedirs(new_folder_path)
 
    imglist = os.listdir(folder_path)
    imglist.sort()
 
    time_start = time.time()
 
    for i,item1 in enumerate(imglist):
        if item1 == '0':
            continue
        path1 = folder_path + '/' + item1
        for j, item2 in enumerate(imglist[i + 1:]):
            if item2 == '0':
                continue
            path2 = folder_path + '/' + item2
            t = similar(path1, path2)
            if t:
                #将判断为相似的图片在trans_list中的名字置‘0',代表不需要复制
                imglist[i+j+1] = '0'
 
    imglist = list(set(imglist))
    imglist.remove('0')
 
    time_end = time.time()
    time_c = time_end - time_start
    print('{} similarity judgement list time cost {}s'.format(item, time_c))
 
 
    time_start = time.time()
    #移动图片
    for item3 in imglist:
        ori_img_path = folder_path + '/' + item3
        new_img_path = new_folder_path + '/' + item3
        shutil.copy(ori_img_path, new_img_path)
 
    time_end = time.time()
    time_c = time_end - time_start # 运行所花时间
    print('{} move image time cost {}s'.format(item, time_c))

img_similarity.py

import cv2
import numpy as np
from PIL import Image
import requests
from io import BytesIO
import matplotlib
 
matplotlib.use('TkAgg')
import matplotlib.pyplot as plt
 
 
def aHash(img):
    # 均值哈希算法
    # 缩放为8*8
    img = cv2.resize(img, (8, 8))
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # s为像素和初值为0,hash_str为hash值初值为''
    s = 0
    hash_str = ''
    # 遍历累加求像素和
    for i in range(8):
        for j in range(8):
            s = s + gray[i, j]
    # 求平均灰度
    avg = s / 64
    # 灰度大于平均值为1相反为0生成图片的hash值
    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'
    return hash_str
 
 
def dHash(img):
    # 差值哈希算法
    # 缩放8*8
    img = cv2.resize(img, (9, 8))
    # 转换灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    hash_str = ''
    # 每行前一个像素大于后一个像素为1,相反为0,生成哈希
    for i in range(8):
        for j in range(8):
            if gray[i, j] > gray[i, j + 1]:
                hash_str = hash_str + '1'
            else:
                hash_str = hash_str + '0'
    return hash_str
 
 
def pHash(img):
    # 感知哈希算法
    # 缩放32*32
    img = cv2.resize(img, (32, 32))  # , interpolation=cv2.INTER_CUBIC
    # 转换为灰度图
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 将灰度图转为浮点型,再进行dct变换
    dct = cv2.dct(np.float32(gray))
    # opencv实现的掩码操作
    dct_roi = dct[0:8, 0:8]
 
    hash = []
    avreage = np.mean(dct_roi)
    for i in range(dct_roi.shape[0]):
        for j in range(dct_roi.shape[1]):
            if dct_roi[i, j] > avreage:
                hash.append(1)
            else:
                hash.append(0)
    return hash
 
 
def calculate(image1, image2):
    # 灰度直方图算法
    # 计算单通道的直方图的相似值
    hist1 = cv2.calcHist([image1], [0], None, [256], [0.0, 255.0])
    hist2 = cv2.calcHist([image2], [0], None, [256], [0.0, 255.0])
    # 计算直方图的重合度
    degree = 0
    for i in range(len(hist1)):
        if hist1[i] != hist2[i]:
            degree = degree + \
                     (1 - abs(hist1[i] - hist2[i]) / max(hist1[i], hist2[i]))
        else:
            degree = degree + 1
    degree = degree / len(hist1)
    return degree
 
 
def classify_hist_with_split(image1, image2, size=(256, 256)):
    # RGB每个通道的直方图相似度
    # 将图像resize后,分离为RGB三个通道,再计算每个通道的相似值
    image1 = cv2.resize(image1, size)
    image2 = cv2.resize(image2, size)
    sub_image1 = cv2.split(image1)
    sub_image2 = cv2.split(image2)
    sub_data = 0
    for im1, im2 in zip(sub_image1, sub_image2):
        sub_data += calculate(im1, im2)
    sub_data = sub_data / 3
    return sub_data
 
 
def cmpHash(hash1, hash2):
    # Hash值对比
    # 算法中1和0顺序组合起来的即是图片的指纹hash。顺序不固定,但是比较的时候必须是相同的顺序。
    # 对比两幅图的指纹,计算汉明距离,即两个64位的hash值有多少是不一样的,不同的位数越小,图片越相似
    # 汉明距离:一组二进制数据变成另一组数据所需要的步骤,可以衡量两图的差异,汉明距离越小,则相似度越高。汉明距离为0,即两张图片完全一样
    n = 0
    # hash长度不同则返回-1代表传参出错
    if len(hash1) != len(hash2):
        return -1
    # 遍历判断
    for i in range(len(hash1)):
        # 不相等则n计数+1,n最终为相似度
        if hash1[i] != hash2[i]:
            n = n + 1
    return n
 
 
def getImageByUrl(url):
    # 根据图片url 获取图片对象
    html = requests.get(url, verify=False)
    image = Image.open(BytesIO(html.content))
    return image
 
 
def PILImageToCV():
    # PIL Image转换成OpenCV格式
    path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
    img = Image.open(path)
    plt.subplot(121)
    plt.imshow(img)
    print(isinstance(img, np.ndarray))
    img = cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
    print(isinstance(img, np.ndarray))
    plt.subplot(122)
    plt.imshow(img)
    plt.show()
 
 
def CVImageToPIL():
    # OpenCV图片转换为PIL image
    path = "/Users/waldenz/Documents/Work/doc/TestImages/t3.png"
    img = cv2.imread(path)
    # cv2.imshow("OpenCV",img)
    plt.subplot(121)
    plt.imshow(img)
 
    img2 = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
    plt.subplot(122)
    plt.imshow(img2)
    plt.show()
 
 
def bytes_to_cvimage(filebytes):
    # 图片字节流转换为cv image
    image = Image.open(filebytes)
    img = cv2.cvtColor(np.asarray(image), cv2.COLOR_RGB2BGR)
    return img
 
 
def runAllImageSimilaryFun(para1, para2):
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    # t1,t2   14;19;10;  0.70;0.75
    # t1,t3   39 33 18   0.58 0.49
    # s1,s2  7 23 11     0.83 0.86  挺相似的图片
    # c1,c2  11 29 17    0.30 0.31
 
    if para1.startswith("http"):
        # 根据链接下载图片,并转换为opencv格式
        img1 = getImageByUrl(para1)
        img1 = cv2.cvtColor(np.asarray(img1), cv2.COLOR_RGB2BGR)
 
        img2 = getImageByUrl(para2)
        img2 = cv2.cvtColor(np.asarray(img2), cv2.COLOR_RGB2BGR)
    else:
        # 通过imread方法直接读取物理路径
        img1 = cv2.imread(para1)
        img2 = cv2.imread(para2)
 
    hash1 = aHash(img1)
    hash2 = aHash(img2)
    n1 = cmpHash(hash1, hash2)
    print('均值哈希算法相似度aHash:', n1)
 
    hash1 = dHash(img1)
    hash2 = dHash(img2)
    n2 = cmpHash(hash1, hash2)
    print('差值哈希算法相似度dHash:', n2)
 
    hash1 = pHash(img1)
    hash2 = pHash(img2)
    n3 = cmpHash(hash1, hash2)
    print('感知哈希算法相似度pHash:', n3)
 
    n4 = classify_hist_with_split(img1, img2)
    print('三直方图算法相似度:', n4)
 
    n5 = calculate(img1, img2)
    print("单通道的直方图", n5)
    print("%d %d %d %.2f %.2f " % (n1, n2, n3, round(n4[0], 2), n5[0]))
    print("%.2f %.2f %.2f %.2f %.2f " % (1 - float(n1 / 64), 1 -
                                         float(n2 / 64), 1 - float(n3 / 64), round(n4[0], 2), n5[0]))
 
    plt.subplot(121)
    plt.imshow(Image.fromarray(cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)))
    plt.subplot(122)
    plt.imshow(Image.fromarray(cv2.cvtColor(img2, cv2.COLOR_BGR2RGB)))
    plt.show()
 
 
def runtwoImageSimilaryFun(para1, para2):
    # 均值、差值、感知哈希算法三种算法值越小,则越相似,相同图片值为0
    # 三直方图算法和单通道的直方图 0-1之间,值越大,越相似。 相同图片为1
    # t1,t2   14;19;10;  0.70;0.75
    # t1,t3   39 33 18   0.58 0.49
    # s1,s2  7 23 11     0.83 0.86  挺相似的图片
    # c1,c2  11 29 17    0.30 0.31
 
    if para1.startswith("http"):
        # 根据链接下载图片,并转换为opencv格式
        img1 = getImageByUrl(para1)
        img1 = cv2.cvtColor(np.asarray(img1), cv2.COLOR_RGB2BGR)
 
        img2 = getImageByUrl(para2)
        img2 = cv2.cvtColor(np.asarray(img2), cv2.COLOR_RGB2BGR)
    else:
        # 通过imread方法直接读取物理路径
        img1 = cv2.imread(para1)
        img2 = cv2.imread(para2)
 
 
    hash1 = pHash(img1)
    hash2 = pHash(img2)
    n3 = cmpHash(hash1, hash2)
 
    n4 = classify_hist_with_split(img1, img2)
 
    return n3, n4
 
 
 
if __name__ == "__main__":
    p1 = '/Users/Desktop/11/24.jpeg'
    p2 = '/Users/Desktop/11/25.jpeg'
    runAllImageSimilaryFun(p1, p2)

总结

到此这篇关于Python列表删除重复元素与图像相似度判断及删除的文章就介绍到这了,更多相关Python列表删除重复元素内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
利用Python的Django框架生成PDF文件的教程
Jul 22 Python
用Python解决计数原理问题的方法
Aug 04 Python
Python 数据结构之队列的实现
Jan 22 Python
Python操作Redis之设置key的过期时间实例代码
Jan 25 Python
Python模拟随机游走图形效果示例
Feb 06 Python
django限制匿名用户访问及重定向的方法实例
Feb 07 Python
django传值给模板, 再用JS接收并进行操作的实例
May 28 Python
django的settings中设置中文支持的实现
Apr 28 Python
Tensorflow矩阵运算实例(矩阵相乘,点乘,行/列累加)
Feb 05 Python
详解Django中views数据查询使用locals()函数进行优化
Aug 24 Python
10个python爬虫入门实例(小结)
Nov 01 Python
Python编程中内置的NotImplemented类型的用法
Mar 23 Python
使用python如何删除同一文件夹下相似的图片
May 07 #Python
python学习之panda数据分析核心支持库
Python基于Tkinter开发一个爬取B站直播弹幕的工具
May 06 #Python
Python爬虫之爬取最新更新的小说网站
May 06 #Python
Python基础之操作MySQL数据库
Python 如何安装Selenium
Django实现在线无水印抖音视频下载(附源码及地址)
You might like
PHP has encountered an Access Violation 错误的解决方法
2010/01/17 PHP
PHP上传文件时文件过大$_FILES为空的解决方法
2013/11/26 PHP
discuz图片顺序混乱解决方案
2015/07/29 PHP
php防止用户重复提交表单
2015/11/02 PHP
微信自定义分享php代码分析
2016/11/24 PHP
PHPMailer发送邮件
2016/12/28 PHP
jquery 学习笔记一
2010/04/07 Javascript
JqueryMobile动态生成listView并实现刷新的两种方法
2014/03/05 Javascript
jQuery中scrollTop()方法用法实例
2015/01/16 Javascript
jQuery.Highcharts.js绘制柱状图饼状图曲线图
2015/03/14 Javascript
javascript数组去重的六种方法汇总
2015/08/16 Javascript
Bootstrap每天必学之按钮
2015/11/26 Javascript
基于JavaScript实现窗口拖动效果
2017/01/18 Javascript
JQuery validate 验证一个单独的表单元素实例
2017/02/17 Javascript
js实现简单的选项卡效果
2017/02/23 Javascript
基于JSONP原理解析(推荐)
2017/12/04 Javascript
vue数据控制视图源码解析
2018/03/28 Javascript
jQuery 实现批量提交表格多行数据的方法
2018/08/09 jQuery
浅析js中mvvm模式实现的原理
2018/10/06 Javascript
es6 symbol的实现方法示例
2019/04/02 Javascript
vue将后台数据时间戳转换成日期格式
2019/07/31 Javascript
vue使用swiper实现中间大两边小的轮播图效果
2019/11/24 Javascript
[02:47]2018年度DOTA2最佳辅助位选手4号位-完美盛典
2018/12/17 DOTA
Python学习笔记之常用函数及说明
2014/05/23 Python
Python的Flask框架中SQLAlchemy使用时的乱码问题解决
2015/11/07 Python
django rest framework 数据的查找、过滤、排序的示例
2018/06/25 Python
Python 窗体(tkinter)按钮 位置实例
2019/06/13 Python
python自动发微信监控报警
2019/09/06 Python
Python环境Pillow( PIL )图像处理工具使用解析
2019/09/12 Python
python实现对列表中的元素进行倒序打印
2019/11/23 Python
解决pycharm安装第三方库失败的问题
2020/05/09 Python
详解CSS3的opacity属性设置透明效果的用法
2016/05/09 HTML / CSS
介绍一下Linux文件的记录形式
2012/04/18 面试题
酒店出纳岗位职责
2013/12/29 职场文书
内蒙古鄂尔多斯市市长寄语
2014/04/10 职场文书
KTV门卫岗位职责
2014/10/09 职场文书