Android opengl screenshot with alpha channel support - android

I'm currently developing an augmented reality application in android. Textured openGL object is drawn over the camera view. I had tried so many methods to take the screen shot of android openGL view (GLSurfaceview). But no success. I want the screenshot with transparent background so that I could draw it over camera image to produce an ARImage. Can any one help me? I know that I have to read the pixels of opengl using glReadPixels() function. I tried it using GL_RGBA mode and created bitmap (used ARGB_8888 and RGB_565). Using ARGB_8888 format I'll get a transparent image with no object and in RGB_565 mode I'll get a image filled with black color. Can any one guide me? Thanks in advance.
Thanks,
Midhun

Hi I found the solution to my question and I'll paste the code here. It may be useful for others who need alpha support.
public static Bitmap SavePixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
}

This so called "solution" is simply making a screen shot. Alpha values that you get from glReadPixels are up to full 255 although you didn't draw anything to those pixels. If it's possible it will be an OpenGL-settings solution.

Related

What is the fastest way to create image files

I have a medical device that sends pixel's values in order to plot as an image (frame after frame).
I need to take the pixels and build from them an image on the screen. Currently with the code I wrote, I manage to receive 2fps for image size of 800x600.
What is the fastest way plot an image on screen? and doing it continuously.
Bitmap mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Canvas c = new Canvas(mBitmap);
Paint paint = new Paint();
int[] colorMatrix = new int[width * height];
for (int i = 0; i < imageXY.length; i++) {
int indexValue = Integer.parseInt(strValueIndex[i]);
int pixelValue = Integer.parseInt(imageValue[indexValue - 1]);
int pixelIndex = GetXY(imageXY[i]);
//int pixelIndex = Integer.parseInt(imageXY[i].split(",")[2]);
colorMatrix[pixelIndex] = pixelValue;
}
c.drawBitmap(colorMatrix, 0, width, 0, 0, width, height, false, paint);
myImage.setImageBitmap(mBitmap);
However its take about 500ms for each frame
This is the easiest place to start OpenGL in Android: http://developer.android.com/guide/topics/graphics/opengl.html
I would also look into using multiple cores for this process; although the GPU based calculations may offer higher single core speeds, a fairly "simple" task such as this will be greatly accelerated by utilizing multiple cores and parallel processing, and shouldn't be too hard to implement. Here is an introduction to parallel processing on Android devices.
https://developer.qualcomm.com/blog/multi-threading-android-apps-multi-core-processors-part-1-2

Android: Converting a Bitmap to a Monochrome Bitmap (1 Bit per Pixel)

I want to print a Bitmap to a mobile Bluetooth Printer (Bixolon SPP-R200) - the SDK doesn't offer direkt methods to print an in-memory image. So I thought about converting a Bitmap like this:
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
To a Monochrome Bitmap. I am drawing black text on above given Bitmap using a Canvas, which works well. However, when I convert the above Bitmap to a ByteArray, the printer seems to be unable to handle those bytes. I suspect I need an Array with one Bit per Pixel (a Pixel would be either white = 1 or black = 0).
As there seems to be no convenient, out of the box way to do that, one idea I had was to use:
bitmap.getPixels(pixels, offset, stride, x, y, width, height)
to Obtain the pixels. I assume, I'd have to use it as follows:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int [] pixels = new int [width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
However - I am not sure about a few things:
In getPixels - does it make sense to simply pass the width as the "Stride" argument?
I guess I'd have to evaluate the color information of each pixel and either switch it to black or white (And I'd write this value in a new target byte array which I would ultimately pass to the printer)?
How to best evaluate each pixel color information in order to decide that it should be black or white? (The rendered Bitmap is black pain on a white background)
Does this approach make sense at all? Is there an easier way? It's not enough to just make the bitmap black & white, the main issue is to reduce the color information for each pixel into one bit.
UPDATE
As suggested by Reuben I'll first convert the Bitmap to a monochrome Bitmap. and then I'll iterate over each pixel:
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int[] pixels = new int[width * height];
bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
// Iterate over height
for (int y = 0; y < height; y++) {
int offset = y * height;
// Iterate over width
for (int x = 0; x < width; x++) {
int pixel = bitmap.getPixel(x, y);
}
}
Now Reuben suggested to "read the lowest byte of each 32-bit pixel" - that would relate to my question about how to evaluate the pixel color. My last question in this regard: Do I get the lowest byte by simply doing this:
// Using the pixel from bitmap.getPixel(x,y)
int lowestByte = pixel & 0xff;
You can convert the image to monochrome 32bpp using a ColorMatrix.
Bitmap bmpMonochrome = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmpMonochrome);
ColorMatrix ma = new ColorMatrix();
ma.setSaturation(0);
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(ma));
canvas.drawBitmap(bmpSrc, 0, 0, paint);
That simplifies the color->monochrome conversion. Now you can just do a getPixels() and read the lowest byte of each 32-bit pixel. If it's <128 it's a 0, otherwise it's a 1.
Well I think its quite late now to reply to this thread but I was also working on this stuff sometimes back and decided to build my own library that will convert any jpg or png image to 1bpp .bmp. Most printers that require 1bpp images will support this image (tested on one of those :)).
Here you can find library as well as a test project that uses it to make a monochrome single channel image. Feel free to change it..:)
https://github.com/acdevs/1bpp-monochrome-android
Enjoy..!! :)
You should convert each pixel into HSV space and use the value to determine if the Pixel on the target image should be black or white:
Bitmap bwBitmap = Bitmap.createBitmap( bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.RGB_565 );
float[] hsv = new float[ 3 ];
for( int col = 0; col < bitmap.getWidth(); col++ ) {
for( int row = 0; row < bitmap.getHeight(); row++ ) {
Color.colorToHSV( bitmap.getPixel( col, row ), hsv );
if( hsv[ 2 ] > 0.5f ) {
bwBitmap.setPixel( col, row, 0xffffffff );
} else {
bwBitmap.setPixel( col, row, 0xff000000 );
}
}
}
return bwBitmap;
Converting to monochrome with exact the same size as the original bitmap is not enough to print.
Printers can only print each "pixel" (dot) as monochrome because each spot of ink has only 1 color, so they must use much more dots than enough and adjust their size, density... to emulate the grayscale-like feel. This technique is called halftoning. You can see that printers often have resolution at least 600dpi, normally 1200-4800dpi, while display screen often tops at 200-300ppi.
So your monochrome bitmap should be at least 3 times the original resolution in each side.

