Link to home
Start Free TrialLog in
Avatar of ctjoumas
ctjoumas

asked on

Reading in raw pixel data and creating an image

I don't know if I need to know anymore specifics on this, but I cannot seem to get this to work. I have a custom file format that has header information, other file information, image width/height and raw pixel data. To make it simple, I have extracted the pixel data (using a hex editor) and put it in a separate file. What I am trying to do is just read in that data and create an image.

Here is the code I am using to read in the pixel data:

Note: fileLength is just the length of the file containing the data...

-----------------------------------
[code]
int i, count = 0;

int [] pixels = new int[ fileLength ];

try {

while ( count != fileLength ) {

i = bufferedInputStream.read();

// if this byte is valid, let's add it to the array
if ( i != -1 ) {

pixels[ count ] = i;

count++;
prog.setValue( count );

}

} // end while

bufferedInputStream.close();

} catch ( IOException e ) {
System.out.println( e );
}
[/code]
-----------------------------------

Then I create the image:

[code]
Image image = createImage( new MemoryImageSource( 150, 200, lf.getPixels(), 0, 150 ) );
[/code]

I already know that the image is 150px by 200px, so this is just hardcoded.

When I try and display this image, it is just all black (which is the background color I paint...so basically the image just isn't being rendered). Any suggestions?

Thanks,
Chris
Avatar of allelopath
allelopath

Have you created a a color model for the image?
Avatar of ctjoumas

ASKER

No I haven't.  I haven't had any experience with doing that - suggestions?
So you've got this pixel data that is an array of ints, with the ints representing a color.
The problem may be the you need something to tell the renderer what colors are represented by those int values, e.g 0 => black

You may be able you use the following class (filling in some blanks, indicated by ???)
It is a class for a 16-color image.


/*
 * @MyImage.java
 *
 */
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;

/**
 * Instantiate this class and then use the draw() method to draw the
 * generated on the graphics context.
 */
public class MyImage
{
// Holds the generated image
Image image;

// Create an Image from an Array of Color-Indexed Pixel Values
ColorModel colorModel = generateColorModel();

// true if image is scaled, false otherwise
boolean scaled = true;

Rectangle2D.Float rect;


/**
 *  Constructor
 */
public MyImage(int width,
                             int height)
{
    rect = new Rectangle2D.Float();
    createNewImage( width,
                                  height,
                                  rect);
} // end constructor

   
/**
 *  create pixel data based on dta by calling generateImage()
 *  create a data buffer from pixel image
 *  create a sample model from from data buffer
 *  create a raster object from sample model
 *  create a buffered image from raster object and color model
 *
 * @param width width of image
 * @param height height of image
 * @param loc location of image
 */
public void createNewImage(int width,
                                          int height,
                                           Rectangle2D.Float loc)
{
    // Generate the pixel data
    // Creating an Image from an Array of Color-Indexed Pixel Values
     byte[] pixels = ??? get pixel data here ???

    // Create a data buffer using the byte buffer of pixel data.
    // The pixel data is not copied; the data buffer uses the byte buffer array.
    DataBuffer dbuf = new DataBufferByte(pixels, width*height, 0);
   
     int numBanks = dbuf.getNumBanks(); // 1

    // Prepare a sample model that specifies a storage 4-bits of
    // pixel datavd in an 8-bit data element
    int bitMasks[] = new int[]{(byte)0xf};
    SampleModel sampleModel = new SinglePixelPackedSampleModel(DataBuffer.TYPE_BYTE, width, height, bitMasks);
   
    // Create a raster using the sample model and data buffer
    WritableRaster raster = Raster.createWritableRaster(sampleModel, dbuf, null);

    // Combine the color model and raster into a buffered image
    image = new BufferedImage(colorModel, raster, false, null);

}  // end constructor

   
/**
 * generate a color model
 *
 */
private static ColorModel generateColorModel()
{
  // Generate 16-color model
  byte[] r = new byte[16];
  byte[] g = new byte[16];
  byte[] b = new byte[16];

  r[0] = 0; g[0] = 0; b[0] = 0;                                               // 0x000000   0 black
  r[1] = 0; g[1] = 0; b[1] = (byte)192;                                   // 0x0000c0   1 dark blue
  r[2] = 0; g[2] = 0; b[2] = (byte)255;                                   // 0x0000ff   2 blue
  r[3] = 0; g[3] = (byte)192; b[3] = 0;                                   // 0x00c000   3 dark green
  r[4] = 0; g[4] = (byte)255; b[4] = 0;                                   // 0x00ff00   4 green
  r[5] = 0; g[5] = (byte)192; b[5] = (byte)192;                       // 0x00c0c0   5 teal
  r[6] = 0; g[6] = (byte)255; b[6] = (byte)255;                       // 0x00ffff   6 cyan
  r[7] = (byte)192; g[7] = 0; b[7] = 0;                                   // 0xc00000   7 dark red
  r[8] = (byte)255; g[8] = 0; b[8] = 0;                                   // 0xff0000   8 red
  r[9] = (byte)192; g[9] = (byte)240; b[9] = (byte)192;           // 0xc0f0c0   9 light green
  r[10] = (byte)255; g[10] = 0; b[10] = (byte)255;                 // 0xff00ff   10 magenta
  r[11] = (byte)192; g[11] = (byte)192; b[11] =  (byte)192;    // 0xc0c0c0   11 light grey
  r[12] = (byte)255; g[12] = (byte)255; b[12] = 0;                 // 0xffff00   12 yellow
  r[13] = (byte)128; g[13] = (byte)128; b[13] = (byte)128;     // 0x808080   13 med grey
  r[14] = (byte)80; g[14] = (byte)80; b[14] = (byte)80;          // 0x505050   14 dark grey
  r[15] = (byte)255; g[15] = (byte)255; b[15] = (byte)255;     // 0xffffff   15 white  

  return new IndexColorModel(4, 16, r, g, b);
}

 
/**
 * check if image is scaled
 *
 * @param g graphics context
 * @param x x-coordinate
 * @param y y-coordinate
 */
public void draw(Graphics g, int x, int y)
{
    g.drawImage(image, x, y, null);
}
   
} // end class
   
I tried what you had and I still get the same result...

I think this might change things - but I just found out from someone that all of these images will be grayscale.  Sorry I didn't have that information earlier (if it changes anything)!

Chris
greyscale could be implemented by changing the rgb code to different shades of grey, rather than color.

  r[0] = 0; g[0] = 0; b[0] = 0;                                               // 0x000000   0 black
  r[1] = ?; g[1] = ?; b[1] = ?;                                                // really dark grey
  ...
  r[14] = ?; g[14] = ?; b[14] = ?;                                          // really light grey
  r[15] = (byte)255; g[15] = (byte)255; b[15] = (byte)255;     // 0xffffff   15 white  

There may be a better way though, in which case it would be a good time for a more experienced java person to jump in (objects, CEHJ, jimmack, el al)
Avatar of Mick Barry
> There may be a better way though

No thats about right :)
i am not worthy  :)
Oh, also, to take a baby step, you could create a 150x200 grey scale gif file and try to display that in the same area where you now get black.
I actually couldn't get that to work, but I have tried different ways to get my desired result.  Also, sorry for the lack of points - just posting this if anyone is curious or if anyone has any solution - here's a pretty good rundown of what I'm doing and what my progress is so far (I'm actually getting an image, it just looks liike crap!):

