Efficient Bitmap masking with black and white alpha mask in Android - android

I wanted to mask a Bitmap with a black and white alpha mask. My mask image is black and white, the BLACK area means TRANSPARENT and WHITE area means OPAQUE.
What I need is:
When I use this mask image to mask any other image, the area of resultant image should TRANSPARENT if the corresponding area of mask image is BLACK. Otherwise the area of resultant image should be OPAQUE.
I have attached the sample images. Please help me with this guys.
Sample Image:
Sample Image for Masking
What I have tried so far:
The following methods work fine. But they are very slow. I needed some solution that is efficient in terrms of speed and memory than these methods.
First Method:
int width = rgbDrawable.getWidth();
int height = rgbDrawable.getHeight();
if (width != alphaDrawable.getWidth() || height != alphaDrawable.getHeight()) {
throw new IllegalStateException("image size mismatch!");
}
Bitmap destBitmap = Bitmap.createBitmap(width, height,
Bitmap.Config.ARGB_8888);
int[] pixels = new int[width];
int[] alpha = new int[width];
for (int y = 0; y < height; y++)
{
rgbDrawable.getPixels(pixels, 0, width, 0, y, width, 1);
alphaDrawable.getPixels(alpha, 0, width, 0, y, width, 1);
for (int x = 0; x < width; x++)
{
// Replace the alpha channel with the r value from the bitmap.
pixels[x] = (pixels[x] & 0x00FFFFFF) | ((alpha[x] << 8) & 0xFF000000);
}
destBitmap.setPixels(pixels, 0, width, 0, y, width, 1);
}
alphaDrawable.recycle();
rgbDrawable.recycle();
return destBitmap;
Second Method
float[] nlf = new float[] {
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
1, 0, 0, 0, 0};
ColorMatrix sRedToAlphaMatrix = new ColorMatrix(nlf);
ColorMatrixColorFilter sRedToAlphaFilter = new ColorMatrixColorFilter(sRedToAlphaMatrix);
// Load RGB data
Bitmap rgb = rgbDrawable;
// Prepare result Bitmap
Bitmap target = Bitmap.createBitmap(rgb.getWidth(), rgb.getHeight(), Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(target);
c.setDensity(Bitmap.DENSITY_NONE);
// Draw RGB data on our result bitmap
c.drawBitmap(rgb, 0, 0, null);
// At this point, we don't need rgb data any more: discard!
rgb.recycle();
rgb = null;
// Load Alpha data
Bitmap alpha = alphaDrawable;
// Draw alpha data on our result bitmap
final Paint grayToAlpha = new Paint();
grayToAlpha.setColorFilter(sRedToAlphaFilter);
grayToAlpha.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
c.drawBitmap(alpha, 0, 0, grayToAlpha);
// Don't need alpha data any more: discard!
alpha.recycle();
alpha = null;
return target;

Related

Converting color bitmap to grayscale image using only the blue channel using a colormatrix

I need to grayscale a bitmap in Android using only the blue color channel.
I managed to get rid of the green and red channels by using a colormatrix, but when I set the saturation of that matrix to 0 it is ignoring the previously made changes to the red and green channels.
Is there a way to accomplish my task? Iterating through the whole pixel array is not an option as it is way too slow.
I'm using this piece of code:
public Bitmap ConvertToGrayscale(Bitmap bitmap) {
int height = super.getHeight();
int width = super.getWidth();
float[] arrayForColorMatrix = new float[] {0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0};
Bitmap.Config config = bitmap.getConfig();
Bitmap grayScaleBitmap = Bitmap.createBitmap(width, height, config);
Canvas c = new Canvas(grayScaleBitmap);
Paint paint = new Paint();
ColorMatrix matrix = new ColorMatrix(arrayForColorMatrix);
matrix.setSaturation(0);
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(matrix);
paint.setColorFilter(filter);
c.drawBitmap(bitmap, 0, 0, paint);
return grayScaleBitmap;
}
The correct matrix for getting a gray scaled image from the blue channel is the following:
float[] arrayForColorMatrix = new float[] {0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 1, 0, 0,
0, 0, 0, 1, 0};
From the Android documentation:
When applied to a color [r, g, b, a], the resulting color is computed as (after clamping):
R' = a*R + b*G + c*B + d*A + e;
G' = f*R + g*G + h*B + i*A + j;
B' = k*R + l*G + m*B + n*A + o;
A' = p*R + q*G + r*B + s*A + t;
Using my arrayForColorMatrix I get the blue value for every value of the RGB color components, which results in a gray scaled bitmap based on the blue channel.

How to convert color image bitmap to black&white image bitmap in android?

In my Business Card Reader android application, I need to convert color image bitmap to black & white image bitmap (not gray scale image) for OCR text reading. so please help me to to convert color image bitmap to black & white image bitmap in android.
This question is long ago, but probably I could help other users.
I also had a long search for creating (fast)a pure Black and White bitmap.
My first methode used bitmap.getPixel() and bitmap.setPixel()
This took about 8s (832 x 1532)
New Method took 0.4s! Thanks factor 20!
Now I load all Pixels in an int array and go so through all pixels with getPixels(..) and setPixels(..):
Here my method:
public static Bitmap createBlackAndWhite(Bitmap src) {
int width = src.getWidth();
int height = src.getHeight();
Bitmap bmOut = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
final float factor = 255f;
final float redBri = 0.2126f;
final float greenBri = 0.2126f;
final float blueBri = 0.0722f;
int length = width * height;
int[] inpixels = new int[length];
int[] oupixels = new int[length];
src.getPixels(inpixels, 0, width, 0, 0, width, height);
int point = 0;
for(int pix: inpixels){
int R = (pix >> 16) & 0xFF;
int G = (pix >> 8) & 0xFF;
int B = pix & 0xFF;
float lum = (redBri * R / factor) + (greenBri * G / factor) + (blueBri * B / factor);
if (lum > 0.4) {
oupixels[point] = 0xFFFFFFFF;
}else{
oupixels[point] = 0xFF000000;
}
point++;
}
bmOut.setPixels(oupixels, 0, width, 0, 0, width, height);
return bmOut;
}
You could convert the image applying a color filter in this way:
Bitmap bwBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bwBitmap );
//set contrast
ColorMatrix contrastMatrix = new ColorMatrix();
//change contrast
float contrast = 50.f;
float shift = (-.5f * contrast + .5f) * 255.f;
contrastMatrix .set(new float[] {
contrast , 0, 0, 0, shift ,
0, contrast , 0, 0, shift ,
0, 0, contrast , 0, shift ,
0, 0, 0, 1, 0 });
//apply contrast
Paint contrastPaint = new Paint();
contrastPaint.setColorFilter(new ColorMatrixColorFilter(contrastMatrix ));
canvas.drawBitmap(colorBitmap, 0, 0, contrastPaint);
//set saturation
ColorMatrix saturationMatrix = new ColorMatrix();
saturationMatrix.setSaturation(0); //you set color saturation to 0 for b/w
//apply new saturation
Paint saturationPaint = new Paint();
saturationPaint.setColorFilter(new ColorMatrixColorFilter(saturationPaint));
canvas.drawBitmap(colorBitmap, 0, 0, saturationPaint);
You need to use ColorMatrix and ColorFilterclass in android to convert to Black and White.
Use this ColorMatrix - ColorMatrix cm1 = new ColorMatrix(new float[]{0.5f,0.5f,0.5f,0,0,
0.5f,0.5f,0.5f,0,0,
0.5f,0.5f,0.5f,0,0,
0,0,0,1,0,0,
0,0,0,0,1,0
});

