问题
I need to read a pgm file and store the array of values contained in it in a 2D array. In PGM format, each pixel is specified by a gray value between 0 and MaxVal. The first three lines give information related to the image: magic number, height, width and maxVal. The file also includes whitespaces. Lines starting with # are comments. This is what I had written till now.
public class PGM{
public static void main(String args[]) throws Exception {
FileInputStream f = new FileInputStream("C:\\......\\brain_001.pgm");
DataInputStream d = new DataInputStream(f);
d.readLine();//first line contains P5
String line = d.readLine();//second line contains height and width
Scanner s = new Scanner(line);
int width = s.nextInt();
int height = s.nextInt();
line = d.readLine();//third line contains maxVal
s = new Scanner(line);
int maxVal = s.nextInt();
byte[][] im = new byte[height][width];
for (int i = 0; i < 258; i++) {
for (int j = 0; j < 258; j++) {
im[i][j] = -1;
}
}
int count = 0;
byte b;
try {
while (true) {
b = (byte) (d.readUnsignedByte());
if (b == '\n') { //do nothing if new line encountered
} else if (b == '#') {
d.readLine();
} else if (Character.isWhitespace(b)) { // do nothing if whitespace encountered
} else {
im[count / width][count % width] = b;
count++;
}
}
} catch (EOFException e) {
}
System.out.println("Height=" + height);
System.out.println("Width=" + height);
System.out.println("Required elemnts=" + (height * width));
System.out.println("Obtained elemnets=" + count);
}
}
When the program is run, I get the following output:
Height=258
Width=258
Required elemnts=66564
Obtained elemnets=43513
The number of elements (each corresponding to a gray value) are less than the required ones. When I open the file with a PGM viewer, everything shows up correctly. Also, when I print the contents of the array, I see a lot of negative values. But all of them have to be greater than or equal to zero. Where have I gone wrong?
回答1:
Most likely its because of deprecated method readLine()
from DataInputStream
. As mentioned in its annotation
*This method does not properly convert bytes to characters. As of JDK 1.1, the preferred way to read lines of text is via the BufferedReader.readLine() method. Programs that use the DataInputStream class to read lines can be converted to use the BufferedReader class by replacing code of the form: DataInputStream d = new DataInputStream(in);
with: BufferedReader d = new BufferedReader(new InputStreamReader(in));*
When I changed your program according to this advice, it worked for me (I made a couple of other changes as well:
(Updated to handle P2 and P5 flavors of PGM)
public static void main(String args[]) throws Exception {
try {
InputStream f = ClassLoader.getSystemClassLoader().getResourceAsStream("lena.pgm");
BufferedReader d = new BufferedReader(new InputStreamReader(f));
String magic = d.readLine(); // first line contains P2 or P5
String line = d.readLine(); // second line contains height and width
while (line.startsWith("#")) {
line = d.readLine();
}
Scanner s = new Scanner(line);
int width = s.nextInt();
int height = s.nextInt();
line = d.readLine();// third line contains maxVal
s = new Scanner(line);
int maxVal = s.nextInt();
byte[][] im = new byte[height][width];
int count = 0;
int b = 0;
try {
while (count < height*width) {
b = d.read() ;
if ( b < 0 )
break ;
if (b == '\n') { // do nothing if new line encountered
}
// else if (b == '#') {
// d.readLine();
// }
// else if (Character.isWhitespace(b)) { // do nothing if whitespace encountered
// }
else {
if ( "P5".equals(magic) ) { // Binary format
im[count / width][count % width] = (byte)((b >> 8) & 0xFF);
count++;
im[count / width][count % width] = (byte)(b & 0xFF);
count++;
}
else { // ASCII format
im[count / width][count % width] = (byte)b ;
count++;
}
}
}
} catch (EOFException eof) {
eof.printStackTrace(System.out) ;
}
System.out.println("Height=" + height);
System.out.println("Width=" + height);
System.out.println("Required elements=" + (height * width));
System.out.println("Obtained elements=" + count);
}
catch(Throwable t) {
t.printStackTrace(System.err) ;
return ;
}
}
回答2:
The following code works for me:
FileInputStream f;
try {
f = new FileInputStream(fileLocation);
BufferedReader br = new BufferedReader(new InputStreamReader(f));
String magic = br.readLine(); // first line contains P2 or P5
String line = br.readLine(); // second line contains height and width
//-scan width and height
Scanner s = new Scanner(line);
int width = s.nextInt();
int height = s.nextInt();
s.close();
//-scan max value
line = br.readLine();// third line contains maxVal
s = new Scanner(line);
// int maxVal = s.nextInt();
//-close scanner
s.close();
//-close buffer
br.close();
f.close();
xvec=new DenseMatrix64F(height*width, 1);
int b=0;
int counter=0;
f = new FileInputStream(fileLocation);
DataInputStream dis = new DataInputStream(f);
//-move across unused lines
dis.readLine();
dis.readLine();
dis.readLine();
while ((b=dis.read()) >= 0) {
xvec.set(counter, 0, b);
counter++;
}
dis.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
来源:https://stackoverflow.com/questions/11922252/reading-a-pgm-file-in-java