OpenCV實現圖像背景虛化效果原理詳解
0 寫在前面
相信用過相機的同學都知道虛化特效,這是一種使焦點聚集在拍攝主題上,讓背景變得朦朧的效果,例如本文最后實現的背景虛化效果
相機虛化特效背后的原理是什么?和計算機視覺有什么關系?本文帶你研究這些問題。
1 小孔成像
小學我們就知道,沒有光就不存在圖像,為了產生圖像,場景必須有一個或多個、直接或間接的光源。
如圖所示,光照主要分為三類:
- 散射
- 直接光照
- 漫反射
在獲得光源后,將產生從物體到檢測平面的光線。
由于從物體上某點A出發(fā)存在無數條四散的光線到達檢測平面,因此可以認為A的成像點A’均勻地分布在成像平面上,同理其他點亦然。所以這種情況下,檢測平面上是無數張物體圖像的混疊,導致成像模糊甚至無法成像。
面對一張白紙上看不到你的臉,不是因為白紙上沒有來自于你的光線,而是因為來自于你不同部分的光線在白紙上產生了重疊,不信你試試?
那如何在白紙上成像?
其實非常簡單,采用小學就嘗試過的小孔成像
本質上小孔相當于一個濾光器,僅保留從物點發(fā)出的少數光線,此時應能獲得清晰的圖像。
2 光學成像
小孔成像的缺陷是成像光線較少,亮度低。為了既能獲得較多光線,又不讓像點四散在檢測面上造成影像重疊,引入具有聚光性的透鏡。透鏡成像與小孔成像的本質都是避免因像點四散導致的無法成像,前者利用聚光,后者則利用濾光。
現代相機在應用上通常使用透鏡成像,但不管是透鏡成像還是小孔成像,都是計算機視覺研究的基本模型和假設,例如透視幾何、相機內參矩陣、畸變修正等等,因此本節(jié)對于建立機器視覺的研究思維很有幫助。
3 虛化效果
介紹完前面的基礎知識,終于開始圖像虛化特效的原理啦!
理想透鏡應保證光線聚焦于一點——焦點,這個點不會產生任何成像混疊,圖像最清晰。在焦點前后光線開始四散,形成不同程度的成像重疊區(qū)域,稱為彌散圓,對于人眼而言,在一定范圍內影象產生的模糊是不能辨認的,不能辨認的彌散圓范圍稱為容許彌散圓
當對被攝主體平面調焦時,因為容許彌散圓的存在,在一定離焦范圍內,成像仍然清晰,這個范圍稱為焦深。調整成像面和鏡頭距離,使成像面處于焦深內,物體可以清晰成像的過程,稱為對焦。
類似地,對被攝物體而言,位于調焦物平面前后的能相對清晰成像的景物間縱深距離稱為景深。圖像虛化效果就和這個景深有關系!
- 景深越小,被攝物體前后能清晰成像的范圍越小,也就相應地出現朦朧虛化的效果
- 景深越大,被攝物體前后能清晰成像的范圍越大,也就沒有虛化效果
如何調節(jié)景深?記住一句話:光圈越大景深越小,所以拿手機拍照的時候,大光圈也就代表了虛化效果!
所以下次有機會給女生拍照的話,請先確認
“請問你喜歡小景深還是大景深?”
4 代碼實戰(zhàn)
相機背景虛化特效在圖像處理中可以采用引導濾波器實現,源碼如下。
//引導濾波器 Mat guidedFilter(Mat& srcMat, Mat& guidedMat, int radius, double eps) { srcMat.convertTo(srcMat, CV_64FC1); guidedMat.convertTo(guidedMat, CV_64FC1); // 計算均值 Mat mean_p, mean_I, mean_Ip, mean_II; boxFilter(srcMat, mean_p, CV_64FC1, Size(radius, radius)); // 生成待濾波圖像均值mean_p boxFilter(guidedMat, mean_I, CV_64FC1, Size(radius, radius)); // 生成引導圖像均值mean_I boxFilter(srcMat.mul(guidedMat), mean_Ip, CV_64FC1, Size(radius, radius)); // 生成互相關均值mean_Ip boxFilter(guidedMat.mul(guidedMat), mean_II, CV_64FC1, Size(radius, radius)); // 生成引導圖像自相關均值mean_II // 計算相關系數、Ip的協(xié)方差cov和I的方差var------------------ Mat cov_Ip = mean_Ip - mean_I.mul(mean_p); Mat var_I = mean_II - mean_I.mul(mean_I); // 計算參數系數a、b Mat a = cov_Ip / (var_I + eps); Mat b = mean_p - a.mul(mean_I); // 計算系數a、b的均值 Mat mean_a, mean_b; boxFilter(a, mean_a, CV_64FC1, Size(radius, radius)); boxFilter(b, mean_b, CV_64FC1, Size(radius, radius)); // 生成輸出矩陣 Mat dstImage = mean_a.mul(srcMat) + mean_b; return dstImage; }
關于引導濾波器的相關原理我們下次再開新的章節(jié)闡述。
主函數內調用濾波器即可,效果如文首所示。
int main() { Mat resultMat; Mat vSrcImage[3], vResultImage[3]; Mat vResultImage[3]; Mat srcImage = imread("1.jpg"); imshow("源圖像", srcImage); // 對源圖像進行通道分離,并對每個分通道進行引導濾波 split(srcImage, vSrcImage); for (int i = 0; i < 3; i++) { Mat tempImage; vSrcImage[i].convertTo(tempImage, CV_64FC1, 1.0 / 255.0); Mat cloneImage = tempImage.clone(); Mat resultImage = guidedFilter(tempImage, cloneImage, 5, 0.3); vResultImage[i] = resultImage; } // 將分通道導向濾波后結果合并 merge(vResultImage, 3, resultMat); imshow("背景虛化特效", resultMat); waitKey(0); return 0; }
一個小小的圖像虛化特效,背后牽扯出光學成像的各種原理,構建了計算機視覺模型的地基。正如我們每個人一樣,也許你覺得自己很渺小,說不定也是別人的中流砥柱呢!
到此這篇關于OpenCV實現圖像背景虛化效果原理詳解的文章就介紹到這了,更多相關OpenCV圖像背景虛化內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!