views:

965

answers:

4

Hi,

I have been given a bit of a strange task, there are around 1500-2000 jpeg images all of around 1-50kb in size. They are currently stored in a simple database I made with Postgres. It's been a long time since I used Matlab and Postgres heavily so any help or suggestions is really appreciated!

I need to get the images that are stored in the database, out of the database into Java. The last step is retrieve the image from Java into Matlab so that the image is stored in the same way in which the imread function works in Matlab. The imread function reads an image in and creates a n by m by 3 matrix array of uint8 values which denote the pixel intensities of RGB.

Atm I have got the image in and out of the database in Java, currently storing the image in a bytea column data type. Is the best data type to use?

How can I get the data back out from the database, so that it is either the constructed jpeg image which I put in or is in the requested matrix array format?

Currently I do not understand the retrieved data. It is in a byte array of around 70,000 elements containing values between -128 to 128. Help!?!

Note: The database toolkit is unavailable to me

ANOTHER UPDATE: I have solved the problem related to the post regarding'UTF-8' encoding error.

If anyone stumbles upon this page, any answer posted will be tried as soon as I can! I really do appreciate your thoughts and answers. Thanks again.

A: 

Do you have access to the Database Toolbox in MATLAB? If so, you should be able to directly connect to a PostgreSQL database using the DATABASE function and then import and export data using the FETCH function or the QUERYBUILDER GUI. This may be easier than first going through Java.

gnovice
No, the Database Toolbox is not available to me and I am unfortunately unable to store the images on a file system as well. Making things little bit tricky!
Graham
A: 

Hi Graham

Here's a not terribly well informed answer -- I do a lot of Matlab but not much image processing and not much Java.

You can write Java statements right inside Matlab, can't you ? So you should be able to write 'Matlab' to retrieve the data from the database by calling Java DB functionality ? (This is a wild guess on my part, I'm away from a Matlab installation this weekend, operating from memory, always unreliable.)

A byte array of values between -128 and 127 (I bet you don't have any values of +128) looks to me like signed integer data, where you want unsigned integer data (uint). Try adding 128 -- of course it's a bit more tricky than that 'cos you can't add 128 to signed integer 8-bit data without overflowing (or wrapping round) so you'll have to either bit twiddle, or copy the data to a larger data type, adjust it, then copy back to uint8.

Another problem you might run into is ordering of rows and columns -- if your Java is a byte array, is it in column-major or row-major order ? Fairly easy to diagnose, is the image when you view it OK or transposed ? And, in Matlab, fairly easy to fix.

I know, not a terribly well-crafted answr, but hope it gives you some useful pointers.

Regards

Mark

High Performance Mark
Matlab's typecast() function can do the signed/unsigned conversion directly without fussing with int math. For example, typecast(int8(-3:3), 'uint8'). It's like a reinterpret cast in C.
Andrew Janke
+1  A: 

When you say you have the image in a bytea column, how exactly is it stored? Is it storing the bytes of the JPEG file's contents, or an array of RGB pixel values, or something else? "Bytea" is just a binary string, which can store data in pretty much any format.

I'm assuming it's the JPEG contents. In that case what you can do is retrieve the jpeg contents via Java, save them to a temporary file, and call imread() on the temp file.

Those [-128,127] values are values of signed bytes Java. Even without the Database Toolbox, you can call regular JDBC or other Java code that uses it. The Java method you used to get those values - call it from Matlab (with your JAR on the classpath), and it should return that array as an int8 array, or something you can convert to one.

Given that in a Matlab variable named "bytes", you can write it out to a temp file with something like this.

file = [tempname() '.jpg'];
fid = fopen(file, 'wb');
fwrite(fid, bytes, 'int8');
fclose(fid);

By specifying 'int8' precision, I think you can skip the step of converting them to unsigned bytes, which is a more common convention. Writing int8s as 'int8' or uint8s as 'uint8' will produce the same file. If you do need to convert them to unsigned, use Matlab's typecast() function.

unsigned_bytes = typecast(bytes, 'uint8');

At that point you can call imread on the temp file and then delete it.

img = imread(file);
delete(file);
Andrew Janke
I create a File object of the image and send the bytes of the image. So clarification, the bytea stores the JPEG file's contents.
Graham
I have attempted what you suggested through the Java app, creating a byte array and filling it from the bytea array that stores the picture. Then I created a FileOutputStream and the File but it seems as the result is not in a jpeg format as Matlab and other programs see the file as corrupt or unknown format.
Graham
A: 

Problem solved :-)

I have managed to get the bytes stored within the bytea column within the database into a byte array. Then through creating a temp file ( using ByteArrayInputStream and Reader object to form a BufferedImage object which I write to a file) send this back into Matlab in an array.

Then process the data I retrieved and read from the temporary file in Matlab. Once the data is within Matlab all the temp files are deleted.

The code to process the ResultSet to create a temp image from a byte array received from the databases bytea column is shown below:

private static void processImageResultSet(ResultSet rs) throws SQLException, FileNotFoundException, IOException{

        int i = 0;                  //used as a count and to name various temp files
        while(rs.next()){           //loop through result sets

        byte[] b = rs.getBytes(1);                                 //the bytea column result
        String location = getFileName(rs.getString(2));            //the name of the jpg file
        ByteArrayInputStream bis = new ByteArrayInputStream(b);    //creates stream storing byts

        //To make individual names of temporary files unique the current time and date is stored
        SimpleDateFormat df = new SimpleDateFormat("'Date 'yyyy-MM-dd HH'H'-mm'M'-ss'secs'-SS'ms'"); //formats date string
        Calendar cal = Calendar.getInstance();                                //gets instance of calendar time
        String fileDate = df.format(cal.getTime());                           //gets the time and date as a String

        Iterator<?> readers = ImageIO.getImageReadersByFormatName("jpg");     //creates a reader object, that will read jpg codec compression format
        Object source = bis;                                                  //object to store stream of bytes from database
        ImageReader reader = (ImageReader) readers.next();                      
        ImageInputStream iis = ImageIO.createImageInputStream(source);        //creates image input stream from object source which stores byte stream

        reader.setInput(iis, true);             //sets the reader object to read image input stream

        ImageReadParam param = reader.getDefaultReadParam(); 
        Image image = reader.read(0, param);

        BufferedImage bufferedImage = new BufferedImage(image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_RGB);   //creates buffered image

        Graphics2D g2 = bufferedImage.createGraphics();
        g2.drawImage(image, null, null);
        File imageFile = new File(location + " " + fileDate + " " + i + ".jpg"); //creates image file 
        ImageIO.write(bufferedImage, "jpg", imageFile);                          //writes buffered image object to created file

        i++;        //counts number of results from query within the ResultSet 
        }

    }
Graham