Converting an Image to RGBA Mat - java

I am making an app for exposure fusion but I have a small hiccup on my ZTE test device. On the Pixel emulator, I am able to take an Image from the ImageReader and convert it to a Mat and then back to a Bitmap to be displayed in an ImageView. This is the code:
int width = image.getWidth();
int height = image.getHeight();
Image.Plane yPlane = image.getPlanes()[0];
Image.Plane uPlane = image.getPlanes()[1];
Image.Plane vPlane = image.getPlanes()[2];
ByteBuffer yBuffer = yPlane.getBuffer();
ByteBuffer uBuffer = uPlane.getBuffer();
ByteBuffer vBuffer = vPlane.getBuffer();
int ySize = yBuffer.remaining();
int uSize = uBuffer.remaining();
int vSize = vBuffer.remaining();
int uvPixelStride = uPlane.getPixelStride();
Mat yuvMat = new Mat(height + (height / 2), width, CvType.CV_8UC1);
byte[] data = new byte[ySize + uSize + vSize];
yBuffer.get(data, 0, ySize);
uBuffer.get(data, ySize, uSize);
vBuffer.get(data, ySize + uSize, vSize);
if (uvPixelStride == 1) {
yuvMat.put(0, 0, data);
Mat rgb = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
Imgproc.cvtColor(yuvMat, rgb, Imgproc.COLOR_YUV420p2RGBA);
return rgb;
Now, for the ZTE, the pixel stride for the U and V planes are 2 but I can't seem to get it to display correctly.
This is the code I'm using right now:
Mat yuv = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC1);
yuv.put(0, 0, data);
Mat rgb = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC4);
Imgproc.cvtColor(yuv, rgb, Imgproc.COLOR_YUV2RGBA_NV21);
return rgb;
Any help would be greatly appreciated.

Related

How to add icon or watermark image to immediately after taking screenshot in android with support multiple screen sizes

Please re-read my question before a vote, I want to add an icon or png image to a screenshot image immediately after taking
I don't know is it a good approach or not, but I tried this
private static Bitmap addWaterMark(Bitmap src, Context context, String waterMarkImage) {
int w = src.getWidth();
int h = src.getHeight();
Bitmap result = Bitmap.createBitmap(w, h, src.getConfig());
Canvas canvas = new Canvas(result);
canvas.drawBitmap(src, 0, 0, null);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
int width = metrics.widthPixels;
int height = metrics.heightPixels;
Log.d(TAG, "Width X Height " + width + " X " + height);
Point point = new Point();
display.getSize(point);
int maxX = point.x;
int maxY = point.y;
point.set(maxX, maxY);
int maxWidth = (70 * width) / 100;
int maxHeight = (80 * height) / 100;
Log.d(TAG, "maxWidth X maxHeight " + maxWidth + " X " + maxHeight);
Bitmap waterMark = null;
if (waterMarkImage != null) {
byte[] decodedByte = Base64.decode(waterMarkImage, 0);
waterMark = BitmapFactory.decodeByteArray(decodedByte, 0, decodedByte.length);
waterMark = Bitmap.createScaledBitmap(waterMark, 250, 250, true);
} else {
waterMark = BitmapFactory.decodeResource(context.getResources(), R.drawable.sharelogo1);
}
canvas.drawBitmap(waterMark, maxWidth, maxHeight, null);
return result;
}
and it's working fine but watermark image size and position is not working as I want (not supporting all screen sizes or resolutions)
In your code snippet change
waterMark = Bitmap.createScaledBitmap(waterMark, 250, 250, true);
by
waterMark = Bitmap.createScaledBitmap(waterMark, getpixels(250), getpixels(250), true);
And add below method in to convert dp to pixel
private float getpixels(float dipValue) {
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dipValue, Resources.getSystem().getDisplayMetrics());
}

Converting Images to Mat and back

