How to read PGM images in Java?

后端 未结 1 935
伪装坚强ぢ
伪装坚强ぢ 2021-02-06 18:38

I feel like I\'m missing something simple here (as usual).

I\'m trying to read PGM images using Java. Matlab does it just fine - outputting the image pixels (for example

相关标签:
1条回答
  • 2021-02-06 19:10

    The problem with your code is that you are using the wrong class to read raw data from the file. As the BufferedReader documentation says:

    public int read() throws IOException

    Reads a single character.

    Returns: The character read, as an integer in the range 0 to 65535 (0x00-0xffff), or -1 if the end of the stream has been reached

    So each call to the read() method of BufferedReader actually consumes one or two bytes (based on character encoding) from the input stream, which is not what you want. This also explains why you get a lot of -1: the stream ended much earlier than you thought.

    Since PGM contains values as ASCII decimal, it is easy to parse using the Scanner class.

    Here's an almost untested code that shows how to read a PGM image assuming that:

    • it contains a single comment after the magic number (i.e. it does not have lines that start with a # except the second one)
    • the PGM file is exactly 4 lines long.

    Here's the code:

    String filePath = "image.pgm";
    fileInputStream = new FileInputStream(filePath);
    Scanner scan = new Scanner(fileInputStream);
    // Discard the magic number
    scan.nextLine();
    // Discard the comment line
    scan.nextLine();
    // Read pic width, height and max value
    int picWidth = scan.nextInt();
    int picHeight = scan.nextInt();
    int maxvalue = scan.nextInt();
    
    fileInputStream.close();
                
     // Now parse the file as binary data
     fileInputStream = new FileInputStream(filePath);
     DataInputStream dis = new DataInputStream(fileInputStream);
     
     // look for 4 lines (i.e.: the header) and discard them
     int numnewlines = 4;
     while (numnewlines > 0) {
         char c;
         do {
             c = (char)(dis.readUnsignedByte());
         } while (c != '\n');
         numnewlines--;
     }
    
     // read the image data
     int[][] data2D = new int[picHeight][picWidth];
     for (int row = 0; row < picHeight; row++) {
         for (int col = 0; col < picWidth; col++) {
             data2D[row][col] = dis.readUnsignedByte();
             System.out.print(data2D[row][col] + " ");
         }
         System.out.println();
     }
    

    Need to implement: support for comment lines, values for each element should be divided by maxvalue, error checking for malformed files, exception handling. I tested it on a PGM file using UNIX end-of-lines, but it should work on Windows too.

    Let me stress that this is not a robust nor complete implementation of a PGM parser. This code is intended just as proof of concept that maybe accomplishes just enough for your needs.

    If you really need a robust PGM parser, you may use the tools provided by Netpbm.

    0 讨论(0)
提交回复
热议问题