I'm reading in raw pixel data of a 16-bit signed grayscale image. I was trying to use the int array of what the readPixels returned (where readPixels returns an Object), but I don't know if what I was trying will make any difference. So, I guess I'm gonna kinda change this topic in case anyone has any ideas:

I am trying different ways to open the raw data -
1) Using a FileInputStream to read the file and creating the image like:

            try {

                FileInputStream in = new FileInputStream( fileName );

                int i;
                int x = 0;
                int y = 0;

                while ( (i = in.read()) != -1 ) {

                    image.setRGB( x, y, 0xFF000000 + (i<<16) + (i<<8) + i );

                    x++;
                    if ( x >= WIDTH ) {
                        x = 0;
                        y++;
                        if ( y >= HEIGHT )
                            break;
                    } // end if

                } // end while
                in.close();
            } catch ( Exception ex ) { ex.printStackTrace(); }


The problem there is that the BufferedImage that I am setting RGB values for is a Grayscale image (BufferedImage.TYPE_BYTE_GRAY), which is unsigned - whereas I need signed and am not sure how to do that.

2) Trying the same way as above, but using ImageReader like this:


            try {

                FileInputStream in = new FileInputStream( fileName );

                ImageReader ir = new ImageReader( fi );
                Object pixels = ir.readPixels( in );

                in.close();

                int x = 0;
                int y = 0;

                ByteArrayOutputStream bos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream( bos );
                oos.writeObject( pixels );
                oos.flush();
                oos.close();
                bos.close();
                byte [] data = bos.toByteArray();

                int [] pix = new int[ data.length ];

                for ( int i=0; i<data.length; i++ ) {
                    pix[ i ] = data[ i ];
                    System.out.println( data[ i ] );
                }

                for ( int i=0; i<pix.length; i++ ) {

                    image.setRGB( x, y, 0xFF000000 + (pix[ i ]<<16) + (pix[ i ]<<8) + pix[ i ] );

                    x++;
                    if ( x >= WIDTH ) {
                        x = 0;
                        y++;
                        if ( y >= HEIGHT )
                            break;
                    } // end if
                } // end for
            } catch ( Exception e ) { System.out.println( e ); }


