pixelate image in code

丶灬走出姿态 提交于 2020-01-15 12:33:06

问题


I've searched for how to pixelate an image in android via code, the results are varied.

I've found libraries and tutorials on how to apply other effects found here: http://xjaphx.wordpress.com/learning/tutorials/

Can someone clear things up for me, what is the simplest way of pixelating an image on the fly in android

Also it would be handy if it was a function that I could how many rounds or how much I wanted the image pixelating.

Thank in advance.


回答1:


The simplest way to pixelate the image would be to scale image down using "nearest neighbour" algorithm, and then scale up, using the same algorithm.

Filtering over the image trying to find an average takes much more time, but does not actually give any improvements in result quality, after all you do intentionally want your image distorted.




回答2:


I have done this before in vb.net and its easily made into a function whose parameter can control how pixelated you want it.

The basic idea is to scan the image in section of blocks of X width and y height. for each block you find the average RGB value and set all those pixels to that color. the smaller the block size the less pixelated.

int avR,avB,avG; // store average of rgb 
    int pixel;
    Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());

    for(int x = 0; x < width; x+= pixelationAmount) { // do the whole image
        for(int y = 0; y < height; y++ pixelationamount) {
            avR = 0; avG = 0; avB =0;

            for(int xx =x; xx <pixelationAmount;xx++){// YOU WILL WANT TO PUYT SOME OUT OF                                      BOUNDS CHECKING HERE
                for(int yy= y; yy <pixelationAmount;yy++){ // this is scanning the colors
                    pixel = src.getPixel(x, y);
                    avR += (int) (color.red(pixel);
                    avG+= (int) (color.green(pixel);
                    avB += (int) (color.blue(pixel);
                }
            }
            avrR/= pixelationAmount^2; //divide all by the amount of samples taken to get an average
            avrG/= pixelationAmount^2;
            avrB/= pixelationAmount^2;

            for(int xx =x; xx <pixelationAmount;xx++){// YOU WILL WANT TO PUYT SOME OUT OF BOUNDS CHECKING HERE
                for(int yy= y; yy <pixelationAmount;yy++){ // this is going back over the block 
                    bmOut.setPixel(xx, yy, Color.argb(255, avR, avG,avB)); //sets the block to the average color
                }
            }

        }

    }

sorry about the bad formatting (wrote it in notepad quickly) but thought it might give you a framework to make your own pixelate function




回答3:


This is corrected of above algorithm that works:

    Bitmap bmOut = Bitmap.createBitmap(OriginalBitmap.getWidth(),OriginalBitmap.getHeight(),OriginalBitmap.getConfig());
    int pixelationAmount = 50; //you can change it!!
    int width = OriginalBitmap.getWidth();
    int height = OriginalBitmap.getHeight();
    int avR,avB,avG; // store average of rgb 
    int pixel;

    for(int x = 0; x < width; x+= pixelationAmount) { // do the whole image
        for(int y = 0; y < height; y+= pixelationAmount) {
            avR = 0; avG = 0; avB =0;


            int bx = x + pixelationAmount;
            int by = y + pixelationAmount;
            if(by >= height) by = height;
            if(bx >= width)bx = width;
            for(int xx =x; xx < bx;xx++){// YOU WILL WANT TO PUYT SOME OUT OF                                      BOUNDS CHECKING HERE
                for(int yy= y; yy < by;yy++){ // this is scanning the colors

                    pixel = OriginalBitmap.getPixel(xx, yy);
                    avR += (int) (Color.red(pixel));
                    avG+= (int) (Color.green(pixel));
                    avB += (int) (Color.blue(pixel));
                }
            }
            avR/= pixelationAmount^2; //divide all by the amount of samples taken to get an average
            avG/= pixelationAmount^2;
            avB/= pixelationAmount^2;

            for(int xx =x; xx < bx;xx++)// YOU WILL WANT TO PUYT SOME OUT OF BOUNDS CHECKING HERE
                for(int yy= y; yy <by;yy++){ // this is going back over the block 
                    bmOut.setPixel(xx, yy, Color.argb(255, avR, avG,avB)); //sets the block to the average color
                }


        }

    }
    iv.setImageBitmap(bmOut);

anyway it was not what i was looking for




回答4:


I have change previous algorithm completely and it really done something like mosaic filter! the idea is to replace each block pixels with its below block pixels use this function simply:

public void filter(){
    Bitmap bmOut = Bitmap.createBitmap(OriginalBitmap.getWidth(),OriginalBitmap.getHeight(),OriginalBitmap.getConfig());

    int pixelationAmount = 10;
    Bitmap a = Bitmap.createBitmap(pixelationAmount,pixelationAmount,OriginalBitmap.getConfig());
    Bitmap b = Bitmap.createBitmap(pixelationAmount,pixelationAmount,OriginalBitmap.getConfig());
    int width = OriginalBitmap.getWidth();
    int height = OriginalBitmap.getHeight();
    int pixel;
    int counter = 1;
    int px = 0;int py = 0;int pbx=0;int pby=0;
    for(int x = 0; x < width; x+= pixelationAmount) { // do the whole image
        for(int y = 0; y < height; y+= pixelationAmount) {
            int bx = x + pixelationAmount;
            int by = y + pixelationAmount;
            if(by >= height) by = height;
            if(bx >= width)bx = width;
            int xxx = -1;
            int yyy = -1;
            for(int xx =x; xx < bx;xx++){// YOU WILL WANT TO PUYT SOME OUT OF                                      BOUNDS CHECKING HERE
                xxx++;
                yyy = -1;
                for(int yy= y; yy < by;yy++){ // this is scanning the colors
                    yyy++;
                    pixel = OriginalBitmap.getPixel(xx, yy);
                    if(counter == 1)
                    {
                        a.setPixel(xxx, yyy, pixel);
                        px = x;//previous x
                        py = y;//previous y
                        pbx = bx;
                        pby = by;
                    }
                    else
                        b.setPixel(xxx, yyy, pixel);
                }
            }
            counter++;
            if(counter == 3)
            {
                int xxxx = -1;
                int yyyy = -1;
                for(int xx =x; xx < bx;xx++)
                {
                    xxxx++;
                    yyyy = -1;
                    for(int yy= y; yy <by;yy++){ 
                        yyyy++;
                        bmOut.setPixel(xx, yy, b.getPixel(xxxx, yyyy)); 
                    }
                }
                for(int xx =px; xx < pbx;xx++)
                {
                    for(int yy= py; yy <pby;yy++){  
                        bmOut.setPixel(xx, yy, a.getPixel(xxxx, yyyy)); //sets the block to the average color
                    }
                }

                counter = 1;
            }


        }

    }
    image_view.setImageBitmap(bmOut);
}



回答5:


This is the code I used:

ImageFilter is the parent class:

public abstract class ImageFilter {

protected int [] pixels;
protected int width;
protected int height;

public ImageFilter (int [] _pixels, int _width,int _height){
    setPixels(_pixels,_width,_height);
}


public void setPixels(int [] _pixels, int _width,int _height){
    pixels = _pixels;
    width = _width;
    height = _height;
}

/**
 * a weighted Euclidean distance in RGB space
 * @param c1
 * @param c2
 * @return
 */
public double colorDistance(int c1, int c2)
{
    int red1 = Color.red(c1);
    int red2 = Color.red(c2);
    int rmean = (red1 + red2) >> 1;
    int r = red1 - red2;
    int g = Color.green(c1) - Color.green(c2);
    int b = Color.blue(c1) - Color.blue(c2);
    return Math.sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}

public abstract int[]  procImage();

}

public class PixelateFilter extends ImageFilter {

int pixelSize;
int[] colors;

/**
 * @param _pixels
 * @param _width
 * @param _height
 */
public PixelateFilter(int[] _pixels, int _width, int _height) {
    this(_pixels, _width, _height, 10);
}

public PixelateFilter(int[] _pixels, int _width, int _height, int _pixelSize) {
    this(_pixels, _width, _height, _pixelSize, null);
}

public PixelateFilter(int[] _pixels, int _width, int _height, int _pixelSize, int[] _colors) {
    super(_pixels, _width, _height);
    pixelSize = _pixelSize;
    colors = _colors;
}

/* (non-Javadoc)
 * @see imageProcessing.ImageFilter#procImage()
 */
@Override
public int[] procImage() {
    for (int i = 0; i < width; i += pixelSize) {
        for (int j = 0; j < height; j += pixelSize) {
            int rectColor = getRectColor(i, j);
            fillRectColor(rectColor, i, j);
        }
    }
    return pixels;
}

private int getRectColor(int col, int row) {
    int r = 0, g = 0, b = 0;
    int sum = 0;
    for (int x = col; x < col + pixelSize; x++) {
        for (int y = row; y < row + pixelSize; y++) {
            int index = x + y * width;
            if (index < width * height) {
                int color = pixels[x + y * width];
                r += Color.red(color);
                g += Color.green(color);
                b += Color.blue(color);
            }

        }
    }
    sum = pixelSize * pixelSize;
    int newColor = Color.rgb(r / sum, g / sum, b / sum);
    if (colors != null)
        newColor = getBestMatch(newColor);
    return newColor;
}

private int getBestMatch(int color) {
    double diff = Double.MAX_VALUE;
    int res = color;
    for (int c : colors) {
        double currDiff = colorDistance(color, c);
        if (currDiff < diff) {
            diff = currDiff;
            res = c;
        }
    }
    return res;
}


private void fillRectColor(int color, int col, int row) {
    for (int x = col; x < col + pixelSize; x++) {
        for (int y = row; y < row + pixelSize; y++) {
            int index = x + y * width;
            if (x < width && y < height && index < width * height) {
                pixels[x + y * width] = color;
            }

        }
    }
}



public static final Bitmap changeToPixelate(Bitmap bitmap, int pixelSize, int [] colors) {
    int width = bitmap.getWidth();
    int height = bitmap.getHeight();

    int[] pixels = new int[width * height];
    bitmap.getPixels(pixels, 0, width, 0, 0, width, height);

    PixelateFilter pixelateFilter = new PixelateFilter(pixels, width, height, pixelSize, colors);

    int[] returnPixels = pixelateFilter.procImage();
    Bitmap returnBitmap = Bitmap.createBitmap(returnPixels, width, height, Bitmap.Config.ARGB_8888);

    return returnBitmap;

}

}

Here is how you use it:

    int [] colors = new int [] { Color.BLACK,Color.WHITE,Color.BLUE,Color.CYAN,Color.RED};
    final Bitmap bmOut  = PixelateFilter.changeToPixelate(OriginalBitmap, pixelSize,colors);


来源:https://stackoverflow.com/questions/15547125/pixelate-image-in-code

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!