どのようにJavaでRAM内の膨大なデータ/画像を処理するには?

ジェイミー:

概要

  1. 私は、画像データを含む大規模なバイナリファイルを読んでいます。
  2. 累積度数カット分析をデータに対して実行されている[これは画像と同じ大きさの別の配列を必要とします]。
  3. データは、0〜255の間に延伸するに格納されたBufferedImageJPanelの上に画像を描画するために、画素ごと。
  4. この画像に、ズームを使用して実行されますAffineTransform

問題

  1. 小さな画像(<。5ギガバイト)

    1.1は、私は後に、ズームを実行するためのスケールファクタを増加していた場合
    小数点例外がスローされます-

java.lang.OutOfMemoryErrorを:Javaのヒープ領域。

以下はzooming-に使用するコードです

    scaled = new BufferedImage(width, height, BufferedImage.TYPE_BYTE_GRAY);
    Graphics2D g2d = (Graphics2D)scaled.createGraphics();
    AffineTransform transformer = new AffineTransform();
    transformer.scale(scaleFactor, scaleFactor); 
    g2d.setTransform(transformer);
  1. 大画像(> 1.5ギガバイト)
    • 巨大な画像(> 1.5ギガバイト)のロード中に、同じ例外が1.1に登場して、でも画像をロードするための十分に小さい、時々、私は同じエラーを取得している場合に発生します。

しようとしたソリューション

  1. 私が使用してみましたBigBufferedImageを伸ばしデータを格納するためのBufferedImageの代わりに。BigBufferedImage image = BigBufferedImage.create(newCol,newRow, BufferedImage.TYPE_INT_ARGB);
  2. しかし、それはに渡すことができなかったg2d.drawImage(image, 0, 0, this);のJPanelの再描画方法はいくつかの理由で停止するため。

  3. Iは画素が読み出され、いくつかの列と行がされている低解像度のローディング画像を試みたジャンプ/スキップしかし、問題は、画像サイズとしてスキップする画素数が変動し、したがって、私が決定する方法を決定することができませんかを決定する方法であるジャンプパラメータを。

    MappedByteBuffer buffer = inChannel.map(FileChannel.MapMode.READ_ONLY,0, inChannel.size());
    buffer.order(ByteOrder.LITTLE_ENDIAN);
    FloatBuffer floatBuffer = buffer.asFloatBuffer();
    for(int i=0,k=0;i<nrow;i=i+jump)  /*jump is the value to be skipped, nrow is height of image*/
    {
        for(int j=0,l=0;j<ncol1;j=j+jump)   //ncol is width of image
        {
                index=(i*ncol)+j;
                oneDimArray[(k*ncolLessRes)+l] = floatBuffer.get(index);//oneDimArray is initialised to size of Low Resolution image.
                l++;
        }
        k++;
    }

問題は、すなわち設定されるべきジャンプのどの値スキップするどのように多くの列と行を決定することです。

  1. 私はXmxの設定しようとしたが、画像サイズが変化し、我々は動的に設定することはできません Xmxの値を。ここではいくつかの値であります-

table, th, td {
  border: 1px solid black;
}
<table style="width:100%">
  <tr>
    <th>Image Size</th>
    <th>Xmx</th>
    <th>Xms</th>
    <th>Problem</th>
  </tr>
  <tr>
    <td>83Mb</td>
    <td>512m</td>
    <td>256m</td>
    <td>working</td>
  </tr>
  <tr>
    <td>83Mb</td>
    <td>3096m</td>
    <td>2048m</td>
    <td>System hanged</td>
  </tr>
   <tr>
    <td>3.84Gb</td>
    <td>512m</td>
    <td>256m</td>
    <td>java.lang.OutOfMemoryError: Java heap space
  </tr>
  <tr>
    <td>3.84Gb</td>
    <td>3096m</td>
    <td>512m</td>
    <td>java.lang.OutOfMemoryError: Java heap space
  </tr>
</table>

  1. このために私はプログラムに割り当てられたメモリを見つけてみました: -
 try(BufferedWriter bw= new BufferedWriter(new FileWriter(dtaFile,true))){
    Runtime runtime=Runtime.getRuntime();
    runtime.gc();
    double oneMB=Math.pow(2,20);
    long[] arr= Instream.range(0,(int)(10.432*long.BYTES*Math.pow(2,20))).asLongStream().toArray();
    runtime.gc();
    long freeMemory= runtime.freeMemory();
    long totalMemory= runtime.totalMemory();
    long usedMemory= totalMemory-freeMemory;
    long maxMemory= runtime.maxMemory();
    String fileLine= String.format(" %9.3f  %9.3f   %9.3f " , usedMemory/oneMb, freeMemory/oneMB, totalMemory/oneMb, maxMemory/oneMB);
    bw.write();
}

以下の結果が得られた
メモリ割り当てを
このアプローチは、私のコードの使用方法に従って使用可能なメモリが増加しているために失敗しました。私はジャンプのための意思決定をするために、結果として、それは有用ではないだろう。

結果は、予想されます

私はジャンプの値に決定を下すためにそれを使用することができるように画像の読み込み前に、使用可能なメモリの量にアクセスする方法。決定する他の代替があり、ジャンプ値(すなわち、多くの私は、解像度を下げることができますか?)。

Sudhirドゥマル:

その後、表示目的のために解像度を落として、それをスケーリング、画像の特定の部分を読むことができます。

だからあなたの場合には、あなたは(私たちは行によってデシベルの行からデータを読み込むだけのように読める画像部)のチャンクで画像を読み取ることができます

例えば:

// Define the portion / row size 50px or 100px
int rowHeight = 50;
int rowsToScan = imageHeight / rowHeight;
if(imageHeight % rowHeight > 0) rowsToScan++;

int x = 0;
int y = 0;
int w = imageWidth;
int h = rowHeight;

ArrayList<BufferedImage> scaledImagePortions = new ArrayList<>();

for(int i = 1; i <= rowsToScan; i++) {
    // Read the portion of an image scale it
    // and push the scaled version in lets say array
    BufferedImage scalledPortionOfImage = this.getScaledPortionOfImage(img, x, y, w, h);
    scaledImagePortions.add(scalledPortionOfImage);

    y = (rowHeight * i);
}

// Create single image out of scaled images portions

画像の一部を取得するためにあなたを助けることができるスレッドのJavaで非常に大きなイメージファイルから読み取り領域

画像(私の迅速な検索結果を:))スケーリングするためにあなたを助けることができるスレッドJavaで画像のサイズを変更する方法?

バッファリングされた画像をマージであなたを助けることができるスレッド:2枚の画像をマージ

あなたはいつもスニペットを微調整することができます:)

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=228920&siteId=1