I am using Android Camera2 API to acquire frames from the camera. I can get an ImageReader that reads Image objects with the acquireLatestImage() method.
Since I need to process the acquired frames, I have to convert each Image object into a Mat object. I suppose this is a quite common problem, so I expected to find a convenient OpenCV method to do that. However I didn't find any.
Do you have an idea on how to get Mat objects from the camera frames with Android Camera2?
Thanks
This depends on what ImageFormat you set for your ImageReader class. This code below assumes that it's using the JPEG format.
Image image = reader.acquireLatestImage();
Mat buf = new Mat(image.getHeight(), image.getWidth(), CvType.CV_8UC1);
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.remaining()];
buffer.get(bytes);
buf.put(0, 0, bytes);
// Do note that Highgui has been replaced by Imgcodecs for OpenCV 3.0 and above
Mat mat = Highgui.imdecode(buf, IMREAD_COLOR);
image.close();
Do note that imdecode is quite slow. I'm not entirely sure but I think YUV_420_888 would be faster to convert to a Mat object, but I haven't figured out how to do it myself. I saw this post attempt the YUV conversion to a Mat,
Related
I'm working with ImageIO and JAI and want to read a byte array into a BufferedImage. The byte[] contains data for a JP2000 encoded image, and it's fairly large, around 100MB. I'm currently doing something like:
byte[] imageDataBytes = ...
InputStream imageStream = new ByteArrayInputStream(imageDataBytes);
BufferedImage imageData = ImageIO.read(imageStream);
It seems that ImageIO is creating a new BufferedImage each time read() is called.
Question:
Is there a way to tell ImageIO to read and decode the image byte data into a pre-allocated mutable BufferedImage?
I did some searching through the Javadocs and found that the BufferedImage stores its data in a Raster object, which stores its data in a DataBuffer object. So I'm aware any solution that exists will technically not be writing to the BufferedImage, but instead will be directly writing to the DataBuffer.
It may help to know that all images are the same size: roughly 10,000 x 10,000, so there shouldn't be any problems with the read image not aligning with the buffered image. Ultimately, I would like to have an object pool of buffered images, or rasters, or data buffers, and borrow from the pool every time I read using ImageIO. Something like this pseudocode:
InputStream imageStream = new ByteArrayInputStream(imageDataBytes);
WritableRaster raster = ObjectPool.getAvailableRaster();
ImageIO.readToRaster(imageStream, raster);
BufferedImage imageData = new BufferedImage(raster);
I'm sure there's a simple solution out there. Any help would be appreciated!
Yes, you can set the destination image of an ImageReadParam object. However, there is a caveat: the BufferedImage must have a ColorModel and SampleModel that match the image being loaded.
I’m not sure about JPEG2000 images, but regular JPEGs are usually RGB images, so an image of TYPE_INT_RGB should suffice:
BufferedImage image = new BufferedImage(10000, 10000,
BufferedImage.TYPE_INT_RGB);
while (bytesAvailable) {
byte[] imageDataBytes = getImageBytes();
try (InputStream in = new ByteArrayInputStream(imageDataBytes);
ImageInputStream stream = ImageIO.createImageInputStream(in)) {
ImageReader reader = ImageIO.getImageReaders(stream).next();
reader.setInput(stream);
ImageReadParam param = reader.getDefaultReadParam();
param.setDestination(image);
reader.read(0, param);
}
}
For those who find themselves in this situation, the answer by VGR works well. I like to add that specifically for JPEG-2000 images that contain metadata, use
reader.setInput(stream, true, true);
instead of
reader.setInput(stream);
This avoids a NullPointer exception. you can read more about it here:
https://issues.apache.org/jira/browse/PDFBOX-2103
Image data stored in hbase and retrieved as byte array using below code.
byte[] image_data = result.getValue(Bytes.toBytes("Data"), Bytes.toBytes("data"));
I need to convert into Opencv Mat for processing. While using below code I got invalid image.
Mat mat = new Mat();
mat.put(0, 0, image_data);
Tried How to convert an byte array to Opencv Mat?
Use image decode in Opencv for creating Mat from byte array
Mat mat = Highgui.imdecode(new MatOfByte(image_data), Highgui.CV_LOAD_IMAGE_UNCHANGED);
In Java:
I am reading an image using JAI:
BufferedImage image = javax.imageio.ImageIO.read(new File("path to JPG image"));
Then, I look at the rgb value of the pixel (0,2):
System.out.println("pixel[0][2]="+(new Color(image.getRGB(2, 0))));
In C++ OpenCV:
Mat image = imread("path to the same JPG image");
image.convertTo(image, CV_32S);
cout <<" r value of pixel[0][2] "<< image.at<Vec3i>(0, 2)[2] << "\n";
The values are different: r value in Java is 156 and in C++ is 155. Why?
I think this has to do with the format of the image, not with Java or OpenCV. JPEG is lossy compression, so when decoding the data you may get different outputs for the same image. That will depend on the decoder you are using to read the image information. The issue you are experimenting is similar to the one described in the below question.
Reading jpg file in OpenCV vs C# Bitmap
I am receiving large size CCITT Group 4 compressed TIFF files that need to be written elsewhere as uncompressed TIFF files. I am using the jai_imageio TIFF reader and writer to do that and it works well as long as the product _width * height_ of the image fits in an integer.
Here is the code I am using:
TIFFImageReaderSpi readerSpi= new TIFFImageReaderSpi();
ImageReader imageReader = readerSpi.createReaderInstance();
byte[] data = blobManager.getObjectForIdAndVersion(id, version);
ImageInputStream imageInputStream = ImageIO.createImageInputStream(data);
imageReader.setInput(imageInputStream);
TIFFImageWriterSpi writerSpi = new TIFFImageWriterSpi();
ImageWriter imageWriter = writerSpi.createWriterInstance();
ImageWriteParam imageWriteParam = imageWriter.getDefaultWriteParam();
imageWriteParam.setCompressionMode(ImageWriteParam.MODE_DISABLED);
//bufferFile is created in the constructor
ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(bufferFile);
imageWriter.setOutput(imageOutputStream);
//Now read the bitmap
BufferedImage bufferedImage = imageReader.read(0);
IIOImage iIOImage = new IIOImage(bufferedImage, null, null);
//and write it
imageWriter.write(null, iIOImage, imageWriteParam);
Unfortunately, the files that I receive are often very large and the BufferedImage cannot be created.
I have been trying to find a way to stream from the ImageReader directly to the ImageWriter but I cannot find out how to do that.
Anybody with a suggestion?
I've had the some issues, and the end result might surprise you :
I ended up calling IrfanView with some command-line options using the Runtime.exec() method. That way, I am not worried about compression or size, it just works and outputs the correct files in the correct folder for me.
If you are on Linux, you can use ImageMagik or something similar.
You can use TIFF tiles to segment a TIFF into smaller portions ("tiles"). If you control the code creating the big images, JAI allows you to retrieve image content tile-by-tile.
Here is an example on how to create tiled image with JAI:
ColorModel cm = source.createColorModel();
// SampleModel with the tilesize
SampleModel sm = cm.createCompatibleSampleModel(tileWidth, tileHeight);
TiledImage image = new TiledImage(0, 0, imageWidth, imageHeight, 0, 0, sm, cm);
TIFFEncodeParam tep = new TIFFEncodeParam();
tep.setTileSize(tileWidth, tileHeight); // Set tile size to avoid OOM
tep.setWriteTiled(true);
JAI.create("filestore", image, filepath, "TIFF", tep);
If you can't control the TIFF production, my knowledge of JAI is too limited to be of much help.
Give your Java VM more memory.
If that doesn't work, look at the source code of the TIFF plugin in the JAI source code. You might be able to write your own processor which just decompresses the data structures using a streaming approach (so you'll never have to keep the whole image in memory at any time).
If that also doesn't work, look at JNA which allows you to call code from a DLL from Java (no C code required; everything is done from pure Java, unlike with Sun's JNI API).
Have a requirement for any given image need to generate 32 bit depth bmp image in Java.
I googled and looked at Java Advance Image processing and Java2D, but couldnt find exact solution. Appreciate if any responses for the same.
Regards,
Rakesh.
May be you should use ImageIO.write(..., "bmp", ...)? I say about ImageIO because you made an accent on BMP. So, you need a BMP bitmap data with BMP header.
Create BufferedImage (http://download.oracle.com/javase/1.4.2/docs/api/java/awt/image/BufferedImage.html) with required parameter and serialize it to BMP.
...
Robot robot = new Robot();
Rectangle screenRectangle = new Rectangle(Toolkit.getDefaultToolkit().getScreenSize());
BufferedImage image = robot.createScreenCapture(screenRectangle);
ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(image, "bmp", out);
...