I'm trying to convert my image into mat that is 8 bits and 3 channels and later on back into a image in OpenCV. But my code doesn't seem to be working.
Does anyone know why this isn't working?
Mat toMat(PImage image) {
int w = image.width;
int h = image.height;
Mat mat = new Mat(h, w, CvType.CV_8UC3);
byte[] data8 = new byte[w*h*4];
int[] data32 = new int[w*h];
arrayCopy(image.pixels, data32);
ByteBuffer bBuf = ByteBuffer.allocate(w*h*4);
IntBuffer iBuf = bBuf.asIntBuffer();
iBuf.put(data32);
bBuf.get(data8);
mat.put(0, 0, data8);
return mat;
}
PImage toPImage(Mat mat) {
int w = mat.width();
int h = mat.height();
PImage image = createImage(h, w, RGB);
byte[] data8 = new byte[w*h*4];
int[] data32 = new int[w*h];
mat.get(0, 0, data8);
ByteBuffer.wrap(data8).asIntBuffer().get(data32);
arrayCopy(data32, image.pixels);
return image;
}

Convert byte array of data type TYPE_4BYTE_ABGR to BufferedImage

I have a byte array with type TYPE_4BYTE_ABGR, and I know its width and height, I want to change it to BufferedImage, any ideas?
The fastest way to create a BufferedImage from a byte array in TYPE_4BYTE_ABGR form, is to wrap the array in a DataBufferByte and create an interleaved WritableRaster from that. This will make sure there are no additional byte array allocations. Then create the BufferedImage from the raster, and a matching color model:
public static void main(String[] args) {
int width = 300;
int height = 200;
int samplesPerPixel = 4; // This is the *4BYTE* in TYPE_4BYTE_ABGR
int[] bandOffsets = {3, 2, 1, 0}; // This is the order (ABGR) part in TYPE_4BYTE_ABGR
byte[] abgrPixelData = new byte[width * height * samplesPerPixel];
DataBuffer buffer = new DataBufferByte(abgrPixelData, abgrPixelData.length);
WritableRaster raster = Raster.createInterleavedRaster(buffer, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
ColorModel colorModel = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
BufferedImage image = new BufferedImage(colorModel, raster, colorModel.isAlphaPremultiplied(), null);
System.out.println("image: " + image); // Should print: image: BufferedImage#<hash>: type = 6 ...
}
Note however, that this image will be "unmanaged" (some HW accelerations will be disabled), because you have direct access to the pixel array.
To avoid this, create the WritableRaster without the pixels, and copy the pixels into it. This will use twice as much memory, but will keep the image "managed" and thus possible better display performance:
// Skip creating the data buffer
WritableRaster raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, samplesPerPixel * width, samplesPerPixel, bandOffsets, null);
raster.setDataElements(0, 0, width, height, abgrPixelData);
// ...rest of code as above.
You could even do this (which might be more familiar):
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);
WritableRaster raster = image.getRaster();
raster.setDataElements(0, 0, width, height, abgrPixelData);
Might not be very efficient, but a BufferedImage can be converted to another type this way:
public static BufferedImage convertToType(BufferedImage image, int type) {
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), type);
Graphics2D graphics = newImage.createGraphics();
graphics.drawImage(image, 0, 0, null);
graphics.dispose();
return newImage;
}
About the method you want to be implemented, you would have to know the width or height of the image to convert a byte[] to a BufferedImage.
Edit:
One way is converting the byte[] to int[] (data type TYPE_INT_ARGB) and using setRGB:
int[] dst = new int[width * height];
for (int i = 0, j = 0; i < dst.length; i++) {
int a = src[j++] & 0xff;
int b = src[j++] & 0xff;
int g = src[j++] & 0xff;
int r = src[j++] & 0xff;
dst[i] = (a << 24) | (r << 16) | (g << 8) | b;
}
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
image.setRGB(0, 0, width, height, dst, 0, width);

canvas.drawBitmap bad Location and size (not placing image correctly)