Replacing a color in a Bitmap

I have images which I display in my app. They are downloaded from the web. These images are pictures of objects on an almost-white background. I want this background to be white (#FFFFFF). I figure, if I look at pixel 0,0 (which should always be off-white), I can get the color value and replace every pixel in the image having that value with white.
This question has been asked before and the answer seems to be this:
int intOldColor = bmpOldBitmap.getPixel(0,0);
Bitmap bmpNewBitmap = Bitmap.createBitmap(bmpOldBitmap.getWidth(), bmpOldBitmap.getHeight(), Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpNewBitmap);
Paint paint = new Paint();
ColorFilter filter = new LightingColorFilter(intOldColor, Color.WHITE);
paint.setColorFilter(filter);
c.drawBitmap(bmpOriginal, 0, 0, paint);
However, this isn't working.
After running this code, the entire image seems to be the color I was wanting to remove. As in, the entire image is 1 solid color now.
I was also hoping to not have to loop through every pixel in the entire image.
Any ideas?
Here is a method I created for you to replace a specific color for the one you want. Note that all the pixels will get scanned on the Bitmap and only the ones that are equal will be replaced for the one you want.
private Bitmap changeColor(Bitmap src, int colorToReplace, int colorThatWillReplace) {
int width = src.getWidth();
int height = src.getHeight();
int[] pixels = new int[width * height];
// get pixel array from source
src.getPixels(pixels, 0, width, 0, 0, width, height);
Bitmap bmOut = Bitmap.createBitmap(width, height, src.getConfig());
int A, R, G, B;
int pixel;
// iteration through pixels
for (int y = 0; y < height; ++y) {
for (int x = 0; x < width; ++x) {
// get current index in 2D-matrix
int index = y * width + x;
pixel = pixels[index];
if(pixel == colorToReplace){
//change A-RGB individually
A = Color.alpha(colorThatWillReplace);
R = Color.red(colorThatWillReplace);
G = Color.green(colorThatWillReplace);
B = Color.blue(colorThatWillReplace);
pixels[index] = Color.argb(A,R,G,B);
/*or change the whole color
pixels[index] = colorThatWillReplace;*/
}
}
}
bmOut.setPixels(pixels, 0, width, 0, 0, width, height);
return bmOut;
}
I hope that helped :)

