How to convert encoded image string to Mat in OpenCV in JAVA? - opencv

In my work I have to get image matrix from the encoded string of an image.
I am using OpenCV and JAVA.
Can anyone tell me how to do this?
Code:
BufferedImage originalImage;
try {
originalImage = ImageIO.read(new File("D:\\testimg.jpg"));
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ImageIO.write(originalImage, "jpeg", baos);
baos.flush();
imageInByte = baos.toByteArray();
baos.close();
String imageDataString = encodeImage(imageInByte);
} catch (IOException e) {
e.printStackTrace();
} catch (Exception ex){
ex.printStackTrace();
}
Now I have the string of image.
The imread() of opencv takes filepath as input param and create Mat, but I have to create the Mat from this imageDataString .
Thanks,
Surodip

The opencv function used to decode images from its encoded forms is imdecode. See http://docs.opencv.org/modules/highgui/doc/reading_and_writing_images_and_video.html

try this code to convert base64 string to mat object in opencv java
byte[] imgbytes = DatatypeConverter.parseBase64Binary(fileBase64);
Mat image = Imgcodecs.imdecode(new MatOfByte(imgbytes), Imgcodecs.CV_LOAD_IMAGE_UNCHANGED);

you can try this
File image = new File("assets/imageparser/imageA.jpg");
BufferedImage buffImage = ImageIO.read(image);
byte[] data = ((DataBufferByte) buffImage.getRaster().getDataBuffer()).getData();
Mat mat = new Mat(buffImage.getHeight(), buffImage.getWidth(), CvType.CV_8UC3);
mat.put(0, 0, data);

Related

Lossing Quality after Compression using Twelvemonkeys in JAVA and highlighters are removed

I am converting a input file (PDF,TIFF) to Output (TIFF) file by using PDFBox (PDF to BufferedImage) and using twelve monkeys for converting Buffered image to Tiff file by resizing using Imagewriter with IIOImage.
File is converting but losing an quality on the image.And after changed the imagetype BufferedImage.TYPE_BYTE_GRAY to BufferedImage.TYPE_BYTE_BINARY my text highlighters on the file lost.
Below is the code used. How to convert the image without losing quality?
I am converting the image file size 1648*2338 with 200 dpi and i wanted to set photometric interpretation to min_is_white but not able to achieve my problem.
File inputFile = new File(inputImagePath);
BufferedImage inputImage = ImageIO.read(inputFile);
final int imageType = BufferedImage.TYPE_BYTE_BINARY;
// creates output image
BufferedImage outputImage = new BufferedImage(scaledWidth, scaledHeight,imageType);
// scales the input image to the output image
Graphics2D g2d = outputImage.createGraphics();
g2d.drawImage(inputImage, 0, 0, scaledWidth, scaledHeight, null);
g2d.dispose();
// writes to output file
final List<Entry> entries =new ArrayList<Entry>();
entries.add(new TIFFEntry(TIFF.TAG_X_RESOLUTION, new Rational(200)));
entries.add(new TIFFEntry(TIFF.TAG_Y_RESOLUTION, new Rational(200)));
entries.add(new TIFFEntry(TIFF.TAG_PHOTOMETRIC_INTERPRETATION, TIFF.TYPE_SHORT, 0));
final IIOMetadata tiffImageMetadata =new TIFFImageMetadata(entries);
ImageWriter writer = ImageIO.getImageWritersByFormatName("tiff").next();
FileImageOutputStream fio = new FileImageOutputStream(new File(outputImagePath));
ImageWriteParam params = writer.getDefaultWriteParam();
params.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
fio.setByteOrder(ByteOrder.LITTLE_ENDIAN);
IIOMetadata metadata = writer.getDefaultImageMetadata(new ImageTypeSpecifier(outputImage), params);
writer.setOutput(fio);
IIOImage iioimage = new IIOImage(outputImage, null, tiffImageMetadata);
writer.write(null, iioimage, params);
fio.close();
writer.dispose();

How to convert Mat to IplImage in Javacv?

