Sending a Matlab Image to an Android tablet - java

I have developed an Android app that connects with a laptop running Matlab over Bluetooth SPP. I am able to send strings back and forth easily and I am now interested in sending an image from Matlab to display on tablet (48x64 grayscale would be sufficient). I am unsure how to package an image and send it over at Matlab serial port. I am guessing you cannot just use fprintf or fwrite.
This is what I think the Android side might look like
public void drawImage(byte[] buffer){
ImageView camView = (ImageView)findViewById(R.id.camView);
Bitmap myBitmap = BitmapFactory.decodeByteArray(buffer, 0, buffer.length);
Log.d(TAG,"decoded image");
if(myBitmap != null){
camView.setImageBitmap(myBitmap);
Log.d(TAG,"Trying to display...");
}
else{
Log.d(TAG, "Bitmap = null");
}
}// end drawImage
Any advice on either the Andriod or Matlab side would be greatly appreciated. Thanks!

Are you just trying to receive serial data from Matlab? Why not treat it like any other serial data.
I would debug through an Android console application first to make sure it’s transmitting at all, and also to be sure that the data is transmitting the way you want it to transmit.

So I got it working. Basically the issue was that I was not sending the image with the proper compression (either .jpg or .png). I found that if you have a Matlab image which Matlab represents simply as a matrix of pixel values regardless of compression you need to create a java BufferedImage in order to properly construct the byte array so you can decode it on the Android side.
The Matlab side
import java.awt.*;
import java.io.*;
import java.util.*;
import javax.imageio.*;
serCam = InitUSBcamera; % initialize USB camera as a serial port
type = java.lang.String('jpg'); % translating matlab to java
outputStream = ByteArrayOutputStream; % create java output stream
im = getsnapshot(serCam); % get an image from the camera
im2 = imresize(im, [96,128],'nearest'); % reduce the size
im3 = im2java2d(im2); % create java Buffered Image
ImageIO.write(im3, type, outputStream);
bytes = outputStream.toByteArray();
fwrite(serTablet, bytes, 'int8') % send the image // changed to async

Related

Bytearray converted from Mat in Java to Image from Socket in Python

