0

機械学習コースのトレーニング セットを用意する必要があります。このトレーニング セットでは、特定の顔画像について、頭の側面 ( Straight 、 Left 、 Right 、 Up ) を表す答えが得られます。

この目的のために、Java で .pgm 画像ファイルを読み取り、そのピクセルを行列 X の 1 行に格納してから、この画像の適切な正解を y ベクトルに格納する必要があります。最後に、これら 2 つの配列を .mat ファイルに保存します。

問題は、(P2 .pgm) 画像からピクセル値を読み取って console に出力しようとすると、matlab マトリックス ビューアーと同じ値が得られないことです。何が問題になるでしょうか?

これは私のコードです:

try{
    InputStream f = Main.class.getResourceAsStream("an2i_left_angry_open.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("#")) {  // ignoring comment lines
            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();
        for(int i=0;i<30;i++) /* printing first 30 values from the image including spaces*/
            System.out.println((byte)d.read());

        } catch (EOFException eof) {
            eof.printStackTrace(System.out) ;
        }

これらは私が得る値です: 50 49 32 50 32 49 32 48 32 50 32 49 56 32 53 57

この写真は、実際に MATLAB Viewer からの画像に含まれているものです: (申し訳ありませんが、評判が悪いため画像を投稿できません)

これは、notepad++ で .pgm ファイルを開くと表示されるものです。

4

2 に答える 2

1

特にこの投稿を見てください。私はimreadJavaのImageIOクラスで同様の問題を経験してきましたが、長い間、他の人が同じことを経験したという証拠としてこのリンクを見つけることができませんでした...今まで. 同様に、誰かがこの投稿で関連する問題を経験しましたが、あなたが経験しているものとはまったく同じではありません.

本質的に、Java と MATLAB の両方に読み込まれるイメージが異なる理由は、機能強化のためです。MATLAB は強度をスケーリングして、イメージがほとんど黒くならないようにします。基本的に、PGM の最大強度は にスケーリングされ255、他の強度は のダイナミック レンジに合わせて線形にスケーリングされます[0,255]。したがって、たとえば、画像をでロードする前に[0-100]PGM ファイルのダイナミック レンジがあった場合、これは にスケーリングされ、元の のスケールにはなりません。そのため、イメージをロードする前に (自分でファイルをスキャンして) イメージの最大強度値を知る必要があります。これは、ファイルの 3 行目を読み取ることで非常に簡単に実行できます。あなたの場合、これはimread[0-255][0-100]156. これを見つけたら、画像内のすべての値をスケーリングして、読み込む前の元の値に再スケーリングする必要があります.

これが事実であることを確認するには、画像の最初のピクセルを見てください。元の PGM ファイルでは強度が 21 です。したがって、MATLAB は次のように強度をスケーリングします。

scaled = round(val*(255/156));

valは入力強度でscaledあり、出力強度です。そのため、 の場合val = 21は次のscaledようになります。

scaled = round(21*(255/156)) = 34

これは、MATLAB で読み取るときに最初のピクセルと一致します。同様に、最初の行の 6 番目のピクセルで、元の値は 18 です。MATLAB は次のようにスケーリングします。

scaled = round(18*(255/156)) = 29

これも、MATLAB で表示されるものと一致します。今パターンを見始めていますか?基本的に、スケーリングを元に戻すには、スケーリング係数の逆数を掛ける必要があります。そのため、それAがロードしたイメージであることを考えると、次のことを行う必要があります。

A_scaled = uint8(double(A)*(max_value/255));

A_scaledは出力イメージで、でロードする前にmax_valuePGM ファイルで見つかった最大強度です。これにより、MATLAB が からイメージをスケーリングするため、スケーリングがに戻ります。最初に画像をキャストする必要があることに注意してください。これは浮動小数点値を生成する可能性が最も高いため、スケーリング係数を使用して乗算を行い、次に に再キャストする必要があります。したがって、元に戻すには、逆の方法でスケーリングする必要があります。imread[0-255]doubleuint8[0-max_value]

具体的には、次のことを行う必要があります。

A_scaled = uint8(double(A)*(156/255));

ここでの欠点は、画像を操作する前に最大値を知る必要があることです。これは煩わしい場合があります。1 つの可能性は、MATLAB を使用して実際にファイル ポインターを使用してファイルを開き、3 行目の値を自分で取得することです。これも面倒な手順ですが、別の方法があります。

代替...おそらくあなたにとってより良い

または、不必要なスケーリングを行わずにPGM ファイルを読み書きする MATLAB で記述された関数への 2 つのリンクを次に示します。これにより、期待する結果 (スケーリングなし) が得られます。

read 関数のしくみは、ファイル ポインターを使用して画像を開き、手動でデータを解析し、値をマトリックスに格納することです。に依存する代わりに、おそらくこの関数を使用したいと思うでしょうimread。画像を保存するために、ファイル ポインターが再び使用され、PGM 標準が維持されるように値が書き込まれ、強度はスケーリングされません。

于 2014-12-19T15:06:39.747 に答える
0

あなたのJava実装は、テキストバイト「21 2 1」などのASCII値を出力しています.

50->2
51->1
32->SPACE
50->2
32->SPACE
51->1 
etc.

一部の PGM ファイルはテキスト ヘッダーを使用しますが、ピクセル自体はバイナリ表現です。これらは、最初に別の魔法の文字列でマークされています。Java コードがバイナリ ピクセルを持っているかのようにファイルを読み取っているようです。

代わりに、PGM ファイルには ASCII コードのピクセルが含まれており、各ピクセルの空白で区切られた値をスキャンする必要があります。これは、幅と高さを読み取るのと同じ方法で行います。

デバッグ コードは次のようになります。

line = d.readLine(); // first image line
s = new Scanner(line);
for(int i=0;i<30;i++) /* printing first 30 values from the image including spaces*/
    System.out.println((byte)s.nextInt());
于 2014-12-19T20:58:45.093 に答える