2018年的三月份寫過一篇:《小豬的Python學習之旅 —— 18.Python微信轉發小宇宙早報》,從一開始 手動轉發別人發的新聞早報,到編寫腳本到自動轉發。而後畢竟這個是別人整理的,並不能保證準時,不少 時候早報變成了午報,而後還有存檔問題,每次想看以前的早報就,都要微信搜聊天記錄。嘖嘖,我琢磨着, 要不本身來整理早報。因而偷偷開始手動去整理早報,而後發在公號「摳腚男孩」上:python
畢竟本身整理的,不肯定看官能不能接受,得找幾個小火汁來驗證下下~數據庫
而後,把我整理的日報,套模板,改下日期,丟到童鞋羣裏看看他們有木有發現,測試兩天後~bash
行吧,我就發吧,接下來簡單說下天天發早報的流程。微信
接着檢查下,沒什麼問題,就發佈了。一開始,天天要耗費將近一個小時的時間來完成這件 事情,天天的摸魚時間這麼寶貴,花一個小時來作這件事情,顯得有些得不償失。做爲一個 **勤(lan)奮(duo)**的開發仔,確定要想辦法來優化下,最好的結果就是:發早報徹底自動化~app
固然,也是想一想而已,有讀者可能好奇,爲啥標題是80%,那麼剩下的20%是什麼?微信公衆平臺
答:15%是新聞的過濾,篩選有意思的新聞標題,這一步其實能夠優化,最簡單的就是,直接爬熱搜 或者評論多的新聞標題,可是這樣莫得靈魂,我更傾向於訓練一個機器人,讓他自動去篩選標題。 可是目前還不會這些東西,因此先擱一擱咯,還得手動去篩選~ 剩下的5%是把早報發表到公號上,其實也能夠自動化,經過selenium寫個腳本自動點點點 就行了,不過我的感受意義不大,並且我習慣發出去以前還須要預覽下,確認內容 無誤後才發送,畢竟文章發佈後只能改標題,不能修改內容。編輯器
說下我目前想達到的一個形態吧:ide
好吧,大概的路線就這樣,本節先從製做早報封面圖開始**優(偷)化(懶)**吧。函數
先來看看我天天的早報封面圖吧,是介樣的:post
組成部分:背景圖(900*383)+ 大標題(52px) + 二級標題(44px) 接着縮下我是製做這種封面圖的流程:
爲了讓大家感覺這個流程,我大概錄了個Gif演示下,實際操做耗時遠比這個久(7,8分鐘的樣子)。
天天如機器搬重複着這樣的操做,多呆哦~而後,我居然堅持了60+天(┬_┬); 着實須要一個腳本,把我從這種繁冗的工做中解脫出來。
讀者可能對圖源感興趣,我通常喜歡直接保存壁紙APP裏精選的靚圖, 固然也能夠自行爬取一些壁紙站點。另外,我發現,有些長圖,其實 能夠裁剪成幾份來做爲多期的封面,好比這樣的圖:
分割成兩個,挺好看的。
感受像像集卡同樣,有點意思。
先來提取下圖片處理的流程:
行吧,處理流程說了,說下用到的Python庫,直接經過pip命令安裝便可: (主要使用opencv來進行圖片處理,pillow即PIL庫)
pip install numpy
pip install opencv-python
pip install pillow
複製代碼
保持長寬比,設置爲900px,咱們經過opencv提供的imread()
方法來獲取一個圖片對象,而後進行 相關操做。先獲取一波高和寬度
import cv2
img = cv2.imread('1.jpg')
(h, w) = img.shape[:2]
print(h, w)
# 輸出結果:956 1080
複製代碼
若是你想把圖片顯示出來,能夠直接調用imshow()
方法:
cv2.imshow('image', img) # 參數依次爲:窗口名稱(窗口不能重名),讀入的圖片。
複製代碼
上述的代碼,運行後會發現窗口一閃而過,能夠調用waitKey()
讓窗口不關閉
cv2.waitkey() # 想窗口一直不關閉,能夠不填參數或填0;也能夠指定一個等待時間(單位毫秒)
# 在一個時間段內,等待用戶按鍵觸發關閉,若是一直不按鍵,到了時間會自動關閉。
複製代碼
可是,這裏其實隱藏着一個小坑:若是你的圖片是中文文件名或文件路徑包含中文,調用imread
會報錯,好比:
img = cv2.imread('測試.jpg')
cv2.imshow('img', img)
cv2.waitKey()
複製代碼
運行結果:
一樣調用imwrite()
方法也是沒法生成帶有中文路徑的圖片的,能夠自行編寫兩個函數來解決:
def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img
def cv_imwrite(img, file_path):
cv2.imencode('.jpg', img)[1].tofile(file_path)
複製代碼
行吧,能獲取到寬高了,接着調用opencv提供的resize()
方法調整圖片的尺寸,參數依次爲: 圖片,寬高元組,還有一個可選參數:interpolation插值方法,默認使用INTER_LINEAR 雙線性插值,其餘的還有:INTER_NEAREST,INTER_AREA,INTER_CUBIC,INTER_LANCZOS4。
import cv2
import numpy as np
def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img
def cv_imwrite(img, file_path):
cv2.imencode('.jpg', img)[1].tofile(file_path)
img = cv_imread('測試.jpg')
(h, w) = img.shape[:2]
print("縮放前的尺寸:", img.shape[:2])
res = cv2.resize(img, (900, round(h * (900 / w))))
print("裁剪後的尺寸:", res.shape[:2])
複製代碼
運行結果:
縮放前的尺寸: (956, 1080)
縮放後的尺寸: (797, 900)
複製代碼
縮放完,接着就到裁剪了,先是計算圖片能裁剪成幾張:
crop_pic_count = int(ch / 383)
print("圖片能夠裁剪爲:%d張" % crop_pic_count)
# 輸出結果:圖片能夠裁剪爲:2張
複製代碼
接着是裁剪圖片,能夠經過:圖片對象[y軸起始座標:y軸終點座標, x軸起始座標:x軸終點座標],來裁剪。 因此,咱們要計算每一個裁剪區域的對應的座標方位。另外,這裏還要考慮一個偏移,以中間位置爲基準進行 裁剪,這樣感受會好一點。給個加偏移和不加偏移裁剪後的對比圖吧:
so,我仍是傾向於加偏移,計算偏移也很簡單,直接拿高對383進行求餘,而後除以2。
start_y = int(ch % 383 / 2)
複製代碼
接着根據能切成的圖片張數,計算怎麼裁剪
for i in range(0, crop_pic_count):
crop_img = res[383 * i + start_y: 383 * (i + 1) + start_y, 0:900]
cv_imwrite(crop_img, '剪切圖%d.jpg' % (i+1))
複製代碼
裁剪後的圖片:
行吧,圖片也裁剪好了,接着就是圖片加字了,能夠經過opencv提供的putText()
添加文字, 參數依次爲: 圖像,文字內容, 座標 ,字體,大小,顏色,字體厚度。
img = cv_imread('剪切圖0.jpg')
cv2.putText(img, 'Test', (50, 300), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 255), 2)
cv2.imshow('image', img)
cv2.waitKey()
複製代碼
運行結果以下:
加字成功,挺簡單的,是吧?可是,若是你添加的文字不是字母或數字,而是中文的話,那麼恭喜,黑人問號~
緣由是:opencv自帶的putText函數沒法輸出utf8類型的字符,所以沒法將中文打印到圖片上。 兩個解決方法:
這裏採用的是方法二,text函數的參數:起始座標元組,文字內容,字體,顏色。 問題來了,怎麼肯定繪製文字的起始座標?
答:若是你要程序算,挺麻煩的,文字寬度怎麼獲取,既然圖片尺寸固定,文字長度不變,爲什麼不取巧一下呢?
直接在Pixelmator Pro上把文字拖好,而後複製下座標,不就行了~
另外,這裏筆者用的字體是 蘋果-簡,常規體
,能夠自行下載,記得把字體文件名改爲英文文件名, 否則,會讀取不到字體。好的,擼代碼試試:
img = cv_imread('剪切圖0.jpg')
# 將圖片從OpenCv格式轉爲PIL格式
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 加載字體(字體文件名,字體大小)
title_font = ImageFont.truetype('apple-simple.ttf', 52)
date_font = ImageFont.truetype('apple-simple.ttf', 44)
# 繪製文字的位置
title_pos = (236, 110)
date_pos = (338, 192)
# 繪製內容
title_content = u"『摳腚早報速讀』"
date_content = u"第190111期"
# 繪製
draw = ImageDraw.Draw(img_pil)
draw.text(title_pos, title_content, font=title_font, fill=(255, 255, 255))
draw.text(date_pos, date_content, font=date_font, fill=(255, 255, 255))
img_open_cv = cv2.cvtColor(np.asarray(img_pil), cv2.COLOR_RGB2BGR)
cv_imwrite(img_open_cv, "加字後.jpg")
複製代碼
接着看下輸出的圖片:
嘖嘖嘖,完美,到此自動裁剪生成一個早報封面的腳本就完成啦,接下來咱們來補全和完善下咱們的程序。
就是加了循環,一些小邏輯,比較簡單,註釋也比較清晰,就不叨逼叨了,直接上完整代吧:
# -*- coding: utf-8 -*-
import os
import cv2
import numpy as np
import time
from PIL import Image, ImageDraw, ImageFont
from datetime import datetime, timedelta
import shutil
pic_source_dir = os.path.join(os.getcwd(), "news_pic_source\\") # 原圖路徑
pic_crop_dir = os.path.join(os.getcwd(), "news_pic_crop\\") # 裁剪後的圖片路徑
pic_font_dir = os.path.join(os.getcwd(), "news_pic_font\\") # 加字後的圖片路徑
start_date = "20190112" # 繪製圖片的其起始日期
# 判斷文件夾是否存在,不存在則新建
def is_dir_existed(path, mkdir=True):
if mkdir:
if not os.path.exists(path):
os.makedirs(path)
else:
return os.path.exists(path)
# opencv讀取中文路徑名會亂碼
def cv_imread(file_path):
cv_img = cv2.imdecode(np.fromfile(file_path, dtype=np.uint8), -1)
return cv_img
# opencv寫入中文路徑名會亂碼
def cv_imwrite(img, file_path):
cv2.imencode('.jpg', img)[1].tofile(file_path)
# 把原圖裁剪爲多個小圖(900*383)
def crop_little_pic(pic_path):
img = cv_imread(pic_path)
(sh, sw) = img.shape[:2]
# 將圖片的寬設置爲900,高則按比例縮放
res = cv2.resize(img, (900, round(sh * (900 / sw))))
# 獲取縮放後的高和寬,判斷圖片可裁剪的張數
(ch, cw) = res.shape[:2]
crop_pic_count = int(ch / 383)
# 計算Y軸偏移
start_y = int(ch % 383 / 2)
# 根據圖片的張數來決定怎麼裁剪
for i in range(0, crop_pic_count):
crop_img = res[383 * i + start_y: 383 * (i + 1) + start_y, 0:900]
cv_imwrite(crop_img, os.path.join(pic_crop_dir, str(int(round(time.time() * 1000))) + '.jpg'))
# 繪製文字
def draw_text(pic_path, date):
img = cv_imread(pic_path)
# 將圖片從OpenCv格式轉爲PIL格式
img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
# 加載字體(字體文件名,字體大小)
title_font = ImageFont.truetype('apple-simple.ttf', 52)
date_font = ImageFont.truetype('apple-simple.ttf', 44)
# 繪製文字的位置
title_pos = (236, 110)
date_pos = (316, 192)
# 繪製內容
title_content = u"『摳腚早報速讀』"
date_content = u"第%s期" % date[2:]
# 繪製
draw = ImageDraw.Draw(img_pil)
draw.text(title_pos, title_content, font=title_font, fill=(255, 255, 255))
draw.text(date_pos, date_content, font=date_font, fill=(255, 255, 255))
img_open_cv = cv2.cvtColor(np.asarray(img_pil), cv2.COLOR_RGB2BGR)
cv_imwrite(img_open_cv, os.path.join(pic_font_dir, date[2:] + '.jpg'))
# 遍歷得到某類文件路徑列表
def fetch_file_path(path, file_type):
file_list = []
f = os.listdir(path)
for i in f:
if i.endswith(file_type):
file_list.append(os.path.join(path, i))
return file_list
# 構造生成日期列表
def init_date_list(begin_date, count):
d_list = []
begin_date = datetime.strptime(begin_date, "%Y%m%d")
end_date = datetime.strptime((datetime.now() + timedelta(days=count)).strftime("%Y%m%d"), "%Y%m%d")
while begin_date <= end_date:
date_str = begin_date.strftime("%Y%m%d")
d_list.append(date_str)
begin_date += timedelta(days=1)
return d_list
if __name__ == '__main__':
is_dir_existed(pic_source_dir)
while True:
choice = input(
"%s\n請輸入你想進行的操做\n1.進行圖片裁剪\n2.圖片加字\n3.清空裁剪文件夾\n4.清空加字文件夾\n5.退出程序\n%s\n" % ('=' * 32, '=' * 32))
if choice == '1':
is_dir_existed(pic_crop_dir)
pic_path_list = fetch_file_path(pic_source_dir, ".jpg")
if len(pic_path_list) == 0:
print("原圖文件夾中無圖片,請先添加圖片!")
else:
print("開始批量裁剪...")
begin = datetime.now()
for pic in pic_path_list:
crop_little_pic(pic)
end = datetime.now()
print("批量裁剪完畢,生成圖片:%d張,耗時:%s秒" % (len(fetch_file_path(pic_crop_dir, ".jpg")), (end - begin).seconds))
elif choice == '2':
is_dir_existed(pic_font_dir)
crop_path_list = fetch_file_path(pic_crop_dir, ".jpg")
date_list = init_date_list(start_date, len(crop_path_list) + 1)
if len(crop_path_list) == 0:
print("裁剪文件夾中無圖片,請先生成裁剪圖片!")
else:
print("開始批量加字...")
begin = datetime.now()
print(len(crop_path_list), len(date_list))
for i in range(len(crop_path_list)):
draw_text(crop_path_list[i], date_list[i])
end = datetime.now()
print("批量加字完畢,處理圖片:%d張,耗時:%s秒" % (len(fetch_file_path(pic_font_dir, ".jpg")), (end - begin).seconds))
elif choice == '3':
if is_dir_existed(pic_crop_dir, False):
shutil.rmtree(pic_crop_dir)
print("文件夾刪除成功!")
else:
print("文件夾不存在,刪除失敗~")
elif choice == '4':
if is_dir_existed(pic_font_dir, False):
shutil.rmtree(pic_font_dir)
print("文件夾刪除成功!")
else:
print("文件夾不存在,刪除失敗~")
elif choice == '5':
exit("退出程序~")
else:
print("錯誤序號,請確認後從新輸入!!!")
複製代碼
執行前,先準備一波圖片原圖,這裏準備了:
接着運行一波代碼,運行後依次鍵入1,2進行裁剪和加字:
嘖嘖,94張原圖生成了243張封面圖,並且,只花了十幾秒,打開生成的文件夾看一波:
都生成到9月份了,2333,真人生苦短,我用Python,此處應該有掌聲~
另外前幾天寫了個腳本是採集一堆視頻第一幀而後進行處理的,趕腳有同窗會須要,把核心代碼也貼下把~
# 截取視頻的第一幀
def fetch_video_first_frame(path_list):
for mp4 in path_list:
cap = cv2.VideoCapture(mp4)
if cap.isOpened():
ret, im = cap.read()
cv2.imencode('.jpg', im)[1].tofile(
os.path.join(pic_source_output_dir, mp4.split("\\")[-1]).replace("mp4", "jpg"))
cap.release()
複製代碼
行吧,本節內容就這麼多,有疑問的歡迎在評論區留言~
Tips:公號目前只是堅持發早報,在慢慢完善,有點心虛,只敢貼個小圖,想看早報的能夠關注下~