大发体育娱乐在线-大发体育娱乐官方网站-大发体育娱乐登录网址
做最好的网站

如法泡制摄影和铅笔画的滤镜效果,基于边缘保

来源:http://www.dfwstonefabricators.com 作者:编程应用 人气:74 发布时间:2019-09-19
摘要:敏捷边缘保留滤波是透过积分图像达成部分均方差的边缘保留模糊算法,计算轻巧并且可以实现总结量跟半径非亲非故。首先局部均方差滤波中总括局地均值的公式如下: 油画效果 先

敏捷边缘保留滤波是透过积分图像达成部分均方差的边缘保留模糊算法,计算轻巧并且可以实现总结量跟半径非亲非故。首先局部均方差滤波中总括局地均值的公式如下:

油画效果

先上未经任何管理的原图

原图.png

然后接纳摄影风格的滤镜OilPaintFilter看看效果,OilPaintFilter的利用办法就一句话:)

RxImageData.bitmap(bitmap).addFilter(new OilPaintFilter()).into(image);

雕塑效果.png

OilPaintFilter在拍卖人物图片和风景图片时享有比较好的机能。

OilPaintFilter的源码如下:

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

/**
 * Created by Tony Shen on 2017/5/7.
 */

public class OilPaintFilter extends BaseFilter {

    private int radius = 15; // default value
    private int intensity = 40; // default value

    public OilPaintFilter() {
        this(15, 40);
    }

    public OilPaintFilter(int radius, int graylevel) {
        this.radius = radius;
        this.intensity = graylevel;
    }

    public int getRadius() {
        return radius;
    }

    public void setRadius(int radius) {
        this.radius = radius;
    }

    public int getIntensity() {
        return intensity;
    }

    public void setIntensity(int intensity) {
        this.intensity = intensity;
    }

    @Override
    public ImageProcessor doFilter(ImageProcessor src) {

        byte[][] output = new byte[3][R.length];

        int index = 0;
        int subradius = this.radius / 2;
        int[] intensityCount = new int[intensity+1];
        int[] ravg = new int[intensity+1];
        int[] gavg = new int[intensity+1];
        int[] bavg = new int[intensity+1];

        for(int i=0; i<=intensity; i++) {
            intensityCount[i] = 0;
            ravg[i] = 0;
            gavg[i] = 0;
            bavg[i] = 0;
        }

        for(int row=0; row<height; row++) {
            int ta = 0, tr = 0, tg = 0, tb = 0;
            for(int col=0; col<width; col++) {

                for(int subRow = -subradius; subRow <= subradius; subRow++)
                {
                    for(int subCol = -subradius; subCol <= subradius; subCol++)
                    {
                        int nrow = row + subRow;
                        int ncol = col + subCol;
                        if(nrow >=height || nrow < 0)
                        {
                            nrow = 0;
                        }
                        if(ncol >= width || ncol < 0)
                        {
                            ncol = 0;
                        }
                        index = nrow * width + ncol;
                        tr = R[index] & 0xff;
                        tg = G[index] & 0xff;
                        tb = B[index] & 0xff;
                        int curIntensity = (int)(((double)((tr+tg+tb)/3)*intensity)/255.0f);
                        intensityCount[curIntensity]++;
                        ravg[curIntensity] += tr;
                        gavg[curIntensity] += tg;
                        bavg[curIntensity] += tb;
                    }
                }

                // find the max number of same gray level pixel
                int maxCount = 0, maxIndex = 0;
                for(int m=0; m<intensityCount.length; m++)
                {
                    if(intensityCount[m] > maxCount)
                    {
                        maxCount = intensityCount[m];
                        maxIndex = m;
                    }
                }

                // get average value of the pixel
                int nr = ravg[maxIndex] / maxCount;
                int ng = gavg[maxIndex] / maxCount;
                int nb = bavg[maxIndex] / maxCount;
                index = row * width + col;
                output[0][index] = (byte) nr;
                output[1][index] = (byte) ng;
                output[2][index] = (byte) nb;

                // post clear values for next pixel
                for(int i=0; i<=intensity; i++)
                {
                    intensityCount[i] = 0;
                    ravg[i] = 0;
                    gavg[i] = 0;
                    bavg[i] = 0;
                }

            }
        }

        ((ColorProcessor) src).putRGB(output[0], output[1], output[2]);
        output = null;

        return src;
    }
}

其原理是运用边缘保留滤波,边缘保留滤波有那些种,能够参见在此之前的一篇作品据说边缘保留滤波完毕人脸磨皮的算法。这里最首要用的是Mean shift算法,修改部分的像素权重进而完结图像的像素模糊,以完毕近似水墨画的意义。

图片 1算算局地均值.png

铅笔画成效

咱俩还开荒了另一款滤镜StrokeAreaFilter,用于模拟铅笔画的职能。

RxImageData.bitmap(bitmap).addFilter(new StrokeAreaFilter()).into(image);

看下效果

铅笔画效果.png

对于铅笔画来讲也是有一点牵强,那再组成三个随机噪声的滤镜试试。

RxImageData.bitmap(bitmap)
        .addFilter(new StrokeAreaFilter())
        .addFilter(new GaussianNoiseFilter())
        .into(image);

