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
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
Have you created a a color model for the image?
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 SinglePixelPackedSampleMod el(DataBuf fer.TYPE_B YTE, width, height, bitMasks);
// Create a raster using the sample model and data buffer
WritableRaster raster = Raster.createWritableRaste r(sampleMo del, 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
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 SinglePixelPackedSampleMod
// Create a raster using the sample model and data buffer
WritableRaster raster = Raster.createWritableRaste
// 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
ASKER
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
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)
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)
> There may be a better way though
No thats about right :)
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.
ASKER
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_G RAY), 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'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_G
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();
ASKER
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
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.
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.
ASKER
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!
Hope this is clear enough!
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.