2

ここでは(いつものように)単純なものが欠けているような気がします。

Javaを使用してPGMイメージを読み取ろうとしています。Matlabはそれをうまく行います-Matlabで画像ピクセル(たとえば、小さな32x32画像)を出力すると、次のようなものが得られます。

1 0 11 49 94118118106 95 88 85 96124143142133

ただし、私のJavaリーダーはこれを出力します。

1 0 11 49 94118118106 95 88 85 96124 65533 65533 65533

127を超えるピクセル値は65533で埋められているように見えますが、ランダムな値が正しくない場合があり、下の行のほぼ全体が-1の値に割り当てられています。

これが私が使用しているコードです:

filePath ='imagepath.pgm';
FileInputStream fileInputStream = new FileInputStream(filePath);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(fileInputStream));

//ヘッダー情報を読み取ります..。

int [] [] data2D = new int [picWidth] [picHeight];

for(int row = 0; row <picHeight; row ++){
  for(int col = 0; col <picWidth; col ++){
    data2D [row] [col] = bufferedReader.read();
    System.out.print(data2D [row] [col] + "");
  }
  System.out.println();
}

fileInputStream.close();

任意のアイデアをいただければ幸いです。

編集符号なしのPGM値は次のとおりです。

     1 0 11 49 94118118106 95 88 85 96124143142133
    30 26 29 57 96122125114102 94 91101127146145136
    96 85 70 75101128136126111106106112131149153147
   163147114 93 99120132123110113124129137154166168
   215195149105 88 99114111106123148158160174191197
   245224173115 81 82100109117144179194194205222230
   235217170115 78 78113117100 83 80212214226244253
   178167135 93 68 78123129106 77 69202204222244255
   114110 92 64 54 81107105 83 59 56182184201222231
    79 80 71 52 55 97 67 55 41 33 42184179181185183
    62 66 65 52 63115 29 16 12 17 30209197174150132
    40 47 52 44 55109171196188186208229218179136107
    31 38 44 37 43 89145167158159191223219179133105
    48 52 56 51 57 91128133117120157196200168128105
    64 67 70 73 87114127107 79 81118159173154123104
    63 67 73 83107132129 91 54 54 88130153146123106

ヘッダーは次のようになります。

P5
#MatLab PGMWRITEファイル、2002年6月27日保存
16 16
255

編集#2

以下に、概念実証コードの完全な出力を示します。

不明なトークンをスキップする: ""
不明なトークンをスキップする: "1 ^vvj_XU`|���"
不明なトークンをスキップする: ""
不明なトークンをスキップする: "9`z} rf ^ [e���`UFKe��〜ojjp������r]cx�{nq|������ÕiXcroj{�������� �sQRdmu��������٪sNNqudSP�����]DN{�jME�����rn\@ 6QkiS;8�����OPG47aC7)!*�����> BA4? s」
不明なトークンをスキップする: ""
不明なトークンをスキップする: ""
不明なトークンをスキップする:「�Ů��(/4,7m�ļ���ڳ�k」
不明なトークンをスキップする: "&、%+Y������۳�i04839[��ux��Ȩ�i@CFIWrkOQv���{h?CISk��[66X���{j"
スレッド「メイン」の例外java.util.NoSuchElementException
    java.util.Scanner.throwFor(Scanner.java:838)で
    java.util.Scanner.next(Scanner.java:1347)で
    Test.main(Test.java:49)で

スローされた例外で参照されている49行目は次のとおりです。

System.out.println(String.format("Skipping unknow token: \"%s\"", scan.next()));

問題は、これらの画像ファイルがASCIIテキスト/数字とバイナリ画像データの両方で構成されているという事実と関係があると確信しています。しかし、JavaがPNGの読み取りに問題がない場合、なぜPGMのサポートがないのでしょうか。

編集3

わかりました、動作する実装を見つけました...残念ながら、非推奨です:

  filePath = "imagepath.pgm"
  FileInputStream fileInputStream = new FileInputStream(filePath);
  DataInputStream dis = new DataInputStream(fileInputStream);
  StreamTokenizer streamTokenizer = new StreamTokenizer(dis);

  // read header text using StreamTokenizer.nextToken()

  data2D = new int [picWidth] [picHeight];
  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();
  }

Javaのドキュメントによると、メソッドがrawバイトを文字に正しく変換しないStreamTokenizer(InputStream)ため、コンストラクターは非推奨になりました。DataInputStream.readLine()ただし、この特定のケースではヘッダーで機能するようであり、次のバイナリイメージデータでも機能することは明らかです。

残念ながら、それはまだ非推奨でありBufferedReader、ドキュメントが示唆しているようにaを混在させることにより、ヘッダーを読み取り、を使用して生のバイトを読み取ろEOFExceptionうとした後、結果はsになるだけのようです。DataInputStreamまだ解決策を探しています...

4

1 に答える 1

7

コードの問題は、ファイルから生データを読み取るために間違ったクラスを使用していることです。BufferedReaderドキュメントにあるように:

public int read() throws IOException

1文字を読み取ります。

戻り値:0〜65535(0x00-0xffff)の範囲の整数として読み取られた文字、またはストリームの終わりに達した場合は-1

read()したがって、のメソッドを呼び出すたびにBufferedReader、入力ストリームから1バイトまたは2バイト(文字エンコードに基づく)が実際に消費されますが、これは必要なものではありません。これは、多くの-1を取得する理由も説明しています。ストリームは思ったよりもはるかに早く終了しました。

PGMにはASCII10進数として値が含まれているため、 Scannerクラスを使用して簡単に解析できます。

これは、次のことを前提としてPGMイメージを読み取る方法を示すほとんどテストされていないコードです。

  • マジックナンバーの後にコメントが1つ含まれています(つまり、2番目の番号を除いて#で始まる行はありません)
  • PGMファイルの長さは正確に4行です。

コードは次のとおりです。

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();
 }

実装する必要があります:コメント行のサポート、各要素の値はmaxvalue、不正な形式のファイルのエラーチェック、例外処理で除算する必要があります。UNIXのエンドオブラインを使用してPGMファイルでテストしましたが、Windowsでも機能するはずです。

これは、PGMパーサーの堅牢でも完全な実装でもないことを強調しておきます。このコードは、ニーズに十分に対応できる概念実証として意図されています。

堅牢なPGMパーサーが本当に必要な場合は、Netpbmが提供するツールを使用できます。

于 2010-09-03T20:27:31.717 に答える