Canvas effect

First, upload the original without any processing

The original image. The PNG

Then use the oil painting style OilPaintFilter to see the effect. OilPaintFilter can be used in one sentence 🙂

RxImageData.bitmap(bitmap).addFilter(new OilPaintFilter()).into(image);Copy the code

Oil painting effect. PNG

OilPaintFilter works well with images of people and landscapes.

OilPaintFilter source code:

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(a) {
        this(15.40);
    }

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

    public int getRadius(a) {
        return radius;
    }

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

    public int getIntensity(a) {
        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.0 f); 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;

        returnsrc; }}Copy the code

Its principle is the use of edge retention filtering, there are many kinds of edge retention filtering, can refer to the previous article based on edge retention filtering algorithm face grinding. Here, Mean Shift algorithm is mainly used to modify the local pixel weight to achieve pixel blur of the image, so as to achieve the effect similar to oil painting.

Pencil drawing effect

We also developed another filter, StrokeAreaFilter, to simulate the effect of pencil drawing.

RxImageData.bitmap(bitmap).addFilter(new StrokeAreaFilter()).into(image);Copy the code

Look at the effect

PNG pencil drawing effect

This might be a bit of a stretch for pencil drawing, but try adding a random noise filter.

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

Pencil drawing effect 2.png

The effect is not particularly good, then change a USMFilter to try.

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

Finally, the effect is better than the previous two.

Pencil drawing effect 3.png

However, since it is a combination of two filters, the speed will be much slower. Furthermore, USMFilter inherits the Gaussian filter. Therefore, in actual use, only the StrokeAreaFilter can be used alone, and the details can be adjusted according to parameters.

conclusion

The two filters used in this article, OilPaintFilter and StrokeAreaFilter, are in CV4J.

Cv4j is an image processing library developed by Hyperyfish and me, with a pure Java implementation. It is still in its early version and the documentation of filters has been updated.

We made two filters last weekend, the effect is still pretty cool, but the speed is not ideal for mobile terminal. We will try to improve the algorithm in the future, so as to better meet the experience of mobile terminal.

This series of previous articles: binary image analysis contour analysis based on edge retention filtering algorithm to achieve face peeling binary image analysis – case study (text separation + coin counting) Java to achieve Gaussian blur and image space convolution Java to achieve image filter advanced play Java to achieve image filter effect