android semitransparent bitmap background is black - android

I'm trying to create semitransparent bitmaps, I used this code:
private Bitmap SemiTransparent(Bitmap bitmap, int opacity) {
// Create an array to hold the data of bitmap for which semi transparent bitmap is to be obtained
int[] data = new int[(int)(bitmap.getWidth()) + 1];
for (int y = 0; y < bitmap.getHeight(); ++y)
{
// Get a single line of data
bitmap.getPixels(data, 0, bitmap.getWidth(), 0, y,bitmap.getWidth(), 1);
// Reset the alpha values
for (int x = bitmap.getWidth(); x>0; --x)
{
data[x] = (data[x] & 0x00ffffff) | (opacity << 24);
}
//fill alphaBitmap data
bitmap.setPixels(data, 0, bitmap.getWidth(), 0, y, bitmap.getWidth(), 1);
}
return bitmap;
}
The only problem is the background (transparent) color is always black - how can I modify this to make the background Color completely transparent and the rest still semitransparent?

Use this method to make a bitmap transparent:
/**
* #param bitmap The source bitmap.
* #param opacity a value between 0 (completely transparent) and 255 (completely
* opaque).
* #return The opacity-adjusted bitmap. If the source bitmap is mutable it will be
* adjusted and returned, otherwise a new bitmap is created.
*/
private Bitmap adjustOpacity(Bitmap bitmap, int opacity)
{
Bitmap mutableBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);
Canvas canvas = new Canvas(mutableBitmap);
int colour = (opacity & 0xFF) << 24;
canvas.drawColor(colour, PorterDuff.Mode.DST_IN);
return mutableBitmap;
}
See an explanation here:
http://blog.uncommons.org/2011/01/12/adjusting-the-opacity-of-an-android-bitmap/
In the blog-post it checks if the bitmap is mutable or not - which can cause problems if the bitmap is mutable but doesn't have the config ARGB_8888 - so use my method instead.

Related

Extract a person from an image in Google ML Kit with Selfie Segmentation in Kotlin

I would like to remove a background from an image with a person in order to use this image in some other part of my android app. I have applied Google ML Kit - Selfie Segmentation and receive segmentation Mask as a result. What I want to do now is - save the image without a background to a device so I can then use it in other parts of my app.
Original image:
Image after Applied Selfie Segmentation:
My problem is I need to somehow apply values from segmentationMask (256 * 256) to the Bitmap where I will remove background and save new Bitmap (with values from segmentation mask on only those pixels that are currently blue) with pixels from segmentation mask. Would anyone be so king and point me in the direction? Should I try to achieve this with Matrix ?? Currently I am drawind this image on jetpack compose Canvas with drawPoints comand in DrawScope.
There is an enableRawSizeMask API on the SelfieSegmenterOptions.Builder. If you don't set it, the returned mask should have the same dimension as the input image.
Then a naive approach would be: Iterating through the result mask to determine whether a certain pixel should be kept, if not, call setPixel method on the original Bitmap to set the background pixel to transparent (or whatever color you want).
This is for sure not the most performant way, but maybe a good start.
Maybe you can try it,this is my way
private void initUI(){
ImageView imageView=findViewById(R.id.iv);
Paint paint=new Paint();
paint.setAntiAlias(true);
SelfieSegmenterOptions options=new SelfieSegmenterOptions.Builder()
.setDetectorMode(SelfieSegmenterOptions.STREAM_MODE)
//.enableRawSizeMask()
.build();
Segmenter segmenter = Segmentation.getClient(options);
Bitmap bitmap= BitmapFactory.decodeResource(getResources(), R.drawable.mv1);
InputImage image = InputImage.fromBitmap(bitmap, 0);
segmenter.process(image).addOnSuccessListener(segmentationMask -> {
ByteBuffer mask = segmentationMask.getBuffer();
int maskWidth = segmentationMask.getWidth();
int maskHeight = segmentationMask.getHeight();
Bitmap background=Bitmap.createBitmap(maskColorsFromByteBuffer(mask,maskWidth,maskHeight),maskWidth,maskHeight, Bitmap.Config.ARGB_8888);
//创建一个bitmap
Bitmap foreground=Bitmap.createBitmap(bitmap.getWidth(),bitmap.getHeight(), Bitmap.Config.ARGB_8888); //裁剪后的图像
Canvas canvas=new Canvas(foreground);
//绘制扣出来的背景
canvas.drawBitmap(background,0,0,paint);
//设置混合模式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
//绘制原图
canvas.drawBitmap(bitmap,0,0,paint);
imageView.setImageBitmap(foreground);
}).addOnFailureListener(e -> {
// Task failed with an exception
// ...
});
}
private int[] maskColorsFromByteBuffer(ByteBuffer byteBuffer,int maskWidth,int maskHeight) {
#ColorInt int[] colors = new int[maskWidth * maskHeight];
for (int i = 0; i < maskWidth * maskHeight; i++) {
float backgroundLikelihood = 1 - byteBuffer.getFloat();
if (backgroundLikelihood > 0.9) { //128
colors[i] = Color.argb(255, 255, 0, 255);
//colors[i] = Color.argb(0, 255, 0, 255);
} else if (backgroundLikelihood > 0.2) {
// Linear interpolation to make sure when backgroundLikelihood is 0.2, the alpha is 0 and
// when backgroundLikelihood is 0.9, the alpha is 128.
// +0.5 to round the float value to the nearest int.
int alpha = (int) (182.9 * backgroundLikelihood - 36.6 + 0.5);
colors[i] = Color.argb(255, 255, 0, 255);
}
}
return colors;
}

