OpenCV-Python圖形圖像處理:制作雪花飄落特效
導讀
Hi,大家好,今天給各位讀者分享一個比較酷炫的特效。
其中匯集了很多opencv的常用操作,一套組合拳,秀的頭皮發(fā)麻
來源:https://blog.csdn.net/LaoYuanPython/article/details/115298737
效果展示
首先看一下目標效果:

素材準備 & 思路分析
本次雪花來源于如下圖片(文件名:f:\pic\snow.jpg):
背景可以是任意圖片,下面是老猿在網上找到的一張珠峰圖像(文件名:f:\pic\Qomolangma2.jpg):

實現思路
要實現雪花飄落,單張圖片的單次顯示肯定不夠,需要不停循環(huán)顯示圖片,并且在每次圖片顯示時,生成新的雪花并更新圖片中已有雪花的位置,這就需要將圖片中每個雪花的位置精確管理。
自然界的雪花大小是不同的,因此為了提升逼真效果,還需要使得雪花大小在一定范圍內隨機變化和旋轉。
不停產生大小不同的雪花,如果每次產生雪花都對雪花進行變換其實浪費了系統的資源,因此為了提升處理性能,只在程序開始初始化時一次批量生產各種不同大小、不同旋轉角度的各種雪花,后續(xù)程序生成雪花時,直接從批量生成的雪花中取一個作為要生成的雪花,而不用每次從基本的雪花圖像開始進行變換。
關鍵實現代碼
1、生成各種雪花形狀
def initSnowShapes():"""從文件中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉從而生成不同的雪花形狀,這些雪花形狀保存到全局列表中snowShapesList"""global snowShapesListimgSnow = 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.01imgSnowSize = cv2.resize(imgSnow, None, fx=f, fy=f)for ange in range(0,360,5):#雪花0-360之間旋轉imgRotate = rotationImg(imgSnowSize,ange)snowShapesList.append(imgRotate)
2、產生一排雪花
def generateOneRowSnows(width,count):"""產生一排雪花對象,每個雪花隨機從snowShapesList取一個、橫坐標位置隨機、縱坐標初始為0:param width: 背景圖像寬度:param count: 希望的雪花數:return:一個包含產生的多個雪花對象信息的列表,每個列表的元素代表一個雪花對象,雪花對象包含三個信息,在snowShapesList的索引號、初始x坐標、初始y坐標(才生成固定為0)"""global snowShapesListline = []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坐標左右隨機小范圍內移動"""global snowShapesList,snowObjectshorizontalMaxDistance,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、主函數
主函數讀入背景圖片,初始化雪花形狀列表,然后循環(huán)自頂部產生一排新的雪花,并將所有雪花對象動態(tài)調整位置后融合到背景圖像,每200毫秒循環(huán)一次,直至按ESC退出。
def main():global snowShapesList,snowObjectsbg = 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
主程序完整代碼及雪花飄落效果
5.1、 主程序完整代碼
# -*- coding: utf-8 -*-import cv2,randomimport numpy as npfrom opencvPublic import addImgToLargeImg,readImgFile,rotationImgsnowShapesList = [] #雪花形狀列表snowObjects=[] #圖片中要顯示的所有雪花對象def initSnowShapes():"""從文件中讀入雪花圖片,并進行不同尺度的縮小和不同角度的旋轉從而生成不同的雪花形狀,這些雪花形狀保存到全局列表中snowShapesList"""global snowShapesListimgSnow = 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.01imgSnowSize = 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 snowShapesListline = []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 linedef putSnowObjectToImg(img):"""將所有snowObjects中的雪花對象融合放到圖像img中,融合時y坐標隨機下移一定高度,x坐標左右隨機小范圍內移動"""global snowShapesList,snowObjectshorizontalMaxDistance,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,snowObjectsinitSnowShapes()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:breakmain()

總結
本文介紹了通過OpenCV-Python以特定圖像為背景制作雪花飄落特效的實現思路、關鍵函數功能以及主程序的完整代碼。雪花飄落特效實際上屬于圖像融合的操作,只要掌握圖像融合的基礎知識以及設計后實現思路,實現起來還是比較快的,效果也挺不錯。結合上面代碼,大家還可以調整雪花的大小以及飄雪的密集程度。
以上實現過程需要注意:
1、雪花圖片一般會比圖片需要的效果大,怎么縮小到合適的大小需要多試一下,下面是才開始將原始圖片只縮寫一半之后的效果。

可以看到該效果就不太讓人滿意。
2、控制好雪花左右移動以及下落的速度和幅度,太快、太慢以及幅度過大或過小都不太象在雪花飄落。
End 
聲明:部分內容來源于網絡,僅供讀者學術交流之目的。文章版權歸原作者所有。如有不妥,請聯系刪除。

