Python趣味編程實現手繪風視頻示例
在正文開始之前,先看一下最初效果,下面是單張圖片轉換前後對比
圖一
圖二
圖三
為瞭增加趣味性,後面將這段代碼應用到一個視頻中,加上一個背景音樂,新鮮的 “手繪風視頻” 出爐
Python 手繪風視頻制作!
“手繪風”實現步驟
講解之前,需要瞭解手繪圖像的三個主要特點:
- 圖片需為灰度圖,是單通道的;
- 邊緣部分線條較重塗抹為黑色,相同或相近像素值轉換後趨於白色;
- 在光源效果的加持下,灰度變化可模擬人類視覺的遠近效果
讀取圖片,轉化為數組
因為後面要用到像素計算,為瞭方便,事先將讀取後的圖片轉化為數組
a = np.asarray(Image.open("Annie1.jpg").convert('L')).astype('float')
計算 x,y,z 軸梯度值,並歸一化
剛才提到手繪照片的一個特點,就是 手繪照片對邊緣區域更加側重,定位圖片邊緣部分,最有效方式就是計算梯度,用灰度變化來模擬圖片遠近效果,depth 表示預設深度,z 軸默認梯度為 1
depth = 10. # (0-100) grad = np.gradient(a) # 取圖像灰度的梯度值 grad_x, grad_y = grad # 分別取橫縱圖像梯度值 grad_x = grad_x * depth / 100. grad_y = grad_y * depth / 100.
對梯度值完成歸一化操作
A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.) uni_x = grad_x / A uni_y = grad_y / A uni_z = 1. / A
加入光源效果
手繪風圖片除瞭計算梯度值之外,還需要考慮光源影響;根據光源入射的角度不同最有對x,y,z 各軸上的梯度值有不同程度的影響,添加一個模擬光源,放置在斜上方,與 x , y 分別形成兩個夾角
並且這兩個夾角是通過實驗得到是已知的,然後根據正弦餘弦函數計算出最終新的像素值
vec_el = np.pi / 2.2 # 光源的俯視角度,弧度值 vec_az = np.pi / 4. # 光源的方位角度,弧度值 dx = np.cos(vec_el) * np.cos(vec_az) # 光源對 x軸的影響 dy = np.cos(vec_el) * np.sin(vec_az) # 光源對 y軸的影響 dz = np.sin(vec_el) # 光源對z 軸的影響 b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z) # 光源歸一化,8 255 b = b.clip(0, 255)# 對像素值低於0,高於255部分做截斷處理
導出圖片,並保存
im.save("Annie_shouhui.jpg")
以下是該步驟涉及到的的全部代碼
from PIL import Image import numpy as np a = np.asarray(Image.open("Annie1.jpg").convert('L')).astype('float') depth = 10. # (0-100) grad = np.gradient(a) # 取圖像灰度的梯度值 grad_x, grad_y = grad # 分別取橫縱圖像梯度值 grad_x = grad_x * depth / 100. grad_y = grad_y * depth / 100. A = np.sqrt(grad_x ** 2 + grad_y ** 2 + 1.) uni_x = grad_x / A uni_y = grad_y / A uni_z = 1. / A vec_el = np.pi / 2.2 # 光源的俯視角度,弧度值 vec_az = np.pi / 4. # 光源的方位角度,弧度值 dx = np.cos(vec_el) * np.cos(vec_az) # 光源對 x軸的影響 dy = np.cos(vec_el) * np.sin(vec_az) # 光源對 y軸的影響 dz = np.sin(vec_el) # 光源對z 軸的影響 b = 255 * (dx * uni_x + dy * uni_y + dz * uni_z) # 光源歸一化 b = b.clip(0, 255) im = Image.fromarray(b.astype('uint8')) # 重構圖像 im.save("Annie_shouhui.jpg")
制作手繪風視頻
圖片轉化後的效果雖然也不錯,但圖片畢竟是靜態的,人作為視覺動物,如果能做成動態的那再好不過瞭,知道上面的方法之後,隻需對視頻再加上一個拆幀合並操作,就能制作一個手繪風 視頻效果
you-get 下載視頻
這裡我用 you-get 命令在 B 站上找瞭一個視頻,下載瞭下來,
you-get --format=dash-flv -o ./ https://www.bilibili.com/video/BV1tT4y1j7a9?from=search&8014393453748720686
下載完之後,用 OpenCV2 對視頻進行切幀操作,切幀同時對圖片進行轉化,寫出到本地視頻文件中
vc = cv2.VideoCapture(video_path) c = 0 if vc.isOpened(): rval,frame = vc.read() height,width = frame.shape[0],frame.shape[1] print(height, width) else: rval = False height,width = 960,1200 # jpg_list = [os.path.join('Pic_Directory/',i) for i in os.listdir('Pic_Directory') if i.endswith('.jpg')] fps = 24 # 視頻幀率 video_path1 = './text.mp4' video_writer = cv2.VideoWriter(video_path1,cv2.VideoWriter_fourcc(*'mp4v'),fps,(width,height)) while rval: rval,frame = vc.read()# 讀取視頻幀 img = coonvert_jpg(Image.fromarray(frame)) frame_converted = np.array(img) # 轉化為三通道 image = np.expand_dims(frame_converted,axis = 2) result_arr = np.concatenate((image,image,image),axis = -1) video_writer.write(result_arr) print('Sucessfully Conveted---------{}'.format(c)) c = c + 1 if c >= 3000: break video_writer.release()
在圖片序列提取時,需要註意一點,因為轉化後的圖片是單通道的,直接借助 OpenCV 生成視頻序列是無法播放的,需增加一個步驟單通道轉化為三通道!
# 轉化為三通道 image = np.expand_dims(frame_converted,axis = 2) result_arr = np.concatenate((image,image,image),axis = -1)
想讓生成的視頻更有感覺的話可以添加一個背影音樂,借助剪輯軟件、Python 都可,這裡建議最好用剪輯軟件,原因是 Python 自定義增加音頻效果並不理想,添加音樂時需要有實時反饋, 而 Python 暫時無法滿足此要求
小結
本文主要介紹瞭如何用 Python將一張圖片轉化為手繪風格,代碼量很少但涉及知識領域與數學、物理相關,所以不容易理解,本篇文章目的隻是為瞭向大傢介紹圖片手繪風轉換有這麼一種方法,當然如果有感興趣的小夥伴可以深究一下
好瞭以上就是本篇文章的全部內容瞭,最後感謝大傢的閱讀,我們下期見,希望大傢以後多多支持WalkonNet!
推薦閱讀:
- Python編程實現小姐姐跳舞並生成詞雲視頻示例
- Python自動化短視頻生成腳本實現熱門視頻流水線生產
- Python+OpenCV讀寫視頻的方法詳解
- 如何使用Python的OpenCV庫處理圖像和視頻
- Python編程利用Numpy和PIL庫將圖片轉化為手繪