NDK 開發實戰 實現相機美顏功能

2021-09-24 07:12:46 字數 3107 閱讀 8319

在 《圖形影象處理 - 實現的美容效果》 一文中提到了的美容,採用雙邊濾波演算法來實現,具體的演算法流程和實現思路,大家可以在上篇文章中了解,這篇文章就在不再反覆囉嗦了。這裡我們再次來看下處理效果:

上面的效果看似好像不錯,其實存在了大量的問題。從處理速度上來說,雙邊模糊演算法是在二維的高斯函式上新增畫素差值來實現的,使得演算法的時間複雜度比較大(處理時間 > 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小姐的全圖真的 可以看出美顏效果還是明顯的,下面進行過程實現 保留邊界細節,模糊變化不明顯的區域 我們知道高斯濾波器可以起到模糊影象的作用,而上述的過程是選擇性地進行模糊,在這裡是對影象的灰度變化進行乙個判斷,達到模糊該模糊的地方,並保留邊緣的細節 這裡可以...