整理提取图片始

背景

这一切要从我清理手机开始说起,最大占用手机空间的内容当然是手机上的照片。糟糕的是,将照片传到计算机之后,照片就完全乱了,虽然之前也是一团乱麻。想到之前想存图片当壁纸,存了几万张照片,这次可以总结一下,用python对图片做些简单的分类。所以总的说,目标是尽可能提取高清的图片作为壁纸,必要时需要按风格分一下类。其次是手机上不需要的图片且质量差的,或者是无法打开的照片都清理掉。下面是清理过程中的代码:

简单整理图片的思路与实现

准备部分

#与图像处理相关的包
from PIL import Image
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from pylab import *
#基础系统和数学包
import math
import numpy as np
import os
import shutil

分类

根据目的,考虑到照片的特性。下面是我对图片的大分类。对于每个大分类下,再进行特性分类,会方便许多。

  • 后缀为.heic的照片:这些图片属于iphone自带格式,利用python读图的函数,无法处理,但可以确定的是,这个格式一定是照片,所以可以单独存一类。
  • 截屏:截屏一般是转发信息,这部分图片一般都是我回消息的垃圾,提取出来可以集中销毁。
  • 太大的图片:大图一般意味着质量高,但这样的图片不会太多,可以集中处理。
  • 太小的图片:小图一般没什么用,这里主要目的是找合适的壁纸,小图当壁纸有损心情。
  • 照片:这里的照片是指满足某些特定尺寸的照片,一般在这个尺寸下得到的图片必然是照片。
  • 未处理的照片:不满足上述条件的照片是最多的,主要目的就是对这些图片分类。

对图片分类的事情和对垃圾分类特别像,说到底还是环境容纳不下了,我必须采取一些措施对他们回收利用,需要考虑的就是照片能做的事情。一方面是作为壁纸,壁纸分为两类,一类是横版,用于计算机;另一类是竖版用于手机壁纸。另一方面是给我当素材(画画、写网页的素材)。所以在大类之下需要考虑对每个大类的小分类是:横版或是竖版,根据颜色、亮度的不同级别细分在不同目录下。之后是部分代码,可以在基础上扩展。

粗糙的python代码——大分类

移动文件

只需要改变输入的条件函数就可以移动整个目录下的文件,之后对每个分类只需要注意运行的顺序和条件的写法。

#将某个文件夹的图片移动到另一个文件夹,加上某个条件判断
def movefile(source_folder,target_folder,condition):
    filelist=os.listdir(source_folder)
    for files in filelist:
        if files[0]==".":
            continue
        if os.path.isdir(os.path.join(source_folder,files)):
        	continue
        #try:#有异常用来测试,整个过程中异常情况少,原因是图片不够复杂。
        if condition(os.path.join(source_folder,files)):
            full_path=os.path.join(source_folder,files)
            des_path=os.path.join(target_folder,files)
            shutil.move(full_path,des_path)
        #except:
        #    print(os.path.join(source_folder,files))

heic后缀图片

def if_heic(file_path):
    if ".heic" in file_path:
        return True
    else:
        return False
movefile(root,heic,if_heic)

截屏图片

iphoneX的截屏图片都是602✖️1304,其他手机的不一定是这个,需要具体情况具体分析

def shortcuts(file_path):
    if ".heic" in file_path:
        return False
    try:
        im=Image.open(file_path)
        if im.size[0]==602 and im.size[1]==1304:
            return True
        else:
            return False
    except:
        print(file_path)
movefile(root,shortcut_path,shortcuts)

大图片

def if_big(file_path):
    size=os.path.getsize(file_path)
    if size>=1048576:
        return True
    else:
        return False
movefile(root,big,if_big)

4032✖️3024的照片

def if_zp(file_path):
    if ".heic" in file_path:
        return False
    try:
        im=Image.open(file_path)
        if (im.size[0]==4032 and im.size[1]==3024) or (im.size[0]==3024 and im.size[1]==4032):
            return True
        else:
            return False
    except:
        print(file_path)
movefile(root,zp,if_zp)

其他大分类的代码也是类似的,取决于读者的想象,这里就不全都放出来,以免限制了想象。

粗糙的python代码——小分类

对于小分类,我稍微想了一天,后来读到HSV颜色模型时豁然开朗,这正是我需要的东西。起初困窘于RGB颜色模型,按照颜色分类,从RGB的角度出发的确可行,代码则比较复杂,必须从三个维度划分颜色。起初的想法是,限制于RGB还不如直接使用聚类的方法。后来看到HSV模型,意识到颜色也可以是线性的。其次人肉眼关注的有时候并不只限于颜色类别,更多的是对明暗的辨别。明亮的图片更偏向于白色,反之则对应于黑暗,阴沉,这两种风格的差异可能是选择壁纸时更重要的指标。