I get a null pointer exception when using setRGB at the first pixel, so not sure whats going on there.

3) the third way I am trying is using a FileOpener to get an ImagePlus image back - again, I think this is an unsigned image, so I get the same exact result as method 1:


            FileInfo fi = new FileInfo();
            fi.width = WIDTH;
            fi.height = HEIGHT;
            fi.offset = 0;
            fi.fileName = fileName;
            fi.intelByteOrder = true;
            FileOpener fo = new FileOpener( fi );
            ImagePlus ip = fo.open( false );
            image = ip.getImage();

I got the third way to work by doing the following:

            FileInfo fi = new FileInfo();
            fi.width = WIDTH;
            fi.height = HEIGHT;
            fi.offset = 0;
            fi.fileName = fileName;

            fi.intelByteOrder = false;
            fi.fileType = FileInfo.GRAY16_SIGNED;

            FileOpener fo = new FileOpener( fi );
            ImagePlus ip = fo.open( false );

            image = ip.getImage();


The image doesn't seem to be as high quality as the software that loaded it (CINE I think it is), but that software may have had something internally to sharpen it.  This method doesn't give me as much flexibility as I'd like since it is all done by itself - is there a way to duplicate this logic with one of the othe rmethods I was using before?

Thanks,
Chris
hmmm...converting 16 bit signed to unsigned can be done by something like this (i think):
if the signed number < 0 then
  signed number = 2^16 + signed number
else // signed number is >= 0
  do nothing

you should definitely check the math on that though, i'm just remembering this from long ago.


I don't want to convert from signed to unsigned - the raw data is signed.  In the other 2 methods that I am using, I need to create a BufferedImage object - and the types that I can choose (the TYPE_BYTE_GRAY) is unsigned.  So my problem in the other methods is storing signed into unsigned!  So I was thinking that there might be another way to create the BufferedImage so that it is not unsigned - or if there is someway to convert the image to signed.

Hope this is clear enough!
ASKER CERTIFIED SOLUTION
Avatar of Netminder
Netminder

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial