起因
喜歡的歌,靜靜地聽;喜歡的人,遠遠的看。30天前,就是3月14號,我情不自禁地走近了《LoveLive!學院偶像祭》,這是我的第一張卡片(見下圖)。第二天也就是3月15日,海未生日了。
之后我一直搜集游戲過程中遇到的卡片(截屏),卡片本身有一定的比例,而我的手機屏幕分辨率是 1920x1080,截完的圖像下面這樣。整個游戲界面並沒有充滿屏幕,所以有黑邊;卡片比游戲界面小,截出的圖很不美觀而且方向不正。
中間的卡片的區域是 1080x1520
我本人並不是處女座,然而也不能忍受不美好的事物。於是一步一步地走上了程序員這條路。
我以為做程序員可以填滿人生的遺憾。然而,制造更多遺憾的。卻偏偏是做程序員。
(問:一個什么都擁有的程序猿他還缺少什么?)
非程序員的解決辦法
while( true ) { 用 PS 打開截圖; 添加輔助線; 裁剪區域; 旋轉正圖像; sit,不對,是save; }
沒圖你說個毛啊!!!
誰說我沒圖,看圖文並茂:
這些卡片在app中是以3位數字作為id編號的,可見數量實在不少。
這樣不斷循環,耗時費力,截完后累覺不愛了 :-(
Pythoner 的解決辦法
第一版的程序
實現功能:處理圖像(裁剪 + 旋轉)
廢話的流程圖
程序代碼大致是這樣的:
運行后的結果,黑斑也沒有了,頭也不歪了,還有了新后綴,Ta好我也好:
第二版的程序
改進之處:圖片文件自動命名
圖片的命名規則:人物名字_屬性_等級_星星數-N.png (其中N為正整數)
例如上圖中的海未應該如此命名,園田海未_Pure_R_3-1.png
程序思路
1.人物名字如何命名?
建立相應的文件夾,將截圖分類放到對應的文件夾下面,腳本獲取文件夾名作為新名字的第一部分。
2.屬性如何確認?
比較各張截圖,人物卡片的右下角在固定位置有相同大小的圓圈,我們取坐標點 (920, 1400) 的 RGB 值判斷。
下圖右邊是我一開始定義的字典,左邊是運行過程中打印出來的 color
3.如何確定星星數(也就是角色的稀有度)?
搞完了右下角,我們來搞左下角。再做幾條輔佐線,以確定來自星星的你的距離。
部分細心的讀者肯定看到我從 ps 轉向了 狗(嗯,我不記得軟件的名字,除了圖標)。
縱坐標大概遞加 55px,獲取坐標點的 color 值,如果不是 (8, 4, 34, 255) 計數變量的值就加1。
發現第二個元素的值有一點差別,其實也可以取指定位置的元素用來判斷。
為了閱讀的方便,數星星的代碼搬到了這里。
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' }
(五)數星星
回去看上文相關的部分。
(六)另外
我再提供兩張截圖,如果讀者願意可以拿去測試代碼,不一樣的是,不需要旋轉,裁剪區域不同。
完整的腳本代碼 [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)
運行結果
腳本執行后得到我們想要的結果:
從上面的結果可以看出,腳本還是存在一些問題的:1,用於比對顏色屬性(右下角)的值定的太死,有的像素點RGB值差了一點,結果就不能識別了,上文我提到過一次;2.對於不確定截圖統一命名是名字-new導致覆蓋問題。
我還專門做了動態圖片:
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! 更配哦!
不要再往下看了,妹子在上面(不明白不理解日本人發明了emoji,卻遲遲不包含 LoveLive! 的手勢)