效果展示
首先看一下目標效果:
素材準備 & 思路分析
本次雪花來源于如下圖片
背景可以是任意圖片,下面是老猿在網(wǎng)上找到的一張珠峰圖像
珠峰背景的天空飄落著紛紛揚揚的雪花,意境不錯吧?
實現(xiàn)思路
要實現(xiàn)雪花飄落,單張圖片的單次顯示肯定不夠,需要不停循環(huán)顯示圖片,并且在每次圖片顯示時,生成新的雪花并更新圖片中已有雪花的位置,這就需要將圖片中每個雪花的位置精確管理。
自然界的雪花大小是不同的,因此為了提升逼真效果,還需要使得雪花大小在一定范圍內(nèi)隨機變化和旋轉(zhuǎn)。
不停產(chǎn)生大小不同的雪花,如果每次產(chǎn)生雪花都對雪花進行變換其實浪費了系統(tǒng)的資源,因此為了提升處理性能,只在程序開始初始化時一次批量生產(chǎn)各種不同大小、不同旋轉(zhuǎn)角度的各種雪花,后續(xù)程序生成雪花時,直接從批量生成的雪花中取一個作為要生成的雪花,而不用每次從基本的雪花圖像開始進行變換。
關(guān)鍵實現(xiàn)代碼
1、生成各種雪花形狀
def initSnowShapes(): “”“ 從文件中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉(zhuǎn)從而生成不同的雪花形狀,這些雪花形狀保存到全局列表中snowShapesList ”“” global snowShapesList imgSnow = readImgFile(r‘f:picsnow.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之間旋轉(zhuǎn) imgRotate = rotationImg(imgSnowSize,ange) snowShapesList.append(imgRotate)
2、產(chǎn)生一排雪花
def generateOneRowSnows(width,count): “”“ 產(chǎn)生一排雪花對象,每個雪花隨機從snowShapesList取一個、橫坐標位置隨機、縱坐標初始為0 :param width: 背景圖像寬度 :param count: 希望的雪花數(shù) 一個包含產(chǎn)生的多個雪花對象信息的列表,每個列表的元素代表一個雪花對象,雪花對象包含三個信息,在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
3、將所有雪花對象融合到背景圖像
def putSnowObjectToImg(img): “”“ 將所有snowObjects中的雪花對象融合放到圖像img中,融合時y坐標隨機下移一定高度,x坐標左右隨機小范圍內(nèi)移動 ”“” 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: #如果雪花的起始縱坐標已經(jīng)超出背景圖像的高度(即到達背景圖像底部),則該雪花對象需進行失效處理 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、主函數(shù)
主函數(shù)讀入背景圖片,初始化雪花形狀列表,然后循環(huán)自頂部產(chǎn)生一排新的雪花,并將所有雪花對象動態(tài)調(diào)整位置后融合到背景圖像,每200毫秒循環(huán)一次,直至按ESC退出。
def main(): global snowShapesList,snowObjects bg = readImgFile(r‘f:picQomolangma2.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
主程序完整代碼及雪花飄落效果
5.1、 主程序完整代碼
# -*- coding: utf-8 -*-import cv2,randomimport numpy as np
from opencvPublic import addImgToLargeImg,readImgFile,rotationImgsnowShapesList = [] #雪花形狀列表snowObjects=[] #圖片中要顯示的所有雪花對象
def initSnowShapes(): “”“ 從文件中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉(zhuǎn)從而生成不同的雪花形狀,這些雪花形狀保存到全局列表中snowShapesList ”“” global snowShapesList imgSnow = readImgFile(r‘f:picsnow.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之間旋轉(zhuǎn),每次旋轉(zhuǎn)角度增加5° imgRotate = rotationImg(imgSnowSize,ange) snowShapesList.append(imgRotate)
def generateOneRowSnows(width,count): “”“ 產(chǎn)生一排雪花對象,每個雪花隨機從snowShapesList取一個、橫坐標位置隨機、縱坐標初始為0 :param width: 背景圖像寬度 :param count: 希望的雪花數(shù) 當前行對應的豎直坐標 一個包含產(chǎn)生的多個雪花對象信息的列表,每個列表的元素代表一個雪花對象,雪花對象包含三個信息,在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坐標左右隨機小范圍內(nèi)移動 ”“” 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: #如果雪花的起始縱坐標已經(jīng)超出背景圖像的高度(即到達背景圖像底部),則該雪花對象需進行失效處理 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:picQomolangma2.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()
總結(jié)
本文介紹了通過OpenCV-Python以特定圖像為背景制作雪花飄落特效的實現(xiàn)思路、關(guān)鍵函數(shù)功能以及主程序的完整代碼。雪花飄落特效實際上屬于圖像融合的操作,只要掌握圖像融合的基礎(chǔ)知識以及設(shè)計后實現(xiàn)思路,實現(xiàn)起來還是比較快的,效果也挺不錯。結(jié)合上面代碼,大家還可以調(diào)整雪花的大小以及飄雪的密集程度。
以上實現(xiàn)過程需要注意:
1、雪花圖片一般會比圖片需要的效果大,怎么縮小到合適的大小需要多試一下,下面是才開始將原始圖片只縮寫一半之后的效果。
可以看到該效果就不太讓人滿意。
2、控制好雪花左右移動以及下落的速度和幅度,太快、太慢以及幅度過大或過小都不太象在雪花飄落。
編輯:lyn
-
OpenCV
+關(guān)注
關(guān)注
31文章
635瀏覽量
41373 -
python
+關(guān)注
關(guān)注
56文章
4797瀏覽量
84745
原文標題:OpenCV-Python圖形圖像處理:制作雪花飄落特效
文章出處:【微信號:vision263com,微信公眾號:新機器視覺】歡迎添加關(guān)注!文章轉(zhuǎn)載請注明出處。
發(fā)布評論請先 登錄
相關(guān)推薦
評論