扣丁書屋

Android 平臺 Camera 實時濾鏡實現方法探討 -- 磨皮算法

Android平臺Camera實時濾鏡實現方法探討-磨皮算法

版權聲明:本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接和本聲明。https://blog.csdn.net/oShunz/article/details/50372968

上一篇開頭提到了一些可用于磨皮的去噪算法,下面我們實現這些算法并且觀察效果,咱不考慮實時性的問題

本文首先探討的首先是《基于局部均方差相關信息的圖像去噪及其在實時磨皮美容算法中的應用》

該算法利用圖像局部統計特性進行濾波處理,例如NXM像素的灰度圖,首先計算點(i,j)所在窗口內(大小為(2n+1)(2m+1))的平均值m(i,j)

以及均方差:

得到加性去噪后的結果為:

其中:

1.根據原文提出的優化方法,首先是建立兩個積分圖,如圖所示,點4的積分即為Sum(Ra)+Sum(Rb)+Sum(Rc)+Sum(Rd)。積分圖的建立算法可以參考這篇文章進行簡單優化,然后即可根據積分圖計算公式中的m值和v值。

例如半徑為r的窗口的m(i,j)為Integral(i+r,j+r) + Integral(i-r-1,j-r-1)-Integral(i+r,j-r-1)-Integral(i-r-1,j+r)。代碼如下,分別求1次方和平方的積分圖。

void MagicBeauty::initIntegral(uint8_t* inputMatrix){
    LOGE("initIntegral start");
    if(mIntegralMatrix == NULL)
        mIntegralMatrix = new uint64_t[mImageWidth * mImageHeight];
    if(mIntegralMatrixSqr == NULL)
        mIntegralMatrixSqr = new uint64_t[mImageWidth * mImageHeight];

    uint64_t *columnSum = new uint64_t[mImageWidth];
    uint64_t *columnSumSqr = new uint64_t[mImageWidth];

    columnSum[0] = inputMatrix[0];
    columnSumSqr[0] = inputMatrix[0] * inputMatrix[0];

    mIntegralMatrix[0] = columnSum[0];
    mIntegralMatrixSqr[0] = columnSumSqr[0];

    for(int i = 1;i < mImageWidth;i++){

        columnSum[i] = inputMatrix[i];
        columnSumSqr[i] = inputMatrix[i] * inputMatrix[i];

        mIntegralMatrix[i] = columnSum[i];
        mIntegralMatrix[i] += mIntegralMatrix[i-1];
        mIntegralMatrixSqr[i] = columnSumSqr[i];
        mIntegralMatrixSqr[i] += mIntegralMatrixSqr[i-1];
    }
    for (int i = 1;i < mImageHeight; i++){
        int offset = i * mImageWidth;

        columnSum[0] += inputMatrix[offset];
        columnSumSqr[0] += inputMatrix[offset] * inputMatrix[offset];

        mIntegralMatrix[offset] = columnSum[0];
        mIntegralMatrixSqr[offset] = columnSumSqr[0];
         // other columns
        for(int j = 1; j < mImageWidth; j++){
            columnSum[j] += inputMatrix[offset+j];
            columnSumSqr[j] += inputMatrix[offset+j] * inputMatrix[offset+j];

            mIntegralMatrix[offset+j] = mIntegralMatrix[offset+j-1] + columnSum[j];
            mIntegralMatrixSqr[offset+j] = mIntegralMatrixSqr[offset+j-1] + columnSumSqr[j];
        }
    }
    delete[] columnSum;
    delete[] columnSumSqr;
    LOGE("initIntegral end");
}

2.根據網上抄來的RGB膚色檢測計算膚色區域