Im working on an Application were I get an image in Opencv Mat format from a Webcam in a Java Client and have to process this image on a python server.
Therefore I`m sending a bytearray to the python server. I´m encoding the Image in Java like this:
private VideoCapture capture = new VideoCapture();
...
this.capture.read(frame);
if (!frame.empty()) {
byte[] return_buff = new byte[(int) (frame.total() *
frame.channels())];
frame.get(0, 0, return_buff);
...
After that I send it through a Socket using a DataOutputStream. When I echo it back to the Java Client the bytedata seems to have been transferred correctly and entirely. In Python I then tried to decode it with PIL
img = Image.open(BytesIO(data))
And yes I already import PIL like suggested here: PIL: Convert Bytearray to Image
But Im still getting this Error:
img = Image.open(BytesIO(data))
File "/root/.local/lib/python2.7/site-packages/PIL/Image.py", line 2590, in
open % (filename if filename else fp))
IOError: cannot identify image file
Do I have to change the way I assembled my bytearra or do I have to encode it in a different way?
Solved it! The thing is that Image.open(BytesIO(data)) apparently expects the data to have some kind of header to describe the image type and was therefore unfitting for a mat converted to bytes because a Mat appears to have no kind of header integrated, just the plain image data. In python an Image from a Mat bytearray can be derived using the following:
img = cv2.imdecode(bytearray, flag)
with flag being a number representing the cvtype of the image.

How to copy and compress and then paste multiple jpg images [duplicate]

From pagespeed I am getting only image link and possible optimizations in bytes & percentage like,
Compressing and resizing https://example.com/…ts/xyz.jpg?036861 could save 212KiB (51% reduction).
Compressing https://example.com/…xyz.png?303584508 could save 4.4KiB (21% reduction).
For an example I have image of size 300kb and for this image pagespeed is displaying 100kb & 30% of reduction.
This is only for one image but I am sure I will have lots of images for compression.
so how can I compress image by passing bytes or percentage as a parameter or using anyother calculations in java
(by using API or image-processing Tool) so,that I can get compressed version of image as suggested by google.
Thanks in advance.
You can use Java ImageIO package to do the compression for many images formats, here is an example
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Iterator;
import javax.imageio.*;
import javax.imageio.stream.*;
public class Compresssion {
public static void main(String[] args) throws IOException {
File input = new File("original_image.jpg");
BufferedImage image = ImageIO.read(input);
File compressedImageFile = new File("compressed_image.jpg");
OutputStream os = new FileOutputStream(compressedImageFile);
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName("jpg");
ImageWriter writer = (ImageWriter) writers.next();
ImageOutputStream ios = ImageIO.createImageOutputStream(os);
writer.setOutput(ios);
ImageWriteParam param = writer.getDefaultWriteParam();
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
param.setCompressionQuality(0.05f); // Change the quality value you prefer
writer.write(null, new IIOImage(image, null, null), param);
os.close();
ios.close();
writer.dispose();
}
}
You can find more details about it here
Also there are some third party tools like these
https://collicalex.github.io/JPEGOptimizer/
https://github.com/depsypher/pngtastic
EDIT: If you want to use Google PageSpeed in your application, it is available as web server module either for Apache or Nginx, you can find how to configure it for your website here
https://developers.google.com/speed/pagespeed/module/
But if you want to integrate the PageSpeed C++ library in your application, you can find build instructions for it here.
https://developers.google.com/speed/pagespeed/psol
It also has a Java Client here
https://github.com/googleapis/google-api-java-client-services/tree/main/clients/google-api-services-pagespeedonline/v5
There is colour compression ("compression quality") and there is resolution compression ("resizing"). Fujy's answer deals with compression quality, but this is not where the main savings come from: the main savings come from resizing down to a smaller size. E.g. I got a 4mb photo to 207K using the maximum compression quality using fujy's answer, and it looked awful, but I got it down to 12K using a reasonable quality but a smaller size.
So the above code should be used for "compression quality", but this is my recommendation for resizing:
https://github.com/rkalla/imgscalr/blob/master/src/main/java/org/imgscalr/Scalr.java
I wish resizing was part of the standard Java libraries, but it seems it's not, (or there are image quality problems with the standard methods?). But Riyad's library is really small - it's just one class. I just copied this class into my project, because I never learnt how to use Maven, and it works great.
One liner java solution: thumbnailator.
Maven dependency:
<!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator -->
<dependency>
<groupId>net.coobird</groupId>
<artifactId>thumbnailator</artifactId>
<version>0.4.17</version>
</dependency>
The one liner:
Thumbnails.of(inputImagePathString).scale(scalingFactorFloat).outputQuality(qualityFactorFloat).toFile(outputImagePathString);
As a solution for this problem I can recommend the API of TinyPNG.
You can use it for compressing as well as resizing the image.
Documentation: tinypng.com/developers/reference/java

Using TCP for File Transfer Between Java (Android client) and C (PC server - Linux)

I know similar questions exist but I haven't found any of them suitable for my problem. I have an Android device (API 15 - Android version 4.0.4) and a Linux machine running Arch Linux. The idea was to create a connection between the server (C program) and client (Android app) so I could exchange files. Also, the server supports parallel connections and requires authentication. The android app has to create 3 connections to the server (using 3 different ports, so that means 3 AsyncTask-s running multi-threaded ) .. Two of them are for parallel background processes, and 1 is for the actual file transfer. I have created a code which worked well on the Emulator (Android KitKat OS), but when testing on my own phone it doesn't work. I will post my code, and I would like some advice from you, if that is possible. Thanks.
This is the code running on Android devices... BUFFSIZE
is 1024 and it is a global variable.
I've tried setting it to many values and none of them worked for me. filesize is set earlier in the code and always has the correct value so don't worry about it :)
InputStream is = socket.getInputStream();
FileOutputStream fs = new FileOutputStream(target);
int u;
byte[] jj = new byte[BUFFSIZE];
long overall = 0, percent = 0;
try {
while (overall < filesize && mRun) {
u = is.read(jj, 0, BUFFSIZE);
if (u == -1) break;
fs.write(jj, 0, u);
overall += u;
percent = overall*100/filesize;
}
fs.flush();
fs.close();
is.close();
socket.close();
} catch (IOException ex) {
// There were no exceptions while testing
// There is some code here that deals with the UI
// which is not important
}
And this is the C code...
for (;;)
{
/* First read file in chunks of BUF_SIZE bytes */
unsigned char buff[BUFFER]={0};
int nread = fread(buffer,1,BUFFER, input);
printf("Bytes read %d \n", nread);
/* If read was success, send data. */
if(nread > 0)
{
printf("Sending \n");
write(sockfd, buffer, nread);
}
/*
* There is something tricky going on with read ..
* Either there was error, or we reached end of file.
*/
if (nread < BUFFER)
{
if (feof(input))
printf("End of file\n");
if (ferror(input))
printf("Error reading\n");
break;
}
}
I have tested this code many times, even using telnet and it worked quite well. But I am not sure about the Java code.
So, why doesn't it work? Well, what I know so far is that some files are damaged. Let's just say that if I transfer an mp3 file with the size of 4MB, 3.99 would be sent and the resting 0.01 would be lost somewhere in the middle of the file, for no reason! When you play the damaged mp3, you can realize that some parts (like, every 10 seconds) you go "off-beat".. Like if there was a small noise that is then skipped. The resulting file is shorter for around 10 000 bytes than the original (but that depends on the actual file size.. You always lose some small percentage of the file, and that means that the while loop never finishes - the download process never finishes because the sockets are blocking and the client ends up waiting for more bytes which are never received) .. What I believe that happens is that, from a 1024-byte-long buffer, around 1000 bytes are used sometimes, instead of the full 1024 buffer size, which leads to the loss of 24 bytes. I am not saying that these are the actual numbers, but, that is just something going on in my head; I am likely wrong about this. I couldn't share the whole code with you because it's really long, so I decided to use the functions that deal with the download process, instead.
It is totally fine for the read method not to fill the whole buffer. That method returns the number of bytes read. You even assign that value to a variable:
u = is.read(jj, 0, BUFFSIZE);
But then you only check if u is -1 in order to find out when to stop reading. From the documentation:
The number of bytes actually read is returned as an integer.
Which means that your byte array has a maximum length of 1024 bytes, but not all of those will be filled at each read. And of course it won't be, otherwise this would only work if your input stream contains an exakt multiple of 1024 bytes.
Also: a thing called debugging exists. It might be hard to inspect binary data such as mp3 files, so try debugging while transmitting a text file.

Java ImageIO.write sends more data than ImageIO.read receives?

I'm trying to send an image over a socket, and I've come across a strange issue.. ImageIO.write is sending MORE data than ImageIO.read receives. For example if I have the code below in a loop:
(Client side)
out.writeByte(222);//magic num for testing
out.writeByte(blockSize);
out.writeByte(x / blockSize);
out.writeByte(y / blockSize);
ImageIO.write(part, "PNG", out);
(Server sided)
if (din.readUnsignedByte() != 222) {
throw new RuntimeException();
}
int partSize = din.readUnsignedByte();
int partX = partSize * din.readUnsignedByte();
int partY = partSize * din.readUnsignedByte();
BufferedImage part = ImageIO.read(din);
On the second iteration, the magic number will fail because ImageIO.read has not read all of the data sent from the other end. Why is this? It seems like a major issue. Or am I missing something?
EDIT: This seems to be a confirmed bug as of 2008-04-14. Bug ID 6687964. Why hasn't this been fixed?.. agh.
I came across the same issue. After the program has received the file, send a confirmation back to the sender. If the sender writes an escape character new String("\n").getBytes() then flushes the OutputStream it should end the buffered stream and allow you to InputStream.ReadLine() on the other end. This should get the excess data and the next repetition of the loop will get the new image data. Annoying I know, but it works
What I came up with as a workaround:
(bout being a ByteArrayOutputStream, and out being the socket stream)
ImageIO.write(part, "jpg", bout);
out.writeShort(bout.size());
bout.writeTo(out);
bout.reset();
This code will send the size of the image as a short before writing the image, thus preventing the bug.

How can I get an image too big from a server?

I'm currenty developing for blackberry and just bumped into this problem as i was trying to download an image from a server. The servlet which the device communicates with is working correctly, as I have made a number of tests for it. But it gives me the
413 HTTP error ("Request entity too large").
I figure i will just get the bytes, uhm, portion by portion. How can i accomplish this?
This is the code of the servlet (the doGet() method):
try {
ImageIcon imageIcon = new ImageIcon("c:\\Users\\dcalderon\\prueba.png");
Image image = imageIcon.getImage();
PngEncoder pngEncoder = new PngEncoder(image, true);
output.write(pngEncoder.pngEncode());
} finally {
output.close();
}
Thanks. It's worth mentioning that I am developing both the client-side and the server-side.
I am not aware by server side code. You can look on this Link to get an idea how to upload file using multipart to support Big files uploading
it can also work on blackberry , With some modifications needed.
http://www.developer.nokia.com/Community/Wiki/HTTP_Post_multipart_file_upload_in_Java_ME
I'm not familiar with the PNGEncoder class you're using, but just looking at your servlet code, and the comment you made about the request size (2.2 MB), I'm guessing that part of your problem is that you're uncompressing the image, and then transmitting it across the network.
I don't think you should have any PNGEncoder or ImageIcon code in your servlet. You should just read the "c:\\Users\\dcalderon\\prueba.png" file in with a normal InputStream as bytes, and then write that to the servlet's output. I don't think it matters whether that file is a PNG image, a .mp3 file, or any other content. (although you might need to set the Content Type to image/png).
So, I would try transmitting the image compressed (as a .png just as it's stored on disk). If that still doesn't work, then go with the suggestion to use multipart transmission.

Categories