Solved

Reading in raw pixel data and creating an image

Posted on 2003-11-19
13
686 Views
Last Modified: 2007-12-19
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
0
Comment
Question by:ctjoumas
13 Comments
 
LVL 1

Expert Comment

by:allelopath
ID: 9780569
Have you created a a color model for the image?
0
 

Author Comment

by:ctjoumas
ID: 9780669
No I haven't.  I haven't had any experience with doing that - suggestions?
0
 
LVL 1

Expert Comment

by:allelopath
ID: 9780866
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
   
0
 

Author Comment

by:ctjoumas
ID: 9781283
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
0
 
LVL 1

Expert Comment

by:allelopath
ID: 9781493
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)
0
 
LVL 92

Expert Comment

by:objects
ID: 9782021
> There may be a better way though

No thats about right :)
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 
LVL 1

Expert Comment

by:allelopath
ID: 9782334
i am not worthy  :)
0
 
LVL 1

Expert Comment

by:allelopath
ID: 9783726
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.
0
 

Author Comment

by:ctjoumas
ID: 9787931
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();

0
 

Author Comment

by:ctjoumas
ID: 9788265
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
0
 
LVL 1

Expert Comment

by:allelopath
ID: 9788321
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.


0
 

Author Comment

by:ctjoumas
ID: 9788597
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!
0
 
LVL 5

Accepted Solution

by:
Netminder earned 0 total points
ID: 10244713
User resolved; points (45) refunded and question closed.

Netminder
EE Admin
0

Featured Post

How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

Join & Write a Comment

An old method to applying the Singleton pattern in your Java code is to check if a static instance, defined in the same class that needs to be instantiated once and only once, is null and then create a new instance; otherwise, the pre-existing insta…
This was posted to the Netbeans forum a Feb, 2010 and I also sent it to Verisign. Who didn't help much in my struggles to get my application signed. ------------------------- Start The idea here is to target your cell phones with the correct…
Viewers learn how to read error messages and identify possible mistakes that could cause hours of frustration. Coding is as much about debugging your code as it is about writing it. Define Error Message: Line Numbers: Type of Error: Break Down…
This tutorial covers a practical example of lazy loading technique and early loading technique in a Singleton Design Pattern.

708 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now