void MagicBeauty::initSkinMatrix(){
    LOGE("start - initSkinMatrix");
    if(mSkinMatrix == NULL)
        mSkinMatrix = new uint8_t[mImageWidth * mImageHeight];
    for(int i = 0; i < mImageHeight; i++){
        for(int j = 0; j < mImageWidth; j++){
            int offset = i*mImageWidth+j;
            ARGB RGB;
            BitmapOperation::convertIntToArgb(mImageData_rgb[offset],&RGB);
            if ((RGB.blue>95 && RGB.green>40 && RGB.red>20 &&
                    RGB.blue-RGB.red>15 && RGB.blue-RGB.green>15)||//uniform illumination
                    (RGB.blue>200 && RGB.green>210 && RGB.red>170 &&
                    abs(RGB.blue-RGB.red)<=15 && RGB.blue>RGB.red&& RGB.green>RGB.red))//lateral illumination
                mSkinMatrix[offset] = 255;
            else
                mSkinMatrix[offset] = 0;
        }
    }
    LOGE("end - initSkinMatrix");
}

3.根據公式對RGB通道或者將RGB通道轉化為YCbCr格式單獨對Y通道進行濾波

void MagicBeauty::startLocalStatisticsSmooth(float sigema){
    if(mIntegralMatrix == NULL || mIntegralMatrixSqr == NULL ||
            mImageData_yuv_y == NULL || mSkinMatrix == NULL || mImageData_yuv == NULL){
        LOGE("not init correctly");
        return;
    }
    int radius = mImageWidth > mImageHeight ? mImageWidth * 0.02 : mImageHeight * 0.02;

    LOGE("startSmooth");
    for(int i = 1; i < mImageHeight; i++){
        for(int j = 1; j < mImageWidth; j++){
            int offset = i * mImageWidth + j;
            if(mSkinMatrix[offset] == 255){
                int iMax = i + radius >= mImageHeight-1 ? mImageHeight-1 : i + radius;
                int jMax = j + radius >= mImageWidth-1 ? mImageWidth-1 :j + radius;
                int iMin = i - radius <= 1 ? 1 : i - radius;
                int jMin = j - radius <= 1 ? 1 : j - radius;

                int squar = (iMax - iMin + 1)*(jMax - jMin + 1);
                int i4 = iMax*mImageWidth+jMax;
                int i3 = (iMin-1)*mImageWidth+(jMin-1);
                int i2 = iMax*mImageWidth+(jMin-1);
                int i1 = (iMin-1)*mImageWidth+jMax;

                float m = (mIntegralMatrix[i4]
                        + mIntegralMatrix[i3]
                        - mIntegralMatrix[i2]
                        - mIntegralMatrix[i1]) / squar;

                float v = (mIntegralMatrixSqr[i4]
                        + mIntegralMatrixSqr[i3]
                        - mIntegralMatrixSqr[i2]
                        - mIntegralMatrixSqr[i1]) / squar - m*m;
                float k = v / (v + sigema);
                    mImageData_yuv[offset*3] = m - k * m + k * mImageData_yuv_y[offset];</span>
            }
        }
    }
    endLocalStatisticsSmooth();
}

效果圖:磨皮強度為最大10.


https://mp.weixin.qq.com/s/aTVIIItlYJVR6DX2I6oYhg

最多閱讀

簡化Android的UI開發 2年以前  |  515143次閱讀
Android 深色模式適配原理分析 1年以前  |  26446次閱讀
Android 樣式系統 | 主題背景覆蓋 1年以前  |  7987次閱讀
Android Studio 生成so文件 及調用 1年以前  |  5629次閱讀
30分鐘搭建一個android的私有Maven倉庫 3年以前  |  4776次閱讀
Android設計與開發工作流 2年以前  |  4438次閱讀
Google Enjarify:可代替dex2jar的dex反編譯 3年以前  |  4420次閱讀
Android多渠道打包工具:apptools 3年以前  |  4054次閱讀
移動端常見崩潰指標 2年以前  |  4052次閱讀
Google Java編程風格規范(中文版) 3年以前  |  3959次閱讀
Android-模塊化-面向接口編程 1年以前  |  3885次閱讀
Android內存異常機制(用戶空間)_NE 1年以前  |  3856次閱讀
Android UI基本技術點 3年以前  |  3805次閱讀
Android死鎖初探 2年以前  |  3765次閱讀

手機掃碼閱讀
18禁止午夜福利体验区,人与动人物xxxx毛片人与狍,色男人窝网站聚色窝
<蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <蜘蛛词>| <文本链> <文本链> <文本链> <文本链> <文本链> <文本链>