How to save bitmap from GLSurfaceView (Only bitmap, not whole texture)

I am using this code to give multiple effect on bitmap that is on GlSurfaceView.
apply-effects-on-image-using-effects
Now, I want to save the bitmap. They have given the code to save the bitmap but with that, whole GlSurfaceView is going to be saved as bitmap image. Instead I want to save only bitmap area to save as Image.
There is method that takes pixels and make bitmap from that and also make image.
e.g.:
public Bitmap takeScreenshot(GL10 mGL) {
final int mWidth = mEffectView.getWidth();
final int mHeight = mEffectView.getHeight();
IntBuffer ib = IntBuffer.allocate(mWidth * mHeight);
IntBuffer ibt = IntBuffer.allocate(mWidth * mHeight);
mGL.glReadPixels(0, 0, mWidth, mHeight, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
// Convert upside down mirror-reversed image to right-side up normal
// image.
for (int i = 0; i < mHeight; i++) {
for (int j = 0; j < mWidth; j++) {
ibt.put((mHeight - i - 1) * mWidth + j, ib.get(i * mWidth + j));
}
}
Bitmap mBitmap = Bitmap.createBitmap(mWidth, mHeight, Bitmap.Config.ARGB_8888);
mBitmap.copyPixelsFromBuffer(ibt);
return mBitmap;
}
I guess, I need to update it like, instead it to be start with 0, 0, that should be start with bitmap top left coordinate. And that should work till bitmap height and width.
So, with that I can able to resolved my issue but don't know how to get that coordinate of bitmap image in GLSurfaceView.
Please check below image for more clarification.
Original Image:
Loaded image in the effect screen:
Image after applying effect and saved it:
This is what i want.
If you can get the dimensions of the image, you can get the exact position of the bitmap.
Let the image dimensions be x and y, and get the screen dimensions following this post. Let that be a and b.
Your starting position will be ((a-x)/2, (b-y)/2).
Use this to crop your image.

Create nine-patch from bitamp - and getting new adjust bitmap

I'm tring to download an image from the net, and to convert it to ninepatch format, how I select the stretchable pixels is out of scope for this thread.
I'm trying to use gist solution but I couldn't get it to work.
This is the source code:
NinePatchDrawable np = createNinePathWithCapInsets(res, bitmap, top,left, bitmap.getWidth() - right, bitmap.getHeight() - bottom, null);
and to get the resulted bitmap:
Bitmap outputBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(outputBitmap);
//np.setBounds(0, 0, width, height);
np.draw(canvas);
canvas.drawBitmap(outputBitmap, width, height, new Paint());
The returned bitmap doesn't contain the source bitmap and looks just like 4 segmentations(rect seg').
I could find any other to achive that goal, even not using OpenGL
The resulted image is:
try this:
public static byte[] getChunk(int xs, int xe, int ys, int ye) {
ByteBuffer b = ByteBuffer.allocate(84).order(ByteOrder.nativeOrder());
b.put((byte) 1); // wasDeserialized
b.put((byte) 2); // numXDivs
b.put((byte) 2); // numYDivs
b.put((byte) 9); // numColors
b.putInt(0); // UNKNOWN
b.putInt(0); // UNKNOWN
b.putInt(0); // paddingLeft
b.putInt(0); // paddingRight
b.putInt(0); // paddingTop
b.putInt(0); // paddingBottom
b.putInt(0); // UNKNOWN
b.putInt(xs); // segX start
b.putInt(xe); // segX end
b.putInt(ys); // segY start
b.putInt(ye); // segY end
for (int i = 0; i < 9; i++) {
b.putInt(1); // NO_COLOR
}
return b.array();
}
you can use it in NinePatchDrawable constructor (Bitmap, byte[], Rect, String)

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 :)

Efficient Bitmap masking with black and white alpha mask in 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;

Categories

Resources