C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[7]: byte配列からbitmapへ変換がうまくいきません


(過去ログ 81 を表示中)

[トピック内 8 記事 (1 - 8 表示)]  << 0 >>

■48272 / inTopicNo.1)  byte配列からbitmapへ変換がうまくいきません
  
□投稿者/ Tak (1回)-(2010/03/31(Wed) 15:34:31)

分類:[C#] 

ネットワークストリームから取得したbyte配列をbitmap形式に変換しようとしているのですが、どうにもうまくいきません。
bitmap形式に変換した後、データファイルとして保存してみると、真っ黒な背景に少しノイズがかったような絵になっていました。
パラメータに問題があるのかと思いPixelFormatを変更したりしてみたのですが、やはりうまくいきませんでした。

public byte [] ReceiveBinary(int size)
{

byte[] buf = new byte[1024];
int read = 0;
int cnt = 0;

NetworkStream ns = client.GetStream();

using (MemoryStream ms = new MemoryStream())
{
while ((read = ns.Read(buf, 0, buf.Length)) != 0)
{
ms.Write(buf, 0, read);
cnt += read;

if (cnt >= size)
break;
}

Bitmap bmp = new Bitmap(1280, 800, PixelFormat.Format24bppRgb);

BitmapData bd = bmp.LockBits(
new Rectangle(0, 0, 1280, 800),
ImageLockMode.WriteOnly,
PixelFormat.Format24bppRgb);

Marshal.Copy(ms.ToArray(), 0, bd.Scan0, ms.ToArray().Length);

bmp.UnlockBits(bd);

bmp.Save("C:\\test.bmp");


return ms.ToArray();
}

}

ストリームから取得したbyte配列の中身がおかしいのかと疑ってみたのですが、下記のようにImageConverterを使用したところ正しく画像表示できました。
なので、byte配列の中身は問題ないと考えています。

public byte [] ReceiveBinary(int size)
{

byte[] buf = new byte[1024];
int read = 0;
int cnt = 0;

NetworkStream ns = client.GetStream();

using (MemoryStream ms = new MemoryStream())
{
while ((read = ns.Read(buf, 0, buf.Length)) != 0)
{
ms.Write(buf, 0, read);
cnt += read;

if (cnt >= size)
break;
}

ImageConverter imgconv = new ImageConverter();
((Image)imgconv.ConvertFrom(ms.ToArray())).Save("C:\\test.bmp");


return ms.ToArray();
}

}

お気づきの点ありましたら、ご指摘頂きたいです。
引用返信 編集キー/
■48273 / inTopicNo.2)  Re[1]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ よねKEN (450回)-(2010/03/31(Wed) 15:54:29)
そのbyte配列がbmpファイルの生データと同じ形式なら、
Image.FromStreamメソッド
でうまくいかないでしょうか?

#ImageConverter.ConvertFromで扱える元データの形式を調べたけれどもわからなかったので、
#そのbyte配列がbmpファイルの生データと同じ形式なのかどうかを推測できませんでした。
#今やろうとしている方向性でのやり方についてはBITMAP形式についてあまり深い知識がないのでわかりません。

引用返信 編集キー/
■48275 / inTopicNo.3)  Re[2]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Hongliang (583回)-(2010/03/31(Wed) 16:08:41)
質問の回答は よねKEN さんがお答えになったとおりだと思います。

で、一点気になったところ。
> bmp.Save("C:\\test.bmp");
Bitmap.Save は、ImageFormat を指定しない場合 png 形式で保存しますよ。
引用返信 編集キー/
■48277 / inTopicNo.4)  Re[3]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Tak (2回)-(2010/03/31(Wed) 17:28:39)
よねKENさん、Hongliangさん

ご返信有難う御座います。すいません、最初に言っておけばよかったことを今補足します。
今回リアルタイムで画像データを受信するクライアントプログラムを組んでいるのですが、ネックになっているのがパフォーマンスです。

while ((read = ns.Read(buf, 0, buf.Length)) != 0)
{
ms.Write(buf, 0, read);
cnt += read;

if (cnt >= size)
break;
}
Image img = Image.FromStream(ms);
// img.Save("C:\\test.bmp", ImageFormat.Bmp);

上記のように修正したところ、正常に画像を見ることができたのですが、結構重い処理のようで、CPU使用率は可能な限り下げておきたい(処理効率を上げたい)のが今回の目的です。
タスクマネージャで見る限り10〜20%ほどCPU使用率が上がりました。

