zoukankan      html  css  js  c++  java
  • [ller必读] LoveLive! 必备技能之 Python Pillow 自动处理截图

    起因


    喜欢的歌,静静地听;喜欢的人,远远的看。30天前,就是3月14号,我情不自禁地走近了《LoveLive!学院偶像祭》,这是我的第一张卡片(见下图)。第二天也就是3月15日,海未生日了。

    园田海未_Smile_R_3 LoveLive!-园田海未_0315_生日

    之后我一直搜集游戏过程中遇到的卡片(截屏),卡片本身有一定的比例,而我的手机屏幕分辨率是 1920x1080,截完的图像下面这样。整个游戏界面并没有充满屏幕,所以有黑边;卡片比游戏界面小,截出的图很不美观而且方向不正。

    Screenshot_2016-04-05-23-44-39-743_Love Live!

    中间的卡片的区域是 1080x1520

    我本人并不是处女座,然而也不能忍受不美好的事物。于是一步一步地走上了程序员这条路。

    我以为做程序员可以填满人生的遗憾。然而,制造更多遗憾的。却偏偏是做程序员。

    (问:一个什么都拥有的程序猿他还缺少什么?)

    非程序员的解决办法


    while( true )
    {
        用 PS 打开截图;
        添加辅助线;
        裁剪区域;
        旋转正图像;
        sit,不对,是save;
    }

    没图你说个毛啊!!!

    谁说我没图,看图文并茂:

    aa

    这些卡片在app中是以3位数字作为id编号的,可见数量实在不少。

    这样不断循环,耗时费力,截完后累觉不爱了 :-(

    Pythoner 的解决办法


    第一版的程序

    实现功能:处理图像(裁剪 + 旋转)

                        废话的流程图

    程序代码大致是这样的:

    深度截图20160412120109

    运行后的结果,黑斑也没有了,头也不歪了,还有了新后缀,Ta好我也好:

    深度截图20160413115157

    第二版的程序


    改进之处:图片文件自动命名

    图片的命名规则:人物名字_属性_等级_星星数-N.png (其中N为正整数)

    例如上图中的海未应该如此命名,园田海未_Pure_R_3-1.png

    程序思路

    1.人物名字如何命名?

    建立相应的文件夹,将截图分类放到对应的文件夹下面,脚本获取文件夹名作为新名字的第一部分。

    2.属性如何确认?

    比较各张截图,人物卡片的右下角在固定位置有相同大小的圆圈,我们取坐标点 (920, 1400) 的 RGB 值判断。

    深度截图20160413111934

    深度截图20160413112219  深度截图20160413112359

    下图右边是我一开始定义的字典,左边是运行过程中打印出来的 color

    深度截图20160413114916

    3.如何确定星星数(也就是角色的稀有度)?

    搞完了右下角,我们来搞左下角。再做几条辅佐线,以确定来自星星的你的距离。

    部分细心的读者肯定看到我从 ps 转向了 狗(嗯,我不记得软件的名字,除了图标)。

    纵坐标大概递加 55px,获取坐标点的 color 值,如果不是 (8, 4, 34, 255) 计数变量的值就加1。

    发现第二个元素的值有一点差别,其实也可以取指定位置的元素用来判断。

    深度截图20160413141858  深度截图20160413150055

    为了阅读的方便,数星星的代码搬到了这里。

    def get_count_of_star(image):
        count = 0
        positon_of_star = (33, 1090)    #星星的初始位置,但星星是会运动的
        for i in range(0,8):            #[0,8) 星星最多有8个
            color = image.getpixel(positon_of_star)         #星星有发亮吗?
            positon_of_star = (33, positon_of_star[1]+55)   #坐标下移到下一个星星处
            if color[2] != 34:          #只比较第三个元素
                count += 1              #不是暗的,说明星星是有效的
        return count

    参数 image 是已打开的图像,返回发亮星星的个数。

    4.如何确定左上角的等级?

    另外因为我不会文字识别,左上角的等级字符就无法获取,但是并不表示就不能解决这个问题。

    观察众多的卡片发现了一条得到等级的捷径,这条捷径就是等级跟星星数是有对应关系的:

    等级(左上角)

    星星数(左下角)

    N 1,  2
    R 3,  4
    SR 5,  6
    UR 7,  8

    有时只要转换一下思考的角度,也同样能解决问题。

    代码设计


    (一)工作路径相关

    import os
    os.getcwd() # 查看当前工作目录
    os.chdir("/home/luoxu") # 改变目录
    
    for root, dirs, files in os.walk(dir):
        for name in files:
            print os.path.join(root, name)

    os.listdir 可以列出 dir 里面的所有文件和目录,但不包括子目录中的内容
    os.walk 可以遍历下面的所有目录,包括子目录,返回路径,路径下目录的元组和文件的元祖。

    (二)获取某个目录下的 png 图像文件

    glob 是 python 自带的一个文件操作相关模块,可以用来查找匹配的文件。

    import glob
    glob.glob('/home/luoxu/*.png')

    参数是某个路径字符串,字符串可以为绝对路径也可以为相对路径,字符串最后部分表示匹配的文件类型。

    *, ? , [ ] 三个通配符,* 代表 0 个或多个字符,? 代表一个字符,[ ] 匹配指定范围内的字符,如[0-9]匹配数字。

    该方法返回所有匹配的文件路径列表。

    (三)图像处理相关

    图像处理用的是 Pillow 模块,官方网站上有手册 http://effbot.org/zone/pil-index.htm

    from PIL import Image
    im = Image.open("lenna.jpg")      #打开图像
    box = (200, 0, 1720, 1080)
    im.crop(box)                      #按box的对角坐标裁剪区域
    im.transpose(Image.ROTATE_90)     #逆时针旋转90度
    im.save('newFileName.png', "PNG") #保存新的图像文件newFileName.png
    color = i.getpixel((920,1400))    #获取某像素点的rgb值

    脚本只用这几个方法,更详细的细节还是使用的时候去阅读文档。

    (四)一些变量的说明

    box = (200, 0, 1720, 1080)

    原图是1920x1080,裁剪后是1520x1080,对角(200,0), (1720,1080)

    POSITION = (920,1400)

    右下角确定属性用的,通过 getpixel(POSITION) 方法获得的值有三种情况:

    attributes = {'Smile':(234,0,115,255),
                  'Pure' :(34,170,85,255),
                  'Cool' :(0,153,238,255)
                 }

    星星数和等级的映射表

    grade = {1:'N', 2:'N',
             3:'R', 4:'R',
             5:'SR', 6:'SR',
             7:'UR', 8:'UR'
            }

    (五)数星星

    回去看上文相关的部分。

    (六)另外

    我再提供两张截图,如果读者愿意可以拿去测试代码,不一样的是,不需要旋转,裁剪区域不同。

    Screenshot-624

    Screenshot-941

    完整的脚本代码 [image-processing.py] :

     1 #!/usr/bin/env python3.5
     2 # -*- coding:utf-8 -*-
     3 
     4 from PIL import Image
     5 import glob, os
     6 
     7 box = (200, 0, 1720, 1080)  #裁剪区域
     8 POSITION = (920,1400)       #属性坐标
     9 
    10 #属性-颜色映射
    11 attributes = {'Smile':(234,0,115,255),
    12               'Pure' :(34,170,85,255),
    13               'Cool' :(0,153,238,255)
    14              }
    15 #星星数-等级映射
    16 grade = {1:'N', 2:'N',
    17          3:'R', 4:'R',
    18          5:'SR', 6:'SR',
    19          7:'UR', 8:'UR'
    20         }
    21 
    22 def image_processing(dirpath, dirname):
    23     os.chdir(dirpath + '/' + dirname)
    24 ##    print(dirpath + dirname)
    25     s_cnt = p_cnt = c_cnt = 1
    26     images = glob.glob('*.png')     #获取所有png文件
    27     for image in images:
    28         try:
    29             im = Image.open(image)
    30             new_im = im.crop(box).transpose(Image.ROTATE_90)    #裁剪和旋转
    31 ##            filename, ext = os.path.splitext(image)
    32 ##            new_im.save(filename + "-new.png", "PNG")
    33             color = new_im.getpixel(POSITION)                   #属性坐标->颜色元组
    34             count = get_count_of_star(new_im)                   #判断星星的数量
    35             if color == attributes['Smile']:                    #确认颜色对应Smile属性
    36                 new_im.save(dirname + "_Smile_{grade}_{count}-{number}.png".format(grade=grade[count],count=count,number=s_cnt), "PNG")
    37                 s_cnt += 1
    38             elif color == attributes['Pure']:
    39                 new_im.save(dirname + "_Pure_{grade}_{count}-{number}.png".format(grade=grade[count],count=count,number=p_cnt), "PNG")
    40                 p_cnt += 1
    41             elif color == attributes['Cool']:
    42                 new_im.save(dirname + "_Cool_{grade}_{count}-{number}.png".format(grade=grade[count],count=count,number=c_cnt), "PNG")
    43                 c_cnt += 1
    44             else:
    45                 new_im.save(dirname + "-new.png", "PNG")
    46 
    47         except IOError:
    48             print('{}: io error!'.format(image))
    49 
    50     print(dirname + ':finished.')
    51 
    52 
    53 def get_count_of_star(image):
    54     count = 0
    55     positon_of_star = (33, 1090)    #星星的初始位置,但星星是会运动的
    56     for i in range(0, 8):           #[0,8) 星星最多有8个
    57         color = image.getpixel(positon_of_star)         #星星有发亮吗?
    58         positon_of_star = (33, positon_of_star[1]+55)   #坐标下移到下一个星星处
    59         if color[2] != 34:          #只比较第三个元素
    60             count += 1              #不是暗的,说明星星是有效的
    61     return count
    62 
    63 
    64 if __name__ == '__main__':
    65     for dirpath, dirnames, filenames in os.walk(os.getcwd()):
    66         for dirname in dirnames:
    67     ##        path = dirpath + dirname
    68             image_processing(dirpath, dirname)

    运行结果


    深度截图20160413153154

    深度截图20160413154739

    运行前准备好,文件夹下放着待处理的截图:
    深度截图20160413153215

    深度截图20160413153233

    深度截图20160413153300

    脚本执行后得到我们想要的结果:

    深度截图20160414005905

    从上面的结果可以看出,脚本还是存在一些问题的:1,用于比对颜色属性(右下角)的值定的太死,有的像素点RGB值差了一点,结果就不能识别了,上文我提到过一次;2.对于不确定截图统一命名是名字-new导致覆盖问题。

    我还专门做了动态图片:

    image-processing

    Pythonner 的解决办法


    书呆子 我不是Pythonner,我不知道Pythonner is how thinking 破碎的心

    不过我知道怎样就简单,就是什么都不做,不去 care 那些黑边,呵呵。

    最后


    下载 https://pypi.python.org/pypi/Pillow/

    手册 http://effbot.org/imagingbook/

    github https://github.com/python-pillow/Pillow

    末了发一下桌面,听说下雨天 乌云 PyCharm 和 LoveLive! 更配哦!

    深度截图20160410194054

    不要再往下看了,妹子在上面向上指向上指向上指(不明白不理解日本人发明了emoji,却迟迟不包含 LoveLive! 的手势)

  • 相关阅读:
    顺序栈的实现
    创建HttpRequest传输数据
    .net Json对象序列化和反序列化
    SqlBulkCopy类数据导入
    两表更新:根据条件从一个表里面查询出符合条件的结果更新另一个表
    javascript实现绚丽效果
    SQL SERVER 表结构修改
    SqlCacheDependency Application
    运用泛型实现增删改
    实现数组的全排列(百度笔试题)
  • 原文地址:https://www.cnblogs.com/luoxu34/p/5389630.html
Copyright © 2011-2022 走看看