Is any one know how i can convert Mat to IplImage ?
to achieve this i have converted Mat to BufferedImage but again not able to find conversion in BufferedImage to IplImage.
is there any way where i can convert Mat to IplImage?
Thanks
I believe you can convert BufferedImage to IplImage as follows.
public static IplImage toIplImage(BufferedImage src) {
Java2DFrameConverter bimConverter = new Java2DFrameConverter();
OpenCVFrameConverter.ToIplImage iplConverter = new OpenCVFrameConverter.ToIplImage();
Frame frame = bimConverter.convert(src);
IplImage img = iplConverter.convert(frame);
IplImage result = img.clone();
img.release();
return result;
}
I got this from this question. Try this for now. I'll check if direct conversion is possible.
UPDATE:
Please have a look at this api docs. I haven't tested the following. Wrote it just now. Please do try and let me know.
public static IplImage toIplImage(Mat src) {
OpenCVFrameConverter.ToIplImage iplConverter = new OpenCVFrameConverter.ToIplImage();
OpenCVFrameConverter.ToMat matConverter = new OpenCVFrameConverter.ToMat();
Frame frame = matConverter.convert(src);
IplImage img = iplConverter.convert(frame);
IplImage result = img.clone();
img.release();
return result;
}

How to limit image size on BlackBerry before uploading to server

