Android平臺Camera實時濾鏡實現方法探討(九)--磨皮演算法探討(一)
阿新 • • 發佈:2019-02-19
上一篇開頭提到了一些可用於磨皮的去噪演算法,下面我們實現這些演算法並且觀察效果,咱不考慮實時性的問題
該演算法利用影象區域性統計特性進行濾波處理,例如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();
- }