Hi everyone and beforehand thanks, I hope are well write because I am doing a simple application that should unite more than two bitmaps in only one, the problem is in which position bitmaps and size Side wrong, and the truth will not find the back for logic given to me that 's fine, in fact it is a Tengo Que code already in c # and PASE java obviously is different sin but have the same principle .
I wonder if you have the way to make the position and size of these images out as this saying in the code,
Sorry for my bad English
CODIGO JAVA
Paint mPaint;
Bitmap image1=BitmapUtils.decodeBase64(Lie.GeFondo().GetImagen());
Bitmap image2=BitmapUtils.decodeBase64(Utilidades.getImagenTomadabase64());
Bitmap image3=BitmapUtils.decodeBase64(Lie.GetBanner().GetImagen());
Bitmap result = Bitmap.createBitmap(image1.getWidth(), image1.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);
Rect srcRect = new Rect(0, 0, image1.getWidth(), image1.getHeight());
Rect dstRect = new Rect(srcRect);
Rect srcRect1 = new Rect( Foto.GetPosicionDeItems().Getx(),Foto.GetPosicionDeItems().Gety(),Foto.GetTamano().GetWidth(), Foto.GetTamano().GeHeight());
Rect srcRect3 = new Rect( Lie.GetBanner().GetPosicionDeItems().Getx(), Lie.GetBanner().GetPosicionDeItems().Gety() ,Lie.GetBanner().GetTamano().GetWidth(), Lie.GetBanner().GetTamano().GeHeight());
Rect srcRect2 = new Rect(0,0,image2.getWidth(), image2.getHeight());
Rect srcRect4 = new Rect(0,0,image3.getWidth(), image3.getHeight());
dstRect.offset(0, 0);
canvas.drawBitmap(image1, srcRect, dstRect, null);
dstRect.offset(image1.getWidth(), 0);
srcRect1.offset(0, 0);
canvas.drawBitmap(image2,srcRect2 ,srcRect1 , null);
srcRect1.offset(image2.getWidth(), 0);
srcRect3.offset(0, 0);
canvas.drawBitmap(image3,srcRect4 ,srcRect3 , null);
srcRect3.offset(image3.getWidth(), 0);
myImage = (ImageView) findViewById(R.id.imageView);
myImage.setImageBitmap(result);
in Java
see java picture http://i58.tinypic.com/1zywm5u.jpg
C# Code
Ignore the foreach.
System.Drawing.Bitmap Bac = (System.Drawing.Bitmap)Lienzo.Fondo.Imagen;
System.Drawing.Graphics r = System.Drawing.Graphics.FromImage(Bac);
if (Lienzo.Fotos != null)
{
if (Lienzo.Fotos.Count > 0)
{
int i = 0;
foreach (RADMLIB.Items item in Lienzo.Fotos)
{
System.Drawing.Bitmap img = (System.Drawing.Bitmap)Lista[i];
r.DrawImage(img, item.PosicionDeItems.X, item.PosicionDeItems.Y, item.Tamano.Width, item.Tamano.Height);
i++;
}
}
}
if (Lienzo.Banner != null)
{
r.DrawImage((System.Drawing.Bitmap)Lienzo.Banner.Imagen, Lienzo.Banner.PosicionDeItems.X, Lienzo.Banner.PosicionDeItems.Y, Lienzo.Banner.Tamano.Width, Lienzo.Banner.Tamano.Height);
}
return Bac;
see c# picture http://i61.tinypic.com/s61wlh.jpg
I found the solution
using Matrix for set location and scale x,y
Bitmap image1=BitmapUtils.decodeBase64(Lie.GeFondo().GetImagen());
Bitmap image2=BitmapUtils.getResizedBitmap(BitmapUtils.decodeBase64(Utilidades.getImagenTomadabase64()),Foto.GetTamano().GetWidth(),Foto.GetTamano().GeHeight());
Bitmap image3=BitmapUtils.getResizedBitmap(BitmapUtils.decodeBase64(Lie.GetBanner().GetImagen()),Lie.GetBanner().GetTamano().GetWidth(),Lie.GetBanner().GetTamano().GeHeight());
Bitmap result = Bitmap.createBitmap(image1.getWidth(), image1.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(result);//Create the canvas to your image
Rect srcRect = new Rect(0, 0, image1.getWidth(), image1.getHeight());
Rect dstRect = new Rect(srcRect);
Matrix matrix = new Matrix ();
Matrix matrix2 = new Matrix ();
matrix.postTranslate( Foto.GetPosicionDeItems().Getx(),Foto.GetPosicionDeItems().Gety());
matrix2.postTranslate( Lie.GetBanner().GetPosicionDeItems().Getx(),Lie.GetBanner().GetPosicionDeItems().Gety());
canvas.drawBitmap(image1, srcRect, dstRect, null);
dstRect.offset(image1.getWidth(), 0);
canvas.drawBitmap(image2,matrix , null);
canvas.drawBitmap(image3,matrix2 , null);
getResizedBitmap Method
public static Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth) {
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
see the image
https://lh4.ggpht.com/LXW8kVc3U8qQUHnORI-3H4H-A2hjq92y_oEDsKIs-iBDkVBFTgjGP03xFReCeuyLlg=h900-rw

Create a WritableRaster based on int array

I need to take an int array and turn it into BufferImage. I really don't have any background on this subject and I learn it all from the internet so here's what I'm trying to do:
Create an array from BufferedImage(done), turn this array into IntBuffer(done) - (Later i'll need to do some opertions on the image through the IntBuffer), put the changed values from the IntBuffer in new array(done), and turn this array into WritableRaster.
(If something isn't right in my understading of the process please tell me)
Here's the line where I deal with the WritableRaster:
WritableRaster newRaster= newRaster.setPixels(0, 0, width, height, matrix);
Eclipse marks this as a mistake and says ''Type mismatch:Cannot convert from void to WritableRaster"
Please help! I'm a bit lost.
Also sorry for bad english.
EDIT:
The matrix:
int height=img.getHeight();
int width=img.getWidth();
int[]matrix=new int[width*height];
The part of the code where I try to insert values to the Raster:
BufferedImage finalImg = new BufferedImage(width,height, BufferedImage.TYPE_INT_RGB);
WritableRaster newRaster= (WritableRaster)finalImg.getData();
newRaster.setPixels(0, 0, width, height, matrix);
The error message:
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10769
at java.awt.image.SinglePixelPackedSampleModel.setPixels(Unknown Source)
at java.awt.image.WritableRaster.setPixels(Unknown Source)
You can create a WritableRaster and/or BufferedImage from an int array like this:
int w = 300;
int h = 200;
int[] matrix = new int[w * h];
// ...manipulate the matrix...
DataBufferInt buffer = new DataBufferInt(matrix, matrix.length);
int[] bandMasks = {0xFF0000, 0xFF00, 0xFF, 0xFF000000}; // ARGB (yes, ARGB, as the masks are R, G, B, A always) order
WritableRaster raster = Raster.createPackedRaster(buffer, w, h, w, bandMasks, null);
System.out.println("raster: " + raster);
ColorModel cm = ColorModel.getRGBdefault();
BufferedImage image = new BufferedImage(cm, raster, cm.isAlphaPremultiplied(), null);
System.err.println("image: " + image);
ColorModel cm = ColorModel.getRGBdefault();
int w = 300;
int h = 200;
WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
DataBufferInt buffer = (DataBufferInt) raster.getDataBuffer();
int[] bufferData = buffer.getData();
int[] array = new int[2400];
Random random = new Random();
for (int i = 0; i < 2400; i++) {
array[i] = random.nextInt(2);
}
System.arraycopy(array, 0, bufferData, 0, (array.length < bufferData.length ? array.length : bufferData.length));
BufferedImage image = new BufferedImage(cm, raster, false, null);
FileOutputStream fos = new FileOutputStream("D:\\abc\\OCR\\" + "LearningRaster" + ".png");
ImageIO.write(image, "PNG", fos);
fos.close();
setPixels returns void:
public static void setPixels(BufferedImage img,
int x, int y, int w, int h, int[] pixels)
so you need to create Raster and than set pixels to it:
WritableRaster newRaster= WritableRaster.createWritableRaster(…);
newRaster.setPixels(0, 0, width, height, matrix);
You need to put 4 int per pixel (it depends on color model, 4 for ARGB). So, matrix size must be
int[] matrix = new int[width * height * 4]
See more about WritableRaster here —
Oracle: WritableRaster
Code examples

Categories