I want to add a limit on uploaded image size (currently images are uploaded to a server).
When anyone gets an image from SDcard or captures image from Camera, I want show message to user that it uploaded max file size - i.e 500kb or can I resize images into smaller sizes. For example 1mb image resize into 400-500kb (like Facebook).
Here is the sample code that I implemented after getting image from SDcard or captured image from Camera.
FileConnection file = (FileConnection)Connector.open(url);
if(file.exists())
{
try{
String fileName = url .substring(url.lastIndexOf('/') + 1);
//String fileName = url ;
Dialog.alert("fileName " + fileName);
InputStream inputStream = file.openInputStream();
ByteArrayOutputStream bos=new ByteArrayOutputStream();
int buffersize=1024;
byte[] buffer=new byte[buffersize];
int length=0;
while((length=inputStream.read(buffer))!=-1)
{
bos.write(buffer,0,length);
}
byte[] imagedata=bos.toByteArray();
Dialog.alert("Url " + Url + " Image Data Byte " + imagedata);
HttpConnection conn = (HttpConnection) Connector.open(Url, Connector.READ_WRITE);
conn.setRequestMethod(HttpConnection.POST);
String boundary = "Some_Unique_Text_Also_Alphanumeric";
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE,
HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA
+ ";boundary=" + boundary);
conn.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH,
String.valueOf(imagedata.length));
conn.setRequestProperty("x-rim-transcode-content", "none");
ByteArrayOutputStream out = new ByteArrayOutputStream();
OutputStream finalOut = conn.openOutputStream();
String newLine = "\r\n";
out.write(newLine.getBytes());
out.write("--".getBytes());
out.write(boundary.getBytes());
out.write(newLine.getBytes());
String contDisp = "Content-Disposition:form-data;name=\"image\";fileName=\"Image.jpg\"";
String contEnc = "Content-Transfer-Encoding: binary";
String contentType = "Content-Type:image/jpeg";
out.write(contDisp.getBytes());
out.write(newLine.getBytes());
out.write(contentType.getBytes());
out.write(newLine.getBytes());
out.write(contEnc.getBytes());
out.write(newLine.getBytes());
out.write(newLine.getBytes());
out.write(imagedata);
out.write(newLine.getBytes());
out.write("--".getBytes());
out.write(boundary.getBytes());
out.write("--".getBytes());
out.write(newLine.getBytes());
finalOut.write(out.toByteArray());
out.flush();
out.close();
finalOut.flush();
finalOut.close();
InputStream instream=conn.openInputStream();
int ch=0;
StringBuffer buffesr=new StringBuffer();
while((ch=instream.read())!=-1)
{
buffesr.append((char)ch);
Dialog.alert("Uploaded");
}
}
catch (Exception e) {
Dialog.alert("Exception " + e);
}
}
Any help ??
The problem is that with Camera pictures, you can't predict what physical image size (pixel width x height) will correspond to a certain size in bytes.
If you have a hard, fixed limit on the size (in bytes) that you can upload, you might need to do something like this:
experiment with a few images, and find an approximate image size (width x height) that will produce a JPG file that normally fits within your 400-500KB limit
in your app, resize the Camera images to that physical size (width x height, in pixels)
check the size of the new JPG data, and see if it fits under your limit
if it does not fit, then you'll have to rescale the original image to a smaller size
As you can see, this isn't that simple to do. Most servers that I've seen (e.g. Facebook) tell you the maximum physical size in pixels that your image can be (e.g. 960 pixels as the widest size ... either width or height). If that's good enough for your server, it's much easier to code on the BlackBerry client side.
Restrict to a Fixed Pixel Width and Height
You could use something like this:
FileConnection file;
InputStream inputStream;
try {
file = (FileConnection) Connector.open(url); // JPG file:// URL
if (file.exists())
{
inputStream = file.openInputStream();
byte[] data = IOUtilities.streamToBytes(inputStream);
Bitmap original = Bitmap.createBitmapFromBytes(data, 0, data.length, 1);
Bitmap scaledImg = new Bitmap(640, 480); // maximum width and height
original.scaleInto(scaledImg,
Bitmap.FILTER_LANCZOS, /* LANCZOS is for best quality */
Bitmap.SCALE_TO_FIT);
// http://stackoverflow.com/a/14147236/119114
int jpegQuality = 85;
EncodedImage encodedImg = JPEGEncodedImage.encode(scaledImg, jpegQuality);
byte[] imageData = encodedImg.getData();
// TODO: send imageData as you already were
}
} catch (Exception e) {
// log exception
} finally {
try {
if (file != null) {
file.close();
}
if (inputStream != null) {
inputStream.close();
}
} catch (IOException ioe) {
// nothing can be done here
}
}
Of course, you should perform all this work on a background thread. Once you know the final image size, if you really want to, you can notify the user with something like:
final uploadSizeKb = imageData.length / 1024;
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
Dialog.alert(uploadSizeKb + "KB uploaded to server");
}
});
Further Optimizations
As you can probably tell, there's things you can adjust with this algorithm:
You could optimize by checking to see if the image file is already small enough, before trying to scale it. (check file.fileSize())
You could speed up the image scaling by using Bitmap.FILTER_BILINEAR or Bitmap.FILTER_BOX instead of Bitmap.FILTER_LANCZOS.
You can change the JPEG quality factor from 85 when you convert back to JPEG for uploading
You might need to check image orientation to avoid wasting too much space when you scale with SCALE_TO_FIT. If the Camera image is in the wrong orientation, just switch the scaledImg bitmap width and height (e.g. 640x480 -> 480x640)
You actually can skip a couple steps, and scale directly when reading in the image file, with createBitmapFromBytes(). The last parameter is a scale parameter. Unfortunately, since photographs are all different, it would also be difficult to pick one scale ratio that would work. As I said, it's more common that the server simply specifies a maximum image size, in pixels.
OS < 5.0 Support
If you don't have the image scaling APIs in OS 5.0 available, this older toolkit can be useful.

How to reduce memory when loading image from website?