铅笔画功用2.png

职能亦不是特地好,那再换三个USMFilter试试。

RxImageData.bitmap(bitmap)
       .addFilter(new StrokeAreaFilter())
       .addFilter(new USMFilter())
       .into(image);

追根究底,本次效果比后边两幅效果越来越好了。

铅笔画功用3.png

唯独,由于是五个滤镜的附加,速度会慢非常多。再者,USMFilter它是持续高斯滤镜的。所以,在骨子里运用中只需单独选用StrokeAreaFilter就能够,细节多少能够依附参数来调解。

当边缘很弱的时候全面K趋近于0、该点的纠正偏差或偏侧之后的像素值就仿佛平均值。而当边缘很强的时候全面K趋近于1、该点的歪曲之后的像素值就类似等于输入像素值。上述计算中最中意的是窗口内像素的均值与方差,总括均值能够遵照积分图像很轻松获取,而计量方差依照一层层的数学推理能够获得如下的结果

总结

本文所采纳的七款滤镜OilPaintFilter和StrokeAreaFilter都在cv4j中。

cv4j 是gloomyfish和本人一块儿付出的图像管理库,纯java达成,目前还处于开始时代的本子,方今早就更新了滤镜的文书档案。

下周末大家做了七款滤镜,效果还算是蛮酷的,不过速度在移动端还相当不足完美,现在会想办法对算法做一些改革,以便越来越好地满意移动端的体验。

该连串先前的稿子:
二值图像深入分析之差不离深入分析
依照边缘保留滤波实现人脸磨皮的算法
二值图像解析:案例实战(文本分离+硬币计数)
Java完成高斯模糊和图像的半空中卷积
Java达成图片滤镜的高等玩的方法
Java实现图片的滤镜效果

图片 2演绎结果.png

宗旨的算法如下:

 @Override public ImageProcessor filter(ImageProcessor src) { // initialization parameters int width = src.getWidth(); int height = src.getHeight(); xr = yr = (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 { System.arraycopy(src.toByte, 0, output, 0, output.length); ii.setImage(src.toByte; ii.process(width, height, true); processSingleChannel(width, height, ii, output); System.arraycopy(output, 0, src.toByte, 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 - /size)/size; float d = c / ; r = *b + d*r); output[offset + col] = Tools.clamp; } } }

个中,IntIntegralImage封装了积分图像的算法,具体能够查阅 cv4j 中的实现。

依靠TiggoGB颜色空间的简便阈值肤色识别来促成皮肤检验,算法如下:LAND>95 And G>40 And B>20 And 猎豹CS6>G And 奥迪Q5>B And 马克斯-Min>15 And Abs>15

public class DefaultSkinDetection implements ISkinDetection{// RGB Color model pixel skin detection method//  is classified as skin if:// R > 95 and G > 40 and B > 20 and// max - min > 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; int min = Math.min(tr, Math.min; int rg = Math.abs; if(tr > 95 && tg > 40 && tb > 20 && rg > 15 && (max - min) > 15 && tr > tg && tr > tb) { return true; } else { return false; } }}

梯度滤波器也叫MediaTek滤波器。梯度滤波器有某个种分化措施,在此间用的是Sobel。Sobel算子依照像素点上下、左右邻点灰度加权差,在边缘处达到极值这一景况检查实验边缘。对噪音具备平滑效能,提供比较正确的边缘方向消息,边缘定位精度比不够高。当对精度须求不是异常高时,是一种比较常用的边缘检查测试方法。由于Sobel算法轻松功能高,所以大家在这里选拔它。

组成以上三步,在 cv4j 中贯彻人脸磨皮的滤镜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, R, 0, R.length); System.arraycopy(src.toByte, 0, G, 0, G.length); System.arraycopy(src.toByte, 0, B, 0, B.length); FastEPFilter epFilter = new FastEPFilter(); epFilter.filter; 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 { src.toByte[i] = r; src.toByte[i] = g; src.toByte[i] = 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 = (0.299 *r + 0.587*g + 0.114*b); gray[i] = 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[i] = r; src.toByte[i] = g; src.toByte[i] = b; } } return src; }}

BeautySkinFilter跟原本的滤镜用法是均等的,一行代码就足以兑现想要的功用:)

RxImageData.bitmap.addFilter(new BeautySkinFilter.into;

来探视在 Android 上的结尾效果:

图片 3人脸磨皮效果.png

cv4j 是gloomyfish和自己一块儿付出的图像管理库,纯java达成,目前还处于开始时期的版本。此次的人脸磨皮算法也还应该有立异空间,今后我们还可能会持续优化该算法。

说来很惭愧,由于大家的劳作都比较劳顿,未有来得及完善开拓文书档案。在及时赶到的五一之间,大家会补上文书档案,今后也会做出进一步炫人眼目的作用。

原先的稿子:二值图像深入分析:案例实战(文本分离+硬币计数)Java实现高斯模糊和图像的空中卷积Java达成图片滤镜的高级游戏的方法Java达成图片的滤镜效果

本文由大发体育娱乐在线发布于编程应用,转载请注明出处:如法泡制摄影和铅笔画的滤镜效果,基于边缘保

关键词:

最火资讯