How to convert byte array to Mat object in Java - java

I want to convert byte array to Mat object, but it throws
java.lang.UnsupportedOperationException: Provided data element number (60181) should be multiple of the Mat channels count (3)
at org.opencv.core.Mat.put(Mat.java:992)
It is my code:
byte[] bytes = FileUtils.readFileToByteArray(new File("aaa.jpg"));
Mat mat = new Mat(576, 720, CvType.CV_8UC3);
//Imgcodecs.imencode(".jpg", mat, new MatOfByte(bytes));
mat.put(0, 0, bytes);
I tried many ways and also googled a lot, but did not find any solution.
Note: I know Imgcodecs.imread("aaa.jpg"); and
BufferedImage img = ImageIO.read(new ByteArrayInputStream(byteArray));
Mat mat = new Mat(img.getHeight(), img.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, ((DataBufferByte) img.getRaster().getDataBuffer()).getData());
But I want to directly convert byte array to Mat without any extra process to speed up the process time.
Thanks in advance!

I solved the problem like this:
byte[] bytes = FileUtils.readFileToByteArray(new File("aaa.jpg"));
Mat mat = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
Now it works well and much faster than *bytes->BufferedImage->Mat*

Try it please. I'm using this.
BufferedImage b = ImageIO.read(url);
BufferedImage b1 = new BufferedImage(b.getWidth(), b.getHeight(), BufferedImage.TYPE_3BYTE_BGR);
b1=b;
byte [] pixels = ((DataBufferByte)b1.getRaster().getDataBuffer()).getData();
Mat myPic = new Mat(b1.getHeight(),b1.getWidth(),CvType.CV_8UC3);
myPic.put(0, 0, pixels);
Or
OpenCV imread()
Mat myPic = Highgui.imread(url);

// OpenCV 3.x
Mat mat = Imgcodecs.imdecode(new MatOfByte(bytes), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
// OpenCV 2.x
Mat mat = Highgui.imdecode(new MatOfByte(bytes), Highgui.CV_LOAD_IMAGE_UNCHANGED);

I've tried this kind of solution.
static Mat ba2Mat(byte[] ba)throws Exception{
// String base64String=Base64.getEncoder().encodeToString(ba);
// byte[] bytearray = Base64.getDecoder().decode(base64String);
Mat mat = Imgcodecs.imdecode(new MatOfByte(ba),
Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);
return mat;
}

Related

How to convert int[][] to Mat in opencv Java?

I got a function where i process different arrays[][] and I need to use a Mat because I'm working with images, so I need the pixels of that image.
System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
Mat img = Imgcodecs.imread(imagelocation);
I need a way to get the pixels values of that Mat.
But I was wondering if I can convert an array[][] into a Mat.
I hope you understand and help me.
To get the pixel values of the Mat you can use: reference
Mat m;
int bufferSize = m.channels()*m.cols()*m.rows();
byte [] b = new byte[bufferSize];
m.get(0,0,b); // get all the pixels
double pixelValue = m.get(0, 0) // get pixel at row 0, column 0
To convert an array to Mat:
byte[] raw_data = ...;
Mat mat = new Mat();
mat.put(0, 0, raw_data);

JavaCV Create Mat from Resource (InputStream)

I use JavaCV (not OpenCV). My goal is to obtain a Mat object from an image that is stored as a Resource. Then I'm going to pass this Mat into opencv_imgproc.matchTemplate method. I've managed to write this bad code:
InputStream in = getClass().getResourceAsStream("Lenna32.png");
BufferedImage image = ImageIO.read(in);
Frame f = new Java2DFrameConverter().getFrame(image);
Mat mat = new OpenCVFrameConverter.ToMat().convert(f);
This works in some cases. The problems are:
For png images that has transparency channel (that is 32BPP), it shifts channels, so that R=00 G=33 B=66 A=FF turns to R=33 G=66 B=FF
On my target environment, I can't use ImageIO
There are too many object conversions InputStream -> BufferedImage -> Frame -> Mat. I feel like there should be a simple and effective way to do this.
What is the best way to create Mat from a Resource?
I resolved this by reading bytes from InputStream and passing them into imdecode function:
InputStream is = context.getResourceAsStream("Lenna32.png");
int nRead;
byte[] data = new byte[16 * 1024];
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
while ((nRead = is.read(data, 0, data.length)) != -1) {
buffer.write(data, 0, nRead);
}
byte[] bytes = buffer.toByteArray();
Mat mat = imdecode(new Mat(bytes), CV_LOAD_IMAGE_UNCHANGED);

java.lang.UnsupportedOperationException: Mat data type is not compatible: 4

i have written my own algorithms to determine the edges and then find the corner points.
But then am having trouble in prespective transforming the image.I have written some code to achieve the result but am getting the above specified error.
Could anyone help please me out.
Thanks in advance!
Mat mat = new Mat(w, h, CvType.CV_32S);
MatOfPoint2f finalc = new MatOfPoint2f();
MatOfPoint2f ma = new MatOfPoint2f();
mat.put(0, 0, array);
Mat quad = new Mat(w,h,CvType.CV_32S);
quad.put(0,0,w,0,w,h,0,w);
ma.put((int)a[0][1],(int)a[0][0],(int)a[1][1],(int)a[1][0],(int)a[2][1],(int)a[2][0],(int)a[3][1],(int)a[3][0]);
Imgproc.approxPolyDP(ma,finalc,2.0,true);
Mat transmtx = Imgproc.getPerspectiveTransform(finalc, quad);
Imgproc.warpPerspective(mat, quad, transmtx, quad.size());
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", quad, matOfByte);
byte[] byteArray = matOfByte.toArray();
//InputStream in = new ByteArrayInputStream(byteArray);
//BufferedImage bufferedImage = ImageIO.read(in);
File f = new File("retrieve1.jpg");
BufferedImage img1 = new BufferedImage(w, h, 12);
WritableRaster raster = (WritableRaster)img1.getData();
raster.setDataElements(0,0,w,h,byteArray);
img1.setData(raster);
try
{
ImageIO.write(img1,"jpg",f);
}
catch(Exception e)
{}
}
all i am basically trying to do is port a part of this (C++) code to java.
https://github.com/bsdnoobz/opencv-code/blob/master/quad-segmentation.cpp
Solution i created:
Mat mat = new Mat(h,w, CvType.CV_8U);
mat.put(0, 0, array);
//Imshow is = new Imshow("try");for verification
MatOfPoint2f quad = new MatOfPoint2f(p);//array of corner points
MatOfPoint2f rect = new MatOfPoint2f(farray);//final array of corner points into which mat should be warped into
Mat transmtx = Imgproc.getPerspectiveTransform(quad,rect);
Mat output = new Mat(w,h,CvType.CV_8U);
Imgproc.warpPerspective(mat, output, transmtx, new Size(w,h),Imgproc.INTER_CUBIC);
//is.showImage(output);
MatOfByte matOfByte = new MatOfByte();
Highgui.imencode(".jpg", output, matOfByte);
byte[] byteArray = matOfByte.toArray();
File f = new File("retrieve1.jpg");
BufferedImage img1 =null;
InputStream in = new ByteArrayInputStream(byteArray);
img1 = ImageIO.read(in);
WritableRaster raster = (WritableRaster)img1.getData();
raster.setDataElements(0,0,byteArray);
img1.setData(raster);
Since i didn't need to verify corner points hence i removed approxpolydp and put everything in as points instead of directly feeding them into the matofpoint2fs. And "array" is the byte equivalent of the image in use.

