2

いくつかの BMP 画像を一緒に追加する必要があります。ご存知かもしれませんが、BMP イメージには 54 バイトのヘッダーがあります。独自の新しいヘッダーを新しいファイルに書き込みます。次に、BMP ファイルのリストをループして相互に追加する必要がありますが、それぞれの最初の 54 バイトをスキップする必要があります。

これは、ギガピクセルのイメージ スティッチング プロジェクト用です。画像に重複がないことを除いて、既存のソフトウェアを使用します(ただし、タイルのレイアウトは知っています)。いくつかの非常に大きな BMP ファイル (192,000x1080) を行として取り込み、それらを上下に追加して、20.7 ギガピクセルの最終画像を作成できるようにする必要があります。メモリは 32​​GB ありますが、最終的な 20.7 ギガピクセルの画像は 62.2GB になります (これを PNG に変換します)。

これらの巨大なメモリ要件を考えると、すべてのメモリを使用せずに各 BMP を読み取って最終ファイルに追加するにはどうすればよいでしょうか? 可能であれば、バイト配列を使用したいと思います。これらは圧縮されていない BMP であるため、GDI オブジェクトを使用せずにそのように読み取って別のファイルに保存できます。

4

3 に答える 3

4

ファイル内の任意の場所に書き込むことができます。ウィット:

using(var s = new FileStream("myBigImage.bmp", FileMode.Create, FileAccess.Write)) {
    //assume that you write out the header here
    foreach(var tileFile in tiles) {
        byte[] imgData = /*read image data into a byte[]*/;
        long y = /*obtain the correct y offset*/;

        s.Position = y * pixelWidth * imageWidth + 58;
        s.Write(imgData, 0, imgData.Length);

    }
}

基本的に、ファイル内をジャンプして、必要な場所に入力できます。Positionは長い値なので、32 ビット整数の制限にぶつかることを心配する必要はありません。

幸いなことに、画像は基本的にタイルを積み重ねただけなので、個々の行を処理することを心配する必要はありません。その場合、メモリを抑えるために、各タイルの行を個別に書き出す必要があります。

于 2013-03-27T13:01:57.507 に答える
1

結果のファイル データのすべてをメモリに保持する必要はありません。FileStream を開いてデータをファイルに書き込むだけです。ギガバイトのデータを書き込んでも、FileStream はメモリをあまり使用しません。

于 2013-03-27T13:01:57.910 に答える
0

私の後の誰かが興味を持っている場合に備えて、これが私がうまくいったことです:

for (int i = 0; i < reverseImageFiles.Length; i++)
        {
            string curBMP = reverseImageFiles[i];

            using(Stream inStream = File.OpenRead(curBMP))
            using (Stream writeStream = new FileStream(outputBMP,FileMode.Append,FileAccess.Write,FileShare.None))
            {
                BinaryReader reader = new BinaryReader(inStream);
                BinaryWriter writer = new BinaryWriter(writeStream);

                byte[] buffer = new Byte[134217728];
                int bytesRead;
                int totalBytes = 0;

                while ((bytesRead = inStream.Read(buffer, 0, 134217728)) > 0)
                {
                    totalBytes += bytesRead;

                    if (totalBytes <= 134217729)  //if it's the first round of reading to the buffer, you need to get rid of 54-byte BMP header
                    {
                        writeStream.Write(buffer, 54, bytesRead - 54);
                    }
                    else
                    {
                        writeStream.Write(buffer, 0, bytesRead);
                    }
                }

            }
        }

2つのこと:

特に BMP の場合、追加時にファイル リストを逆にする必要があることがわかりました。たとえば、追加する 3 つのファイルのラベルが 001.bmp、002.bmp、003.bmp の場合、001.bmp が先頭にあるはずですが、実際には 003.bmp から開始して下に進む必要があります。どうやら BMP は逆方向にエンコードされているようです。

ご覧のとおり、128MB のバッファーを使用しました。ハード ドライブのシークを減らしたい場合は、別のサイズを使用したほうがよいでしょうか? 私のドライブは最近最適化されました。助けてくれてありがとう!

于 2013-03-28T08:43:11.620 に答える