OpenGL screenshot Android

I have an application that uses GLSurfaceView to do some 3-D goodness in Android. I'd like the user to be able to take a screenshot. I think this snippet of code should be storing the pixel colors and storing them inside a bitmap. However, does anyone know how to access the gl10 element that the screen is using, so I can feed it into this function?
public static Bitmap savePixelsOnScreen(int x, int y, int width, int height, GL10 gl){
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
//gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
return bitmap;
I had tried to do this from within the Activity that calls the GLSurfaceView:
EGL10 egl = (EGL10)EGLContext.getEGL();
GL10 gl = (GL10)egl.eglGetCurrentContext().getGL();
But every element of the int buffer is zero so I think this is not correct.
put the code under draw(GL10 gl) method of your CClayer/CCNode class and also maintain boolean variable to draw it only once. Draw method will be called 60+ times per second.

How to get access to main screen/OpenGL buffer in Android?

I'd like to get access to the main (OpenGL) screen in Android to implement some overlay 3D effects.
Is it possible to do so?
If yes, how can I do it?
When amending this context, my application should be a service, right?
You cannot get access to the framebuffer, for obvious security reasons.
What you will probably want to do is research the glReadPixels() function. I ran a test where I had the screen split with a glsurfaceview and image view and wanted to see if I could grab the pixels from the glview and create a Bitmap and then apply that to the ImageView. After some research, I found using glReadPixels() works, but you have to tranform the pixels before using them for an android bitmap. This is the method I ended up using. I'm confident that I found it exactly this way on another forum.
public Bitmap SaveGLPixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*h];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, y, w, h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0; i<h; i++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-i-1)*w+j]=pix1;
}
}
Bitmap.Config bconfig = Bitmap.Config.RGB_565;
Bitmap sb=Bitmap.createBitmap(bt, w, h, bconfig);
return sb;
}

Android OpenGL Screenshot

I've searched a lot about taking screenshot of my OpenGL object on Android and come up with this solution. It worked great but in my case I have camera view and opengl view(with transparent background) on top of camera view. So what I want to do is to get opengl screenshot with transparent background instead of black.
As I said I have tried link above and it worked but I'm stuck with black background. It's little bit complicated to figure out how to get rid of the black background in this particular case.
Hope somebody could help me and asap if it's possible(also I think the solution is easy, I'm just missing something simple).
Thank you.
I used following method and worked like a champ.
public static Bitmap SavePixels(int x, int y, int w, int h, GL10 gl)
{
int b[]=new int[w*(y+h)];
int bt[]=new int[w*h];
IntBuffer ib=IntBuffer.wrap(b);
ib.position(0);
gl.glReadPixels(x, 0, w, y+h, GL10.GL_RGBA, GL10.GL_UNSIGNED_BYTE, ib);
for(int i=0, k=0; i<h; i++, k++)
{//remember, that OpenGL bitmap is incompatible with Android bitmap
//and so, some correction need.
for(int j=0; j<w; j++)
{
int pix=b[i*w+j];
int pb=(pix>>16)&0xff;
int pr=(pix<<16)&0x00ff0000;
int pix1=(pix&0xff00ff00) | pr | pb;
bt[(h-k-1)*w+j]=pix1;
}
}
Bitmap sb=Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
return sb;
}
You just need to call
YourClass.SavePixels(0,0,width,height,gl);
I hope this will work for you...
Thanks,
Midhun
The solution you mentioned is using a Bitmap.Config.RGB_565 which doesn't support alpha channels.
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
Instead you should use Bitmap.Config.ARGB_8888 or Bitmap.Config.ARGB_4444.

Categories

Resources