? ? 老猿Python博文目錄:https://blog.csdn.net/LaoYuanPython ?

一、引言
前幾天有博友咨詢,能否在視頻中實作雪花飄落的效果,答案是肯定的,老猿前天簡單構思了一下,利用周末時間,使用OpenCV-Python通過影像回圈顯示方式,實作了給圖片顯示增加動態雪花飄落的效果,經過不停優化,效果還是不錯的,花了半天時間將實作程序總結成文,供大家參考,
二、案例背景
本次雪花來源于如下圖片(檔案名:f:\pic\snow.jpg):

背景可以是任意圖片,下面是老猿在網上找到的一張珠峰影像(檔案名:f:\pic\Qomolangma2.jpg):

珠峰背景的天空飄落著紛紛揚揚的雪花,意境不錯吧?
三、實作思路
要實作雪花飄落,單張圖片的單次顯示肯定不夠,需要不停回圈顯示圖片,并且在每次圖片顯示時,生成新的雪花并更新圖片中已有雪花的位置,這就需要將圖片中每個雪花的位置精確管理,
自然界的雪花大小是不同的,因此為了提升逼真效果,還需要使得雪花大小在一定范圍內隨機變化和旋轉,
不停產生大小不同的雪花,如果每次產生雪花都對雪花進行變換其實浪費了系統的資源,因此為了提升處理性能,只在程式開始初始化時一次批量生產各種不同大小、不同旋轉角度的各種雪花,后續程式生成雪花時,直接從批量生成的雪花中取一個作為要生成的雪花,而不用每次從基本的雪花影像開始進行變換,
四、關鍵實作代碼
4.1、生成各種雪花形狀
def initSnowShapes():
"""
從檔案中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉從而生成不同的雪花形狀,這些雪花形狀保存到全域串列中snowShapesList
"""
global snowShapesList
imgSnow = readImgFile(r'f:\pic\snow.jpg')
imgSnow = cv2.resize(imgSnow, None, fx=0.2, fy=0.2) #圖片檔案中的雪花比較大,需要縮小才能象自然的雪花形象
minFactor,maxFactor = 50,100 #雪花大小在imgSnow的0.5-1倍之間變化
for factor in range(minFactor,maxFactor,5): #每次增加5%大小
f = factor*0.01
imgSnowSize = cv2.resize(imgSnow, None, fx=f, fy=f)
for ange in range(0,360,5):#雪花0-360之間旋轉
imgRotate = rotationImg(imgSnowSize,ange)
snowShapesList.append(imgRotate)
4.2、產生一排雪花
def generateOneRowSnows(width,count):
"""
產生一排雪花物件,每個雪花隨機從snowShapesList取一個、橫坐標位置隨機、縱坐標初始為0
:param width: 背景影像寬度
:param count: 希望的雪花數
:return:一個包含產生的多個雪花物件資訊的串列,每個串列的元素代表一個雪花物件,雪花物件包含三個資訊,在snowShapesList的索引號、初始x坐標、初始y坐標(才生成固定為0)
"""
global snowShapesList
line = []
picCount = len(snowShapesList)
for loop in range(count):
imgId = random.randint(0,picCount-1)
xPos = random.randint(0,width-1)
line.append((imgId,xPos,0))
return line
4.3、將所有雪花物件融合到背景影像
def putSnowObjectToImg(img):
"""
將所有snowObjects中的雪花物件融合放到影像img中,融合時y坐標隨機下移一定高度,x坐標左右隨機小范圍內移動
"""
global snowShapesList,snowObjects
horizontalMaxDistance,verticalMaxDistance = 5,20 #水平方向左右漂移最大值和豎直方向下落最大值
snowObjectCount = len(snowObjects)
rows,cols = img.shape[0:2]
imgResult = np.array(img)
for index in range(snowObjectCount-1,-1,-1):
imgObj = snowObjects[index] #每個元素為(imgId,x,y)
if imgObj[2]>rows: #如果雪花的起始縱坐標已經超出背景影像的高度(即到達背景影像底部),則該雪花物件需進行失效處理
del(snowObjects[index])
else:
imgSnow = snowShapesList[imgObj[0]]
x,y = imgObj[1:] #取該雪花上次的位置
x = x+random.randint(-1*horizontalMaxDistance,horizontalMaxDistance) #橫坐標隨機左右移動一定范圍
y = y+random.randint(1,verticalMaxDistance) #縱坐標隨機下落一定范圍
snowObjects[index] = (imgObj[0],x,y) #更新雪花物件資訊
imgResult = addImgToLargeImg(imgSnow,imgResult,(x,y),180) #將所有雪花物件影像按照其位置融合到背景影像中
return imgResult #回傳融合影像
4.4、主函式
主函式讀入背景圖片,初始化雪花形狀串列,然后回圈自頂部產生一排新的雪花,并將所有雪花物件動態調整位置后融合到背景影像,每200毫秒回圈一次,直至按ESC退出,
def main():
global snowShapesList,snowObjects
bg = readImgFile(r'f:\pic\Qomolangma2.jpg')
initSnowShapes()
rows,cols = bg.shape[:2]
maxObjsPerRow = int(cols/100)
while(True):
snowObjects += generateOneRowSnows(cols,random.randint(0,maxObjsPerRow))
result = putSnowObjectToImg(bg)
cv2.imshow('result',result)
ch = cv2.waitKey(200)
if ch==27:break
4.5、其他說明
程式的執行直接直接main函式即可,另外本程式還用到了部分老猿經常用的公用函式,這部分函式包括readImgFile、addImgToLargeImg、rotationImg,其功能請參考《https://blog.csdn.net/LaoYuanPython/article/details/111351901 OpenCV-Python圖形影像處理:自用的一些工具函式功能及呼叫語法介紹》的介紹,根據介紹大家自行實作相關代碼并不難,
五、主程式完整代碼及雪花飄落效果
5.1、 主程式完整代碼
# -*- coding: utf-8 -*-
import cv2,random
import numpy as np
from opencvPublic import addImgToLargeImg,readImgFile,rotationImg
snowShapesList = [] #雪花形狀串列
snowObjects=[] #圖片中要顯示的所有雪花物件
def initSnowShapes():
"""
從檔案中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉從而生成不同的雪花形狀,這些雪花形狀保存到全域串列中snowShapesList
"""
global snowShapesList
imgSnow = readImgFile(r'f:\pic\snow.jpg')
imgSnow = cv2.resize(imgSnow, None, fx=0.2, fy=0.2) #圖片檔案中的雪花比較大,需要縮小才能象自然的雪花形象
minFactor,maxFactor = 50,100 #雪花大小在imgSnow的0.5-1倍之間變化
for factor in range(minFactor,maxFactor,5): #每次增加5%大小
f = factor*0.01
imgSnowSize = cv2.resize(imgSnow, None, fx=f, fy=f)
for ange in range(0,360,5):#雪花0-360之間旋轉,每次旋轉角度增加5°
imgRotate = rotationImg(imgSnowSize,ange)
snowShapesList.append(imgRotate)
def generateOneRowSnows(width,count):
"""
產生一排雪花物件,每個雪花隨機從snowShapesList取一個、橫坐標位置隨機、縱坐標初始為0
:param width: 背景影像寬度
:param count: 希望的雪花數
:y:當前行對應的豎直坐標
:return:一個包含產生的多個雪花物件資訊的串列,每個串列的元素代表一個雪花物件,雪花物件包含三個資訊,在snowShapesList的索引號、初始x坐標、初始y坐標(才生成固定為0)
"""
global snowShapesList
line = []
picCount = len(snowShapesList)
for loop in range(count):
imgId = random.randint(0,picCount-1)
xPos = random.randint(0,width-1)
line.append((imgId,xPos,0))
return line
def putSnowObjectToImg(img):
"""
將所有snowObjects中的雪花物件融合放到影像img中,融合時y坐標隨機下移一定高度,x坐標左右隨機小范圍內移動
"""
global snowShapesList,snowObjects
horizontalMaxDistance,verticalMaxDistance = 5,20 #水平方向左右漂移最大值和豎直方向下落最大值
snowObjectCount = len(snowObjects)
rows,cols = img.shape[0:2]
imgResult = np.array(img)
for index in range(snowObjectCount-1,-1,-1):
imgObj = snowObjects[index] #每個元素為(imgId,x,y)
if imgObj[2]>rows: #如果雪花的起始縱坐標已經超出背景影像的高度(即到達背景影像底部),則該雪花物件需進行失效處理
del(snowObjects[index])
else:
imgSnow = snowShapesList[imgObj[0]]
x,y = imgObj[1:] #取該雪花上次的位置
x = x+random.randint(-1*horizontalMaxDistance,horizontalMaxDistance) #橫坐標隨機左右移動一定范圍
y = y+random.randint(1,verticalMaxDistance) #縱坐標隨機下落一定范圍
snowObjects[index] = (imgObj[0],x,y) #更新雪花物件資訊
imgResult = addImgToLargeImg(imgSnow,imgResult,(x,y),180) #將所有雪花物件影像按照其位置融合到背景影像中
return imgResult #回傳融合影像
def main():
global snowShapesList,snowObjects
initSnowShapes()
bg = readImgFile(r'f:\pic\Qomolangma2.jpg')
rows,cols = bg.shape[:2]
maxObjsPerRow = int(cols/100)
while(True):
snowObjects += generateOneRowSnows(cols,random.randint(0,maxObjsPerRow))
result = putSnowObjectToImg(bg)
cv2.imshow('result',result)
ch = cv2.waitKey(200)
if ch==27:break
main()
5.2、雪花飄落特效

六、小結
本文介紹了通過OpenCV-Python以特定影像為背景制作雪花飄落特效的實作思路、關鍵函式功能以及主程式的完整代碼,雪花飄落特效實際上屬于影像融合的操作,只要掌握影像融合的基礎知識以及設計后實作思路,實作起來還是比較快的,效果也挺不錯,結合上面代碼,大家還可以調整雪花的大小以及飄雪的密集程度,
有了以上內容的介紹,要實作視頻加雪花特效就很容易了,只要將上述程序使用的關鍵步驟疊加Moviepy音視頻處理合成就可以實作,老猿對本文的代碼稍進行調整,然后寫了個三行代碼的函式就完成了相關處理,相信學習過Moviepy的都能很快實作,在此就不多介紹了,等過一陣子老猿再在Moviepy相關專欄發布相關實作,
以上實作程序需要注意:
-
雪花圖片一般會比圖片需要的效果大,怎么縮小到合適的大小需要多試一下,下面是才開始將原始圖片只縮寫一半之后的效果,

可以看到該效果就不太讓人滿意, -
控制好雪花左右移動以及下落的速度和幅度,太快、太慢以及幅度過大或過小都不太象在雪花飄落,
更多影像處理的介紹請參考專欄《OpenCV-Python圖形影像處理 https://blog.csdn.net/laoyuanpython/category_9979286.html》和《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初學者疑難問題集》相關文章,
寫博不易,敬請支持:
如果閱讀本文于您有所獲,敬請點贊、評論、收藏,謝謝大家的支持!
關于老猿的付費專欄
- 付費專欄《https://blog.csdn.net/laoyuanpython/category_9607725.html 使用PyQt開發圖形界面Python應用》專門介紹基于Python的PyQt圖形界面開發基礎教程,對應文章目錄為《 https://blog.csdn.net/LaoYuanPython/article/details/107580932 使用PyQt開發圖形界面Python應用專欄目錄》;
- 付費專欄《https://blog.csdn.net/laoyuanpython/category_10232926.html moviepy音視頻開發專欄 )詳細介紹moviepy音視頻剪輯合成處理的類相關方法及使用相關方法進行相關剪輯合成場景的處理,對應文章目錄為《https://blog.csdn.net/LaoYuanPython/article/details/107574583 moviepy音視頻開發專欄文章目錄》;
- 付費專欄《https://blog.csdn.net/laoyuanpython/category_10581071.html OpenCV-Python初學者疑難問題集》為《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python圖形影像處理 》的伴生專欄,是筆者對OpenCV-Python圖形影像處理學習中遇到的一些問題個人感悟的整合,相關資料基本上都是老猿反復研究的成果,有助于OpenCV-Python初學者比較深入地理解OpenCV,對應文章目錄為《https://blog.csdn.net/LaoYuanPython/article/details/109713407 OpenCV-Python初學者疑難問題集專欄目錄 》
- 付費專欄《https://blog.csdn.net/laoyuanpython/category_10762553.html Python爬蟲入門 》站在一個互聯網前端開發小白的角度介紹爬蟲開發應知應會內容,包括爬蟲入門的基礎知識,以及爬取CSDN文章資訊、博主資訊、給文章點贊、評論等實戰內容,
前兩個專欄都適合有一定Python基礎但無相關知識的小白讀者學習,第三個專欄請大家結合《https://blog.csdn.net/laoyuanpython/category_9979286.html OpenCV-Python圖形影像處理 》的學習使用,
對于缺乏Python基礎的同仁,可以通過老猿的免費專欄《https://blog.csdn.net/laoyuanpython/category_9831699.html 專欄:Python基礎教程目錄)從零開始學習Python,
如果有興趣也愿意支持老猿的讀者,歡迎購買付費專欄,
如果對文章內容存在疑問,可以在博客評論區留言,或關注:老猿Python 微信公號發訊息咨詢,


跟老猿學Python!
? ? 前往老猿Python博文目錄 https://blog.csdn.net/LaoYuanPython ?
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/271241.html
標籤:AI