私の調べた限り、最初の方法が良さそうだと思っていたのですが、今回の問題に当たりまして・・・
今回の方法で正常に表示できるということは、やはり、Bitmapファイルと同じデータがバイナリデータには入っている、ということなのでしょうか。

他にもこういう方法がある等ご教授頂ければ幸いです。
引用返信 編集キー/
■48285 / inTopicNo.5)  Re[4]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Hongliang (584回)-(2010/03/31(Wed) 20:08:36)
単に「ネットワーク上のファイルを保存する」だけなら、そもそも Bitmap オブジェクトを経由させる必要はありませんが、bmp 形式のファイルとして保存しないといけないという事情でもありますか?

Bitmap オブジェクトの構築処理の大部分は画像デコードが占めます。
bmp 形式に変換する、あるいはそれを(ファイルとしてではなく)画像として扱う必要があるなら、どのみち一旦デコードしなければならず、それは必要なコストです。CPU 使用率を下げれば代わりに処理時間が長くなるだけの話です。
他の処理の邪魔をしないようにするなら、Bitmap オブジェクトの生成を別スレッドにし、そのスレッドの Priority を下げるという方法はあります。
引用返信 編集キー/
■48289 / inTopicNo.6)  Re[5]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Tak (3回)-(2010/03/31(Wed) 20:56:36)
Hongliangさん

ご回答有難うございます。

「bmp形式のファイルとして保存しないといけない」という事情はありません。
ストリームから取得したバイナリデータを何らかの形で、フォームに連続して描画させようとしています。
そこで、パッと思いついたのがbmp形式でした。

他に方法がありますでしょうか??

>そもそも Bitmap オブジェクトを経由させる必要はありません

すいません。ここの理解が足りないようです。
引用返信 編集キー/
■48296 / inTopicNo.7)  Re[6]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Hongliang (585回)-(2010/03/31(Wed) 22:48:09)
保存形式と、プログラム上の画像オブジェクトを混同しないようにして下さい。

まず、生の画像データが存在します。このデータは、縦横のサイズやパレットの情報、各ピクセルの色情報を持ちます。
・この画像データを保存する際に、データを圧縮したりヘッダを付けたりするのが保存形式です。bmp ならほとんどそのまま保存しますし、png なら可逆的に、jpeg なら非可逆的に圧縮して保存します。
・.NET / System.Drawing では、プログラムから扱いやすいように生の画像データは Image クラス(とその派生クラスの Bitmap クラス)によって抽象化されたオブジェクトとしてラップされます。

Image/Bitmap オブジェクトには、保存形式は意味がありません。生の画像データを持っていればそれで十分だからです。
Save メソッドで保存するときに初めて保存形式である ImageFormat が出現するわけです。
なおロードする(FromStream などで開く)ときは、ライブラリがヘッダを見て保存形式を調べ、適切な方法で生の画像データに変換します(保存されているデータから生の画像データに展開することをデコードと表現します。逆に生の画像データを任意の保存形式で保存するのはエンコードです)。

「bmp 形式」は保存形式であり、プログラム上で画像として扱っている間は意味がありません。


さて、プログラム上で画像を扱う場合、WinForm では System.Drawing.Image を使うしかありません。
そしてある画像ファイルから Image オブジェクトを作成するのは Image.FromStream ぐらいしか存在しない以上、特にこれ以上打つ手はないでしょう。
前述のように優先順位の低いスレッドにやらせてメインの処理が待たされないようにするぐらい(メインの処理が優先されるだけであり、メインの処理がなければ普通に全力でデコードしますが)ですが、これは多分「効果がないのに実装が面倒」に感じるでしょう。
// なんか「CPU 使用率が見かけ上高くなるのが困る」と書いてあるように見える。
引用返信 編集キー/
■48300 / inTopicNo.8)  Re[7]: byte配列からbitmapへ変換がうまくいきません
□投稿者/ Tak (4回)-(2010/04/01(Thu) 01:50:27)
Hongliangさん、ご返信有難う御座います。

送信側は画像データを保存形式に変換(エンコード)してデータを配信し、受信側はこれを適切な方法で生の画像データに変換する(デコード)
ということで良いでしょうか。
それで、デコードの処理(Image.FromStream)は必要コストであり、優先順位の低いスレッドにやらせるのが良いということですよね。

>この画像データを保存する際に、データを圧縮したりヘッダを付けたりするのが保存形式です。bmp ならほとんどそのまま保存しますし、png なら可逆的に、jpeg なら非可逆的に圧縮して保存します。

ということは、bmp形式をデコードする場合、pngやjpegに比べて、デコードの処理が速いと考えても良いのでしょうか。
これは試してみたいと思います。
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -