バイナリデータをビットマップ形式の画像にするには?

解決


初心者  2008-11-05 18:48:00  No: 32468  IP: 192.*.*.*

バイナリデータをビットマップに必要な8ビット形式(256階調)に直すことはできたのですが、このデータをビットマップ形式で画像表示することができません。
方法を教えていただけるとありがたいです。
よろしくお願いします。

編集 削除
junki  2008-11-05 19:10:33  No: 32469  IP: 192.*.*.*

縦横が同じ TBitmap を Create し PixelFormat を pf8bit にセットしてから、ScanLine を利用してデータを書き込み、グレイスケールのパレットをセット
します。これで作成したビットマップを普通に表示できるでしょう。

パレットのセットの例は

http://junki.lix.jp/delphigr/009SetPaletteEntries.htm

にあります。ここで紹介しているライブラリの TBmpData8 を使えば高速に
書き込みできるでしょう。

編集 削除
ウォレス  2008-11-06 10:56:12  No: 32470  IP: 192.*.*.*

初心者の方ならば、先ずはわかりやすいPixelsプロパティを使って様子をみてはどうでしょう?
例えば、

Image1.canvas.Pixels[x,y] :=RGB(r,g,b);

x,y:座標
r,g,b:画素の各色データ(8bit)

です。先ずは r=g=b でその8bitデータを書き込んでみては?
それで過不足無ければそのままでもよいし、実行速度に不満があれば(Pixelsはめっちゃ遅い)ScanLineを使って一歩上を目指せばよいし。

編集 削除
初心者  2008-11-06 12:25:51  No: 32471  IP: 192.*.*.*

ご回答ありがとうございます。
初心者ですのでPixelsプロパティを使用したのですが、
斜めに線が一本入るだけで画像にできません。
J:=0にしたら一列だけはできるのですが、一ライン312ピクセルの、二列目以降がうまくいかない状態です。
inc(i)では二列目以降はできないのでしょうか?
他の方法を教えていただけるとありがたいです。

procedure TForm1.Button2Click(Sender: TObject);
var
   data : WORD;
   cnt: WORD;
   buff:WORD;
   i,j: WORD;
begin
  i :=0 ;
  j :=0 ;
  with TFileStream.Create('ファイル名', fmOpenRead) do try
  
   while True do begin
    cnt := Read(data, Sizeof(data));
    if cnt < Sizeof(data) then break;

    buff:=trunc(data/16);  //12ビットのデータを8ビットに
    if buff>255 then  buff:=255;
     begin
     Image1.Canvas.Pixels[i,j]:=RGB(buff,buff,buff);
     end;
   inc(i) ;
   inc(j) ;
  end;
  finally
   Free;
  end;

end;

編集 削除
ウォレス  2008-11-06 12:41:50  No: 32472  IP: 192.*.*.*

iとjを同時にカウントアップしたら必ず右下がりの直線が描けます^^;

Inc(j);

ではなく、

if i=311 then
begin
  Inc(j);
  i := 0;
end;

とでもすればいいのかしら・・・
ここは素直にforの2重ループで書くのがベターです。

編集 削除
初心者  2008-11-06 15:47:15  No: 32473  IP: 192.*.*.*

ループ関数を初めに試したのですが
  for i := 0 to 311 do
  for j := 0 to 239 do 
としたら
止まってしまいましたw

重いからでしょうか?

編集 削除
ウォレス  2008-11-06 17:37:05  No: 32474  IP: 192.*.*.*

「止まって」とはどのような状態ですか?正確な表現をしてください。
アプリケーションが落ちるのか、OS自体が落ちるのか、あるいはエラーメッセージが出るのか。

312x240程度なら、恐らく0.5秒もかかりません。(CPUによりますが)
重いからということはないと思います。

編集 削除
初心者  2008-11-06 17:58:51  No: 32475  IP: 192.*.*.*

プロジェクトが応答なしの状態になるんです。

     for i := 0 to 311 do
     for j := 0 to 239 do
     begin
    Image1.Canvas.Pixels[i,j]:=RGB(buff,buff,buff);
     end;

このような関数ではだめなのでしょうか?

編集 削除
初心者  2008-11-06 17:58:54  No: 32476  IP: 192.*.*.*