使用HSV对颜色分类还需要考虑的问题是,一张图片有m✖️n个像素点,即使是划分好了区间,直接统计也是费时费力不靠谱的。所以我采取的方法是间隔一定距离取像素点作为图片的代表,这样可以大大简化时间。以下分别是对颜色分类和对明亮程度分类的代码:

颜色小分类

filelist=os.listdir(path)
for files in filelist:
    if files[0]==".":
        continue
    if os.path.isdir(os.path.join(path,files)):
        continue
    try:
        img = mpimg.imread(os.path.join(path,files))
        HSV=cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        H, S, V = cv2.split(HSV)
        x=H.shape[0]
        y=H.shape[1]
        #间隔取点
        newH=H[np.arange(0,x,30)][:,np.arange(0,y,30)]
        #颜色区间计数
        count=[0 for i in range(classes)]
        for j in newH:
            for i in j:
                if(isinstance(i,int)):
                    count[math.floor(i/(180/classes))]+=1
                else:
                    count[math.floor(i/(360/classes))]+=1
        which_class=argmax(count)

        full_path=os.path.join(path,files)
        des_path=os.path.join(path,str(which_class),files)
        shutil.move(full_path,des_path)
    except:
        print(files)

明亮度小分类

filelist=os.listdir(path)
for files in filelist:
    if files[0]==".":
        continue
    if os.path.isdir(os.path.join(path,files)):
        continue
    try:
        img = mpimg.imread(os.path.join(path,files))
        HSV=cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
        H, S, V = cv2.split(HSV)
        x=V.shape[0]
        y=V.shape[1]
        newV=V[np.arange(0,x,30)][:,np.arange(0,y,30)]
        count=[0 for i in range(classes)]
        for j in newV:
            for i in j:
                if(isinstance(i,int)):
                    count[math.floor(i/(256/classes))]+=1
        which_class=argmax(count)
        
        full_path=os.path.join(path,files)
        des_path=os.path.join(path,str(which_class),files)
        shutil.move(full_path,des_path)
    except:
        print(files)

最后补充一点,毕竟最主要的目的是提取壁纸,最后附上筛选壁纸条件的代码。首先我计算机的分辨率比较高,壁纸需要在2000以上才足够清晰,其次是需要横图作为计算机墙纸,竖图作为手机壁纸。

提取壁纸图片

path=root
two_thousand_up="2000plus"
two_thousand_minus="2000minus"
wall="wall"
phone="phone"
if not os.path.exists(path+"/"+wall+two_thousand_up):
    os.makedirs(path+"/"+wall+two_thousand_up)
if not os.path.exists(path+"/"+wall+two_thousand_minus):
    os.makedirs(path+"/"+wall+two_thousand_minus)
if not os.path.exists(path+"/"+phone+two_thousand_up):
    os.makedirs(path+"/"+phone+two_thousand_up)
if not os.path.exists(path+"/"+phone+two_thousand_minus):
    os.makedirs(path+"/"+phone+two_thousand_minus)

filelist=os.listdir(path)
for files in filelist:
    if files[0]==".":
        continue
    if os.path.isdir(os.path.join(path,files)):
        continue
    try:
        im=Image.open(os.path.join(path,files))
        if (im.size[0]>=2000 and im.size[1]>=2000) and im.size[0]>im.size[1]:
            shutil.move(os.path.join(path,files),os.path.join(path,wall+two_thousand_up,files))
        elif (im.size[0]>=2000 and im.size[1]>=2000) and im.size[0]<=im.size[1]:
            shutil.move(os.path.join(path,files),os.path.join(path,phone+two_thousand_up,files))
        elif im.size[0]>im.size[1]:
            shutil.move(os.path.join(path,files),os.path.join(path,wall+two_thousand_minus,files))
        elif im.size[0]<=im.size[1]:
            shutil.move(os.path.join(path,files),os.path.join(path,phone+two_thousand_minus,files))
    except:
        print(files)

小结

整个过程主要是为了熟悉python提取图片的流程。细节还有许多可以加强的地方。比较遗憾的是,最后还是没有用上利用无监督算法等,对图片做进一步划分。为了保护隐私,这里没有放我整理之后的图片。对于小分类,的确可以按照颜色和明亮程度很好的划分出我需要的图片。但并不能划分出我图片中最大的两个类别:人像和画。这一点是可以由编写分类算法来实现的。等未来有时间进一步研究时,将再写sort_img2。

上半学期做了一些关于图片分类的大作业,在实际对我自己的照片分类时,我有些许对当时做的不恰当的点进行了反思。很大程度上,这些简单的分类手段已经足以细化图片,而当时简单地将所有图片整合为一个维度,就直接开始增强训练,这点现在想想是不太妥当的。