Convert BufferedImage TYPE_INT_RGB to OpenCV Mat Object

I am storing BufferedImages inside a MySQL database and retrieve them to a java application.
The BufferedImages are of type TYPE_INT_RGB.
How can i convert that image to a OpenCV Mat object?
I do always get a
java.lang.UnsupportedOperationException: Mat data type is not compatible:
Exception.
Can somebody help?
Got it on my own.
int[] data = ((DataBufferInt)image.getRaster().getDataBuffer()).getData();
ByteBuffer byteBuffer = ByteBuffer.allocate(data.length * 4);
IntBuffer intBuffer = byteBuffer.asIntBuffer();
intBuffer.put(data);
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, byteBuffer.array());
return mat;
image is the BufferedImage, you want to convert to a Mat-Object.
A much more simplified version of tellob's orignal anwser.
public static Mat mat2(BufferedImage image)
{
byte[] data = ((DataBufferByte)image.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, data);
return mat;
}

Bitmap to Mat gives wrong colors back

So I make a bitmap from a blob with the next code:
byte[] blob = contact.getMP();
ByteArrayInputStream inputStream = new ByteArrayInputStream(blob);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
Bitmap scalen = Bitmap.createScaledBitmap(bitmap, 320, 240, false);
and it gives back the next output, which is good
Then I do the following to make the bitmap into a Mat, but then my colors just change...
//Mat ImageMat = new Mat();
Mat ImageMat = new Mat(320, 240, CvType.CV_32F);
Utils.bitmapToMat(scalen, ImageMat);
I have no idea why, nor another way to make the bitmap into a Mat. What is wrong?
The format of color channels in Android Bitmap are RGB
But in opencv Mat, the channels are BGR by default.
So when you do Utils.bitmapToMat(), [B,G,R] values are stored in [R,G,B] channels. The red and blue channels are interchanged.
One possible solution is to apply cvtcolor on the opencv Mat you got as below:
Imgproc.cvtColor(ImageMat, ImageMat, Imgproc.COLOR_BGR2RGB);
It worked for me.

Categories

Resources