ColorMatrixColorFilter does not affect alpha values less than 255

I have a method that take a Bitmap and a color, and converts all the pixels on the Bitmap to that color, while keeping the original's alpha values. In addition, the method is written so that as the color passed in gets darker, the Bitmap is made more transparent rather than darker. If the color passed in is completely black, then the Bitmap should be made entirely transparent instead of black.
public static Bitmap colorImage(Bitmap img, int red, int green, int blue) {
int max = blue;
if (red >= green && red >= blue)
max = red;
else if (green >= red && green >= blue)
max = green;
double scale = 255.0 / max;
red = (int)(scale * red);
green = (int)(scale * green);
blue = (int)(scale * blue);
Bitmap resultBitmap = img.copy(Bitmap.Config.ARGB_8888, true);
float[] colorTransform = {
0, 0, 0, 0, red,
0, 0, 0, 0, green,
0, 0, 0, 0, blue,
0, 0, 0, (float) (1f / scale), 0};
ColorMatrix colorMatrix = new ColorMatrix(colorTransform);
ColorMatrixColorFilter colorFilter = new ColorMatrixColorFilter(colorMatrix);
Paint paint = new Paint();
paint.setColorFilter(colorFilter);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(resultBitmap, 0, 0, paint);
return resultBitmap;
}
There is an issue with making the Bitmap transparent.
If I set the color matrix so that it is as follows,
float[] colorTransform = {
0, 0, 0, 0, red,
0, 0, 0, 0, green,
0, 0, 0, 0, blue,
0, 0, 0, 0, 0};
the entire Bitmap should be made completely transparent. However, this only works correctly if the original Bitmap has no transparency at all. If the Bitmap has only alpha values of 255 for all of its pixels, then the result is completely transparent. However, if the Bitmap has any pixel with an alpha value of less than 255, the final image will not be transparent, but will have the same alpha values as the original.
Can anybody tell why?
Thanks in advance.
Bitmaps by default have black backgrounds. Setting the Bitmap's background to transparent resolves the issue.
This can be done by adding resultBitmap.eraseColor(Color.argb(0, 0, 0, 0)); after resultBitmap is declared, changing canvas.drawBitmap(resultBitmap, 0, 0, paint); to canvas.drawBitmap(img, 0, 0, paint);.

Android : Converting color image to grayscale [duplicate]

This question already has answers here:
Convert a Bitmap to GrayScale in Android
(5 answers)
Closed 9 years ago.
I am trying to convert color image into grayscale using the average of red, green, blue. But it comes out with errors.
Here is my code
imgWidth = myBitmap.getWidth();
imgHeight = myBitmap.getHeight();
for(int i =0;i<imgWidth;i++) {
for(int j=0;j<imgHeight;j++) {
int s = myBitmap.getPixel(i, j)/3;
myBitmap.setPixel(i, j, s);
}
}
ImageView img = (ImageView)findViewById(R.id.image1);
img.setImageBitmap(myBitmap);
But when I run my application on Emulator, it's force close. Any idea?
I have solved my problem use the following code:
for(int x = 0; x < width; ++x) {
for(int y = 0; y < height; ++y) {
// get one pixel color
pixel = src.getPixel(x, y);
// retrieve color of all channels
A = Color.alpha(pixel);
R = Color.red(pixel);
G = Color.green(pixel);
B = Color.blue(pixel);
// take conversion up to one single value
R = G = B = (int)(0.299 * R + 0.587 * G + 0.114 * B);
// set new pixel color to output bitmap
bmOut.setPixel(x, y, Color.argb(A, R, G, B));
}
}
You can do this too :
ColorMatrix matrix = new ColorMatrix();
matrix.setSaturation(0);
imageview.setColorFilter(new ColorMatrixColorFilter(matrix));
Try the solution from this previous answer by leparlon:
public Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
Lalit has the most practical answer. However, you wanted the resulting grey to be the average of the red, green and blue and should set up your matrix like so:
float oneThird = 1/3f;
float[] mat = new float[]{
oneThird, oneThird, oneThird, 0, 0,
oneThird, oneThird, oneThird, 0, 0,
oneThird, oneThird, oneThird, 0, 0,
0, 0, 0, 1, 0,};
ColorMatrixColorFilter filter = new ColorMatrixColorFilter(mat);
paint.setColorFilter(filter);
c.drawBitmap(original, 0, 0, paint);
And finally, as I have faced the problem of converting an image to grayscale before - the most visually pleasing result in all cases is achieved by not taking the average, but through giving each colour different weight depending on its percieved brightness, I tend to use these values:
float[] mat = new float[]{
0.3f, 0.59f, 0.11f, 0, 0,
0.3f, 0.59f, 0.11f, 0, 0,
0.3f, 0.59f, 0.11f, 0, 0,
0, 0, 0, 1, 0,};

Categories

Resources