在 《圖形影象處理 - 實現的美容效果》 一文中提到了的美容,採用雙邊濾波演算法來實現,具體的演算法流程和實現思路,大家可以在上篇文章中了解,這篇文章就在不再反覆囉嗦了。這裡我們再次來看下處理效果:
上面的效果看似好像不錯,其實存在了大量的問題。從處理速度上來說,雙邊模糊演算法是在二維的高斯函式上新增畫素差值來實現的,使得演算法的時間複雜度比較大(處理時間 > 1s),其次從處理效果上來說,使用者一眼就能看出來,這是一張經過加工處理過的,眼睛很迷茫沒了深邃,效果看上去很模糊沒真實感。因此本文就從這兩個方面下手,第一優化美容演算法,其次優化美顏效果,使其能夠真正的用到我們的手機移動端,實現實時美顏的功能。
1. 實現快速模糊
之前我們在實現模糊時,採用的是做卷積操作,其演算法的複雜度是 image.rows * image.cols* kernel.rows * kernel.cols 且內部採用的是 float 運算,我們的卷積核 kernel 越大其演算法的複雜度就越大。寫法如下:
mat src = imread("c:/users/hcdarren/desktop/android/example.png");
if (!src.data)
imshow("src", src);
mat dst;
int size = 13;
mat kernel = mat::ones(size(size,size),cv_32fc1)/(size*size);
filter2d(src,dst,src.depth(),kernel);
imshow("dst", dst);
複製**
上圖的實現原理其實很簡單,處理的流程就是我們根據原圖建立一張積分圖,通過積分圖就可以求得原圖某一塊區域的畫素大小總和。之前做卷積操作的複雜度是 kernel.rows * kernel.cols , 而通過積分圖來求就變成了 o(1) ,且不會隨著卷積核的增大而增加其演算法的複雜度。我們來看下具體的**實現:
// 積分圖的模糊演算法 size 模糊的直徑
void meanblur(mat & src, mat &dst, int size)
} }}複製**
2. 快速邊緣保留
實現了快速模糊演算法後,我們就得思考一下如何才能實現,快速的邊緣保留效果呢?我們來看幾個公式:
具體的實現分析,大家可以參考上面的實現思路,方差公式的推倒大家可以參考這裡 en.wikipedia.org/wiki/varian… 。剩下的就是直接開始套公式了:
int getblocksum(mat &sum_mat, int x0, int y0, int x1, int y1, int ch)
float getblocksqsum(mat &sqsum_mat, int x0, int y0, int x1, int y1, int ch)
// 積分圖的模糊演算法 size 模糊的直徑
void fatsbilateralblur(mat & src, mat &dst, int size, int sigma)
} }}複製**
3. 檢測與融合**區域
實現了快速邊緣保留後,我們有了兩方面的提公升,第乙個是演算法時間上面的提公升,第二個是效果上面的提公升,臉上的水滴效果還在,眼睛區域基本沒有變化,看上去比較真實。但我們發現效果還不是很好,如脖子上面的頭髮與原圖相比有些模糊,因此我們打算只對**區域實現美顏,其他區域採用其他演算法。那我們怎麼去判斷**區域呢?最簡單的一種方式就是根據 rgb 或者 ycrcb 的值來篩選,然後根據**區域來進行融合。
// **區域檢測
void skindetect(const mat &src, mat &skinmask)
else
} }}// **區域融合
void fuseskin(const mat &src, const mat &blur_mat, mat &dst, const mat &mask)
else
*/// src ,通過指標去獲取, 指標 -> vec3b -> 獲取
uchar b1 = src.at(row, col)[0];
uchar g1 = src.at(row, col)[1];
uchar r1 = src.at(row, col)[2];
// blur_mat
uchar b2 = blur_mat.at(row, col)[0];
uchar g2 = blur_mat.at(row, col)[1];
uchar r2 = blur_mat.at(row, col)[2];
// dst 254 1
float k = mask_f.at(row,col);
dst.at(row, col)[0] = b2*k + (1 - k)*b1;
dst.at(row, col)[1] = g2*k + (1 - k)*g1;
dst.at(row, col)[2] = r2*k + (1 - k)*r1;
} }}複製**
4. 最後總結
如果我們對處理效果依舊不是很滿意的話,我們可以自己再做一些折騰,像邊緣加強或者模糊疊加等等。
// 邊緣的提公升 (可有可無)
mat cannymask;
canny(src, cannymask, 150, 300, 3, false);
imshow("canny", cannymask);
// & 運算 0 ,255
bitwise_and(src, src, fusedst, cannymask);
imshow("bitwise_and", fusedst);
// 稍微提公升一下對比度(亮度)
add(fusedst, scalar(10, 10, 10), fusedst);
複製**
最後總結一下:無論我們怎麼處理要保證兩個方面,第乙個是速度方面,因為如果整合到移動端手機上必須得考慮實時性,第二個是效果方面,要讓使用者看上去自然,盡量不要讓使用者感知這是處理過的特效。至於怎麼整合到 android 移動端,大家感興趣可以自己去試試,我將在後面的直播美顏部分來為大家進行講解。 iOS開發高階 實現類似美顏相機的相機啟動動畫
最近在寫乙個相簿的demo,偶爾看到了美拍的相機過載動畫覺得很有意思,就想在我的相簿demo中加入乙個這種特效,下面把我的想法和實現過程給大家分享一下 這個動效看起來很有特色但是實現起來是非常簡單的,只需要用到calayer和cashapelayer做為展示層,然後通過cabasicanimatio...
Camera相機開發 實現開啟相機
android camera相機開發知識點介紹了進行camera開發需要了解的知識點 由於6.0 以上的系統需要我們在程式執行的時候進行動態許可權申請,所以我們需要在程式啟動的時候去檢查許可權,有任何乙個必要的許可權被使用者拒絕時,我們就彈窗提示使用者程式因為許可權被拒絕而無法正常工作 privat...
使用Matlab實現美顏功能(雙邊濾波器)
借用一張lena小姐的圖 題外話 lena小姐的全圖真的 可以看出美顏效果還是明顯的,下面進行過程實現 保留邊界細節,模糊變化不明顯的區域 我們知道高斯濾波器可以起到模糊影象的作用,而上述的過程是選擇性地進行模糊,在這裡是對影象的灰度變化進行乙個判斷,達到模糊該模糊的地方,並保留邊緣的細節 這裡可以...