プロジェクトが応答なしの状態になるんです。

     for i := 0 to 311 do
     for j := 0 to 239 do
     begin
    Image1.Canvas.Pixels[i,j]:=RGB(buff,buff,buff);
     end;

このような関数ではだめなのでしょうか?

編集 削除
ウォレス  2008-11-06 18:54:34  No: 32477  IP: 192.*.*.*

再現できるコードをきちんと載せる、かつ誰でも試せる状態を用意する。
これをクリアしない限り、貴方のプロジェクトが何故破綻するのかを指摘するのは難しいと思いますよ。

>このような関数ではだめなのでしょうか?
貴方自身で上記のコードを新プロジェクトに貼って試してみればわかります。
この6行のコード自体には特に問題はありません。

「問題の切り分け」というのは大事なことです。
きちんと押さえましょう。

※もしかして時間がかかっているだけかも^^;
今試してみたら0.35秒くらいかかってます。
(Core2Quad 2.8G)

編集 削除
初心者  2008-11-07 10:10:37  No: 32478  IP: 192.*.*.*

ご指摘ありがとうございます。以後気をつけます。
エラーで二回送信されたのも申し訳ないです。

コードは以下のようにして再度試したのですがやはりプロジェクトが応答しない状態になってしまいました。CPU使用率100%でした。
XPでintelのceleronです。

この場合、やはりコードがどこかおかしいのが疑われると思うのですが。
以下にコードを貼り付けます。
たびたびすみませんが、指摘いただけるとありがたいです。

procedure TForm1.Button2Click(Sender: TObject);
    
var
   data : WORD;
   cnt: WORD;
   buff:WORD;
   i,j: WORD;
begin
  with TFileStream.Create('ファイル名', fmOpenRead) do try
   // 2Byte単位で読み込み
   // Position := 0;

     while True do begin
    cnt := Read(data, Sizeof(data));
    if cnt < Sizeof(data) then break;

    buff:=trunc(data/16);
    if buff>255 then  buff:=255;
        //12bitから8bitに変換

     for i := 0 to 311 do
     for j := 0 to 239 do
     begin
      Image1.Canvas.Pixels[i,j]:=RGB(buff,buff,buff);
     end;
end;
  finally
   Free;
  end;

end;

編集 削除
ウォレス  2008-11-07 10:46:25  No: 32479  IP: 192.*.*.*

明らかにforのループの括りが間違っています。
これではデータ1つ読む度に全画面をそのデータでベタ塗り(しかも遅いPixelsで)し、そのベタ塗りをデータ数だけ繰り返していませんか?

動きそうな感じで書いてみました。いろいろ細かく変更してます。参考にしてください。

procedure TForm1.Button2Click(Sender: TObject);
var
  data: ShortInt;  //8bit単位にしている(注意)
  cnt: Integer;
  buff: Integer;
  i, j: Integer;
  fs: TFileStream;
  breakflag: BOOL;
  t1, t2: Cardinal;
begin

  t1 := GetTickCount;

  fs := TFileStream.Create('C:\WINDOWS\シャボン.bmp', fmOpenRead); //私のPCにはある。貴方のPCには無いかもしれない。

  try

    breakflag := false;
    fs.Position := 440 * Sizeof(data); //ヘッダ読みとばし(注意)

    for i := 0 to 255 {311} do   //注意
    begin

      for j := 0 to 255 {239} do //注意
      begin

        cnt := fs.Read(data, Sizeof(data)); //8bit単位(注意)

        if cnt < Sizeof(data) then
        begin
          breakflag := true;
          break;
        end;

        buff := data * 4; //ここも適当に正規化(注意)

        if buff > 255 then
          buff := 255;

        Image1.Canvas.Pixels[i, j] := RGB(buff, buff, buff);

      end;

      if breakflag = true then
        break;

    end;
    t2 := GetTickCount;

    Label1.Caption := IntToStr(t2 - t1 )+'ms';

  finally
    fs.Free;
  end;

end;

編集 削除
初心者  2008-11-07 11:44:05  No: 32480  IP: 192.*.*.*

ありがとうございます!!!
8bitで読み込んでいるところを変更して、
適当に計算式で正規化させればいいのですね。
うまくいきそうです^^;

本当に感謝です。丁寧なご指導ありがとうございました。

編集 削除