基于邊緣保留濾波實(shí)現(xiàn)人臉磨皮的算法

快速邊緣保留濾波

快速邊緣保留濾波是通過積分圖像實(shí)現(xiàn)局部均方差的邊緣保留模糊算法,計(jì)算簡單而且可以做到計(jì)算量跟半徑無關(guān)亚铁。
首先局部均方差濾波中計(jì)算局部均值的公式如下:

計(jì)算局部均值.png

當(dāng)邊緣很弱的時(shí)候系數(shù)K趨近于0蝇刀、該點(diǎn)的矯正之后的像素值就接近平均值。而當(dāng)邊緣很強(qiáng)的時(shí)候系數(shù)K趨近于1徘溢、該點(diǎn)的模糊之后的像素值就接近等于輸入像素值吞琐。上述計(jì)算中最中意的是窗口內(nèi)像素的均值與方差,計(jì)算均值可以根據(jù)積分圖像很容易得到然爆,而計(jì)算方差根據(jù)一系列的數(shù)學(xué)推導(dǎo)可以得到如下的結(jié)果

推導(dǎo)結(jié)果.png

算法實(shí)現(xiàn)的步驟:

1. 快速邊緣保留濾波

核心的算法如下:

    @Override
    public ImageProcessor filter(ImageProcessor src) {
        // initialization parameters
        int width = src.getWidth();
        int height = src.getHeight();
        xr = yr = (int)(Math.max(width, height) * 0.02);
        sigma = 10 + sigma * sigma * 5;

        // start ep process
        byte[] output = new byte[width*height];
        IntIntegralImage ii = new IntIntegralImage();
        for(int i=0; i<src.getChannels(); i++) {
            System.arraycopy(src.toByte(i), 0, output, 0, output.length);
            ii.setImage(src.toByte(i));
            ii.process(width, height, true);
            processSingleChannel(width, height, ii, output);
            System.arraycopy(output, 0, src.toByte(i), 0, output.length);
        }

        // release memory
        output = null;
        return src;
    }

    public void processSingleChannel(int width, int height, IntIntegralImage input, byte[] output) {
        float sigma2 = sigma*sigma;
        int offset = 0;
        int wy = (yr * 2 + 1);
        int wx = (xr * 2 + 1);
        int size = wx * wy;
        int r = 0;
        for (int row = yr; row < height-yr; row++) {
            offset = row * width;
            for (int col = xr; col < width-xr; col++) {
                int sr = input.getBlockSum(col, row, wy, wx);
                float a = input.getBlockSquareSum(col, row, wy, wx);
                float b = sr / size;
                float c = (a - (sr*sr)/size)/size;
                float d = c / (c+sigma2);
                r = (int)((1-d)*b + d*r);
                output[offset + col] = (byte)Tools.clamp(r);
            }
        }
    }

其中站粟,IntIntegralImage封裝了積分圖像的算法,具體可以查看 cv4j 中的實(shí)現(xiàn)施蜜。

2. 皮膚檢測

基于RGB顏色空間的簡單閾值膚色識別來實(shí)現(xiàn)皮膚檢測卒蘸,算法如下:
R>95 And G>40 And B>20 And R>G And R>B And Max(R,G,B)-Min(R,G,B)>15 And Abs(R-G)>15

public class DefaultSkinDetection implements ISkinDetection{
// RGB Color model pixel skin detection method
// (R, G, B) is classified as skin if:
// R > 95 and G > 40 and B > 20 and
// max(R, G, B) - min(R, G, B) > 15 and
// |R-G| > 15 and R > G and R > B
//===============================================
    
    @Override
    public boolean findSkin(int tr, int tg, int tb) {
        return isSkin(tr, tg, tb);
    }

    @Override
    public boolean isSkin(int tr, int tg, int tb) {
        int max = Math.max(tr, Math.max(tg, tb));
        int min = Math.min(tr, Math.min(tg, tb));
        int rg = Math.abs(tr - tg);
        if(tr > 95 && tg > 40 && tb > 20 && rg > 15 && 
                (max - min) > 15 && tr > tg && tr > tb) {
            return true;
        } else {
            return false;
        }
    }

}

3. 梯度濾波

梯度濾波器也叫高通濾波器。梯度濾波器有好幾種不同方式翻默,在這里用的是Sobel缸沃。
Sobel算子根據(jù)像素點(diǎn)上下、左右鄰點(diǎn)灰度加權(quán)差修械,在邊緣處達(dá)到極值這一現(xiàn)象檢測邊緣趾牧。對噪聲具有平滑作用,提供較為精確的邊緣方向信息肯污,邊緣定位精度不夠高腰根。當(dāng)對精度要求不是很高時(shí)蔑歌,是一種較為常用的邊緣檢測方法。由于Sobel算法簡單效率高,所以我們在這里選擇它溯警。

4. BeautySkinFilter

結(jié)合以上三步,在 cv4j 中實(shí)現(xiàn)人臉磨皮的濾鏡BeautySkinFilter

package com.cv4j.core.filters;

import com.cv4j.core.datamodel.ByteProcessor;
import com.cv4j.core.datamodel.ImageProcessor;

/**
 * Created by gloomy fish on 2017/4/23.
 */

public class BeautySkinFilter implements CommonFilter {
    @Override
    public ImageProcessor filter(ImageProcessor src) {
        int width = src.getWidth();
        int height = src.getHeight();
        byte[] R = new byte[width*height];
        byte[] G = new byte[width*height];
        byte[] B = new byte[width*height];
        System.arraycopy(src.toByte(0), 0, R, 0, R.length);
        System.arraycopy(src.toByte(1), 0, G, 0, G.length);
        System.arraycopy(src.toByte(2), 0, B, 0, B.length);

        FastEPFilter epFilter = new FastEPFilter();
        epFilter.filter(src);
        ISkinDetection skinDetector = new DefaultSkinDetection();
        int r = 0, g = 0, b = 0;
        for(int i=0; i<R.length; i++) {
            r = R[i]&0xff;
            g = G[i]&0xff;
            b = B[i]&0xff;
            if(!skinDetector.isSkin(r, g, b)) {
                src.toByte(0)[i] = (byte)r;
                src.toByte(1)[i] = (byte)g;
                src.toByte(2)[i] = (byte)b;
            }
        }

        byte[] gray = new byte[width*height];
        int c = 0;
        for(int i=0; i<R.length; i++) {
            r = R[i] & 0xff;
            g = G[i] & 0xff;
            b = B[i] & 0xff;
            c = (int)(0.299 *r + 0.587*g + 0.114*b);
            gray[i] = (byte)c;
        }

        GradientFilter gradientFilter = new GradientFilter();
        int[] gradient = gradientFilter.gradient(new ByteProcessor(gray, width, height));
        gray = null;
        for(int i=0; i<R.length; i++) {
            r = R[i]&0xff;
            g = G[i]&0xff;
            b = B[i]&0xff;
            if(gradient[i] > 50) {
                src.toByte(0)[i] = (byte)r;
                src.toByte(1)[i] = (byte)g;
                src.toByte(2)[i] = (byte)b;
            }
        }
        return src;
    }
}

5. 最終效果

BeautySkinFilter跟原先的濾鏡用法是一樣的揭北,一行代碼就可以實(shí)現(xiàn)想要的效果:)

RxImageData.bitmap(bitmap).addFilter(new BeautySkinFilter()).into(image1);

來看看在 Android 上的最終效果:


人臉磨皮效果.png

總結(jié):

cv4jgloomyfish和我一起開發(fā)的圖像處理庫寨辩,純java實(shí)現(xiàn),目前還處于早期的版本锄奢。這次的人臉磨皮算法也還有改進(jìn)空間失晴,未來我們還會(huì)繼續(xù)優(yōu)化該算法。

說來很慚愧拘央,由于我們的工作都比較繁忙涂屁,沒有來得及完善開發(fā)文檔。在馬上到來的五一期間灰伟,我們會(huì)補(bǔ)上文檔拆又,未來也會(huì)做出更加酷炫的功能。

先前的文章:
二值圖像分析:案例實(shí)戰(zhàn)(文本分離+硬幣計(jì)數(shù))
Java實(shí)現(xiàn)高斯模糊和圖像的空間卷積
Java實(shí)現(xiàn)圖片濾鏡的高級玩法
Java實(shí)現(xiàn)圖片的濾鏡效果

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市帖族,隨后出現(xiàn)的幾起案子义矛,更是在濱河造成了極大的恐慌,老刑警劉巖盟萨,帶你破解...
    沈念sama閱讀 206,602評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件凉翻,死亡現(xiàn)場離奇詭異,居然都是意外死亡捻激,警方通過查閱死者的電腦和手機(jī)制轰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來胞谭,“玉大人垃杖,你說我怎么就攤上這事≌梢伲” “怎么了调俘?”我有些...
    開封第一講書人閱讀 152,878評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長旺垒。 經(jīng)常有香客問我彩库,道長,這世上最難降的妖魔是什么先蒋? 我笑而不...
    開封第一講書人閱讀 55,306評論 1 279
  • 正文 為了忘掉前任骇钦,我火速辦了婚禮,結(jié)果婚禮上竞漾,老公的妹妹穿的比我還像新娘眯搭。我一直安慰自己,他們只是感情好业岁,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評論 5 373
  • 文/花漫 我一把揭開白布鳞仙。 她就那樣靜靜地躺著,像睡著了一般笔时。 火紅的嫁衣襯著肌膚如雪棍好。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,071評論 1 285
  • 那天糊闽,我揣著相機(jī)與錄音梳玫,去河邊找鬼爹梁。 笑死右犹,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的姚垃。 我是一名探鬼主播念链,決...
    沈念sama閱讀 38,382評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了掂墓?” 一聲冷哼從身側(cè)響起谦纱,我...
    開封第一講書人閱讀 37,006評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎君编,沒想到半個(gè)月后跨嘉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,512評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡吃嘿,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評論 2 325
  • 正文 我和宋清朗相戀三年祠乃,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片兑燥。...
    茶點(diǎn)故事閱讀 38,094評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡亮瓷,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出降瞳,到底是詐尸還是另有隱情嘱支,我是刑警寧澤,帶...
    沈念sama閱讀 33,732評論 4 323
  • 正文 年R本政府宣布挣饥,位于F島的核電站除师,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏扔枫。R本人自食惡果不足惜馍盟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望茧吊。 院中可真熱鬧贞岭,春花似錦、人聲如沸搓侄。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,286評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讶踪。三九已至芯侥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間乳讥,已是汗流浹背柱查。 一陣腳步聲響...
    開封第一講書人閱讀 31,512評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留云石,地道東北人唉工。 一個(gè)月前我還...
    沈念sama閱讀 45,536評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像汹忠,于是被迫代替她去往敵國和親淋硝。 傳聞我的和親對象是個(gè)殘疾皇子雹熬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 不同圖像灰度不同,邊界處一般會(huì)有明顯的邊緣谣膳,利用此特征可以分割圖像竿报。需要說明的是:邊緣和物體間的邊界并不等同,邊緣...
    大川無敵閱讀 13,822評論 0 29
  • http://blog.csdn.net/x454045816/article/details/52153250 ...
    G風(fēng)閱讀 7,023評論 0 1
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,515評論 25 707
  • 卡爾曼濾波在我當(dāng)學(xué)生的時(shí)候就用過继谚,但是當(dāng)年我似乎就是套公式烈菌,沒有理解其精髓,加之時(shí)間久了有點(diǎn)模糊花履,突然需要指導(dǎo)學(xué)生...
    Roger_羅杰閱讀 83,475評論 41 159
  • 昨天剛要出萬達(dá)地下停車場臭挽,在地下二層要轉(zhuǎn)上一層捂襟,這轉(zhuǎn)彎道經(jīng)常會(huì)塞車的,在塞車的時(shí)候欢峰,后面有一輛車在五分鐘內(nèi)至少...
    回音_陳毅力閱讀 624評論 4 0