[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! 的手勢)

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM