OpenGL (三) 濾鏡filter 應(yīng)用

OpenGL (一)OpenGL ES 繪制基礎(chǔ)
OpenGL (二)GLSurface 視頻錄制
OpenGL (三)濾鏡filter 應(yīng)用
OpenGL (四)貼紙和磨皮理論

用到了人臉識(shí)別定位吏颖。SeetaFace2

具體內(nèi)容搜索關(guān)鍵字产喉,到github搜搜,找到Android編譯,不再用鏈接,這里的書寫環(huán)境用到鏈接容易鎖文章

編譯好之后焕数,進(jìn)行配置android C++ 環(huán)境

具體api的時(shí)候參考他的example

大眼萌算法

其實(shí)就是根據(jù)photoshop上面功能的算法公式

Local Scale warps 局部縮放

前提:定位到眼睛的位置

local_scale_wraps.png

解釋: rmax為圓形選區(qū)的半徑透罢,r為控制點(diǎn)移動(dòng)位移钦铁,即目的矢量,as是(-1,1)之間的縮放參數(shù)殉疼,a<0表示縮小梯浪,a>0表示放大,給出點(diǎn)X時(shí)瓢娜,可以求出它變換前的坐標(biāo)U(精確的浮點(diǎn)坐標(biāo))挂洛,然后用變化前圖像在U點(diǎn)附近的像素進(jìn)行插值,求出U的像素值眠砾。如此對(duì)圓形選區(qū)內(nèi)的每一個(gè)像素進(jìn)行求值抹锄,便可得出變換后的圖像。

變換后的公式.png

理解圖像


眼睛縮放黑眼白.png

實(shí)現(xiàn)

寫著色器

bigeye_frag.frag

precision mediump float;//數(shù)據(jù)精度

varying vec2 aCoord;

uniform sampler2D vTexture;// samplerExternalOES 圖片荠藤,采樣器
uniform vec2 left_eye;
uniform vec2 right_eye;

//r: 要畫的點(diǎn)與眼睛的距離
//max 最大半徑
//0.4 放大系數(shù) -1 -- 1 大于0 就是放大
float fs(float r,float rmax){
//    return (1.0-pow(r/rmax-1.0,2.0)* 0.5)*r;
    return (1.0-pow(r/rmax-1.0,2.0)* 0.5);

}

vec2 newCoord(vec2 coord,vec2 eye,float rmax){
    vec2 p = cood;
    //得到要畫的點(diǎn)coord伙单,與眼睛的距離
    float r = distance(coord,eye);
    if(r < rmax){
        // 在這個(gè)范圍,新的點(diǎn)與眼睛的距離
        float fsr = fs(r,rmax);
        // (縮放后的點(diǎn)- 眼睛的點(diǎn))/(原點(diǎn)-眼睛的點(diǎn))= fsr /r
        //縮放的點(diǎn)=fsr/r * (原點(diǎn)-眼睛的點(diǎn)) + 眼睛的點(diǎn)
//        p = fsr/r*(coord-eye) + eye;
        // 優(yōu)化 抵消掉,這需要除哈肖,上面公式需要乘
        p = fsr/(coord-eye) + eye;
    }

    return p;
}

void main(){
//    gl_FragColor = texture2D(vTexture,aCoord);//從圖片中找到像素點(diǎn)吻育,賦值

    float rmax = distance(left_eye,right_eye)/2.0;
    vec2 p =  newCoord(aCoord,left_eye,rmax);
    p =  newCoord(aCoord,right_eye,rmax);

    gl_FragColor = texture2D(vTexture,p);//從圖片中找到像素點(diǎn),賦值


}

opecv 相關(guān)+CameraX采集人臉數(shù)據(jù)

參考之前的文章

OpenCV 系列人臉定位&人臉定位模型訓(xùn)練

將識(shí)別的人臉圖像通過SeetaFace2 定位到眼睛的位置淤井,
然后計(jì)算布疼,利用著色器在指定區(qū)域著色。

大眼濾鏡

public class BigEyeFilter extends AbstractFrameFilter {
    private FloatBuffer left;
    private FloatBuffer right;
    int left_eye;
    int right_eye;
    Face face;

    public BigEyeFilter(Context context) {
        super(context, R.raw.base_vert, R.raw.bigeye_frag);

        left = ByteBuffer.allocateDirect(8).order(ByteOrder.nativeOrder()).asFloatBuffer();
        right = ByteBuffer.allocateDirect(8).order(ByteOrder.nativeOrder()).asFloatBuffer();
    }

    @Override
    public void initGL(Context context, int vertexShaderId, int fragmentShaderId) {
        super.initGL(context, vertexShaderId, fragmentShaderId);
        left_eye = GLES20.glGetUniformLocation(program, "left_eye");
        right_eye = GLES20.glGetUniformLocation(program, "right_eye");
    }


    @Override
    public int onDraw(int texture, FilterChain filterChain) {
        FilterContext filterContext = filterChain.filterContext;
        face = filterContext.face;
        return super.onDraw(texture, filterChain);
    }

    @Override
    public void beforeDraw() {
        super.beforeDraw();

        if (face == null) {
//            Log.e("zcw_opengl","未識(shí)別到人臉");
            return;
        }
        Log.e("zcw_opengl","是一個(gè)-------人臉");

        float x = face.left_x / face.imgWidth;
        float y = 1.0f - face.left_y / face.imgHeight;

        left.clear();
        left.put(x).put(y).position(0);

        GLES20.glUniform2fv(left_eye, 1, left);


        x = face.right_x / face.imgWidth;
        y = 1.0f - face.right_y / face.imgHeight;

        right.clear();
        right.put(x).put(y).position(0);

        GLES20.glUniform2fv(right_eye, 1, right);


    }
}

責(zé)任連模式币狠,使用濾鏡開發(fā)更簡(jiǎn)單

public class FilterContext {

    public Face face; // 人臉

    public float[] cameraMtx; //攝像頭轉(zhuǎn)換矩陣

    public int width;
    public int height;

    public void setSize(int width, int height) {
        this.width = width;
        this.height = height;
    }

    public void setTransformMatrix(float[] mtx) {
        this.cameraMtx = mtx;
    }

    public void setFace(Face face) {
        this.face = face;
    }
}

--------
public class FilterChain {

    public FilterContext filterContext;
    private List<AbstractFilter> filters;
    private int index;

    public FilterChain(List<AbstractFilter> filters, int index, FilterContext filterContext) {
        this.filters = filters;
        this.index = index;
        this.filterContext = filterContext;
    }


    public int proceed(int textureId) {
        if (index >= filters.size()) {
            return textureId;
        }

        FilterChain nextFilterChain = new FilterChain(filters, index + 1, filterContext);
        AbstractFilter abstractFilter = filters.get(index);
        return abstractFilter.onDraw(textureId, nextFilterChain);
    }

    public void setSize(int width, int height) {
        filterContext.setSize(width, height);
    }

    public void setTransformMatrix(float[] mtx) {
        filterContext.setTransformMatrix(mtx);
    }

    public void setFace(Face face) {
        filterContext.setFace(face);
    }

    public void release() {
        for (AbstractFilter filter : filters) {
            filter.release();
        }
    }
}
------

/**
 * FBO
 */
public abstract class AbstractFrameFilter extends AbstractFilter {

    int[] frameBuffer;
    int[] frameTextures;

    public AbstractFrameFilter(Context context, int vertexShaderId, int fragmentShaderId) {
        super(context, vertexShaderId, fragmentShaderId);
    }


    public void createFrame(int width, int height) {
        releaseFrame();
        //創(chuàng)建FBO
        /**
         * 1游两、創(chuàng)建FBO + FBO中的紋理
         */
        frameBuffer = new int[1];
        frameTextures = new int[1];
        GLES20.glGenFramebuffers(1, frameBuffer, 0);
        OpenGLUtils.glGenTextures(frameTextures);

        /**
         * 2、fbo與紋理關(guān)聯(lián)
         */
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, frameTextures[0]);
        GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, width, height, 0, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
                null);
        //紋理關(guān)聯(lián) fbo
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]);  //綁定FBO
        GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D,
                frameTextures[0],
                0);

        /**
         * 3漩绵、解除綁定
         */
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);

    }


    @Override
    public int onDraw(int texture, FilterChain filterChain) {
        FilterContext filterContext = filterChain.filterContext;
        createFrame(filterContext.width, filterContext.height);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]); //綁定fbo
        super.onDraw(texture, filterChain);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);  //

        return filterChain.proceed(frameTextures[0]);
    }

    @Override
    public void release() {
        super.release();
        releaseFrame();
    }

    private void releaseFrame() {
        if (frameTextures != null) {
            GLES20.glDeleteTextures(1, frameTextures, 0);
            frameTextures = null;
        }

        if (frameBuffer != null) {
            GLES20.glDeleteFramebuffers(1, frameBuffer, 0);
        }
    }
}


核心 onDraw

public int onDraw(int texture, FilterChain filterChain) {
        FilterContext filterContext = filterChain.filterContext;
        createFrame(filterContext.width, filterContext.height);

        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBuffer[0]); //綁定fbo
        super.onDraw(texture, filterChain);
        GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);  //

        return filterChain.proceed(frameTextures[0]);
    }

我們有很多過濾器贱案,可以看成不同處理流程,都繼承超類AbstractFrameFilter 并且實(shí)現(xiàn)onDraw 調(diào)用super.onDraw

CameraFilter,BigEyeFilter,ScreenFilter,RecordFilter

參考項(xiàng)目

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載止吐,如需轉(zhuǎn)載請(qǐng)通過簡(jiǎn)信或評(píng)論聯(lián)系作者宝踪。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市碍扔,隨后出現(xiàn)的幾起案子瘩燥,更是在濱河造成了極大的恐慌,老刑警劉巖不同,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件厉膀,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡二拐,警方通過查閱死者的電腦和手機(jī)服鹅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來卓鹿,“玉大人菱魔,你說我怎么就攤上這事∫魉铮” “怎么了澜倦?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)杰妓。 經(jīng)常有香客問我藻治,道長(zhǎng),這世上最難降的妖魔是什么巷挥? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任桩卵,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘雏节。我一直安慰自己胜嗓,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布钩乍。 她就那樣靜靜地躺著辞州,像睡著了一般。 火紅的嫁衣襯著肌膚如雪寥粹。 梳的紋絲不亂的頭發(fā)上变过,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天,我揣著相機(jī)與錄音涝涤,去河邊找鬼媚狰。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阔拳,可吹牛的內(nèi)容都是我干的崭孤。 我是一名探鬼主播,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼衫生,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼裳瘪!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起罪针,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤彭羹,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后泪酱,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體派殷,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年墓阀,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了毡惜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡斯撮,死狀恐怖经伙,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情勿锅,我是刑警寧澤帕膜,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站溢十,受9級(jí)特大地震影響垮刹,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜张弛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一荒典、第九天 我趴在偏房一處隱蔽的房頂上張望酪劫。 院中可真熱鬧,春花似錦寺董、人聲如沸覆糟。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽搪桂。三九已至,卻和暖如春盯滚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酗电。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工魄藕, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人撵术。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓背率,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親嫩与。 傳聞我的和親對(duì)象是個(gè)殘疾皇子寝姿,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

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