I am using this Utility
public class Util_ImageLoader {
public static Bitmap _bmap;
Util_ImageLoader(String url) {
HttpConnection connection = null;
InputStream inputStream = null;
EncodedImage bitmap;
byte[] dataArray = null;
try {
connection = (HttpConnection) Connector.open(url + Util_GetInternet.getConnParam(), Connector.READ,
true);
inputStream = connection.openInputStream();
byte[] responseData = new byte[10000];
int length = 0;
StringBuffer rawResponse = new StringBuffer();
while (-1 != (length = inputStream.read(responseData))) {
rawResponse.append(new String(responseData, 0, length));
}
int responseCode = connection.getResponseCode();
if (responseCode != HttpConnection.HTTP_OK) {
throw new IOException("HTTP response code: " + responseCode);
}
final String result = rawResponse.toString();
dataArray = result.getBytes();
} catch (final Exception ex) {
}
finally {
try {
inputStream.close();
inputStream = null;
connection.close();
connection = null;
} catch (Exception e) {
}
}
bitmap = EncodedImage
.createEncodedImage(dataArray, 0, dataArray.length);
int multH;
int multW;
int currHeight = bitmap.getHeight();
int currWidth = bitmap.getWidth();
multH = Fixed32.div(Fixed32.toFP(currHeight), Fixed32.toFP(currHeight));// height
multW = Fixed32.div(Fixed32.toFP(currWidth), Fixed32.toFP(currWidth));// width
bitmap = bitmap.scaleImage32(multW, multH);
_bmap = bitmap.getBitmap();
}
public Bitmap getbitmap() {
return _bmap;
}
}
When I call it in a listfield which contains 10 childs, then the log keeps saying failed to allocate timer 0: no slots left.
This means the memory is being used up and no more memory to allocate again and as a result my main screen cannot start.
At the same time you have the following objects in memory:
// A buffer of about 10KB
byte[] responseData = new byte[10000];
// A string buffer which will grow up to the total response size
rawResponse.append(new String(responseData, 0, length));
// Another string the same length that string buffer
final String result = rawResponse.toString();
// Now another buffer the same size of the response.
dataArray = result.getBytes();
It total, if you downloaded n ascii chars, you have simultaneously 10KB, plus 2*n bytes in the first unicode string buffer, plus 2*n bytes in the result string, plus n bytes in dataArray. If I'm not wrong, that sums up to 5n + 10k. There's room for optimization.
Some improvements would be:
Check response code first, and then read the stream if response code is HTTP 200. No need to read if server returned an error.
Get rid of strings. No need to convert to string if after that you are converting again to bytes.
If images are large, don't store them in RAM while downloading. Instead, open a FileOutputStream and write to a temporary file as you read from input stream. Then, if temporary images are still large enough to be displayed, downscale them.

Create a Bitmap from an Image

I have an Image object which is a jpg picture taken by the camera and I need to create a Bitmap from it.
Is there any way to do it besides using BMPGenerator class? I'm working on a commercial project and I don't think I can use it due to the GPLv3 license.
So far this is the code I have. Can I do something with it?
FileConnection file = (FileConnection) Connector.open("file://" + imagePath, Connector.READ_WRITE);
InputStream is = file.openInputStream();
Image capturedImage = Image.createImage(is);
I tried this but I wasn't able to get the correct filepaht and the image is stuck in null
EncodedImage image = EncodedImage.getEncodedImageResource(filePath);
byte[] array = image.getData();
capturedBitmap = image.getBitmap();
You can use videoControl.getSnapshot(null) and then Bitmap myBitmap = Bitmap.createBitmapFromBytes(raw, 0, raw.length, 1) to get a bitmap from camera.
videoControl is got from player.getControl("VideoControl") and player is got from Manager.createPlayer()
By the way, what kind of Image do you have? If we are talking of EncodedImage, you can just use getBitmap() from it.
Fixed!
Well, almost.
Used the following method but the image is rotated 90 degrees.
Going to fix that with this
public Bitmap loadIconFromSDcard(String imgname){
FileConnection fcon = null;
Bitmap icon = null;
try {
fcon = (FileConnection)Connector.open(imgname, Connector.READ);
if(fcon.exists()) {
byte[] content = new byte[(int) fcon.fileSize()];
int readOffset = 0;
int readBytes = 0;
int bytesToRead = content.length - readOffset;
InputStream is = fcon.openInputStream();
while (bytesToRead > 0) {
readBytes = is.read(content, readOffset, bytesToRead);
if (readBytes < 0) {
break;
}
readOffset += readBytes;
bytesToRead -= readBytes;
}
is.close();
EncodedImage image = EncodedImage.createEncodedImage(content,0,content.length);
icon = image.getBitmap();
}
} catch (Exception e) {
}finally{
// Close the connections
try{ if(fcon != null) fcon.close(); }
catch(Exception e){}
}
return icon;
}

Resources