質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.35%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Q&A

解決済

1回答

2662閲覧

System.Drawing 8bit Bitmapの描画・出力が崩れてしまう問題について

hibin0bin0

総合スコア2

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

0グッド

0クリップ

投稿2021/01/10 13:12

編集2021/01/10 13:47

前提・実現したいこと

音声波形をFFTで周波数を解析し、その情報を8bitグレースケールの画像として保存することが当初の目的ですが、
32bit bitmapでSetPixelを用いて描画した際は想定通りに出力できたものが
8bit bitmapで実装した際にどうしても画像が崩れてしまうため、
挙動を確かめようとしたところ想定の結果とかなりピクセルが
ずれて描画されていることがわかりました。

発生している問題・エラーメッセージ

「画像の上半分をグレーに、下半分を真っ黒に塗る」ものを組んだはずが
「下半分だけ黒塗りになるはずの画像が、黒塗り部分が少しずれて出力される問題」についての解決策を
お伺いしたいです。

※ネット上での検索は試行済みで、解決につながる情報を捕捉できませんでした。
※32あるいは24bit bitmapで作成してから8bitに変換、などは避け、
なるべく自前のバイト配列から8bit画像を出力する方向性を保ちたいです。

該当のソースコード

Windows Forms上で組んだものから抜粋します。

C#

1//8bit グレースケール 2bitmap = new Bitmap(78, 256, PixelFormat.Format8bppIndexed); 3byte[] res = new byte[bitmap.Width * bitmap.Height]; 4 5//パレット設定、白黒反転 6var palette = bitmap.Palette; 7for (int p = 0; p < 256; p++) 8{ 9 palette.Entries[p] = Color.FromArgb(255 - p, 255 - p, 255 - p); 10} 11bitmap.Palette = palette; 12 13//画像の下半分が真っ黒になるはず 14for (int y = 0; y < res.Length; y++) 15{ 16 if (y > res.Length / 2) res[y] = 255; 17 //追記:グレーにする処理を忘れてました 18 else res[y] = 128; 19} 20 21//byte情報流し込み 22BitmapData bmpdata = bitmap.LockBits( 23 new Rectangle(0, 0, bitmap.Width, bitmap.Height), 24 ImageLockMode.WriteOnly, 25 PixelFormat.Format8bppIndexed 26 ); 27 28Marshal.Copy(res, 0, bmpdata.Scan0, res.Length); 29bitmap.UnlockBits(bmpdata); 30 31bitmap.Save($"chunk.png", ImageFormat.Png); 32bitmap.Dispose();

試したこと

bitmapの横サイズを2の累乗にするとピッタリ半分に分かれて色が塗られていそうなことを確認しました。
右の失敗例では黒塗が半分より少し前からずれて始まっており、一番下に白い部分が余っています。

例:左・タテヨコ256px 右・ヨコ78px * タテ256px
イメージ説明  イメージ説明

補足情報(FW/ツールのバージョンなど)

C# Visual Studio 2019

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

Marshal.Copy(res, 0, bmpdata.Scan0, res.Length);

これ、バイトデータをそのまんまコピーしてますが、
コピー先の1ピクセルは1バイトではないのでは?

投稿2021/01/10 13:32

y_waiwai

総合スコア88042

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

hibin0bin0

2021/01/10 13:53

>コピー先の1ピクセルは1バイトではないのでは? 8bit画像で、色は指定通り、256四方の画像ではピクセルの位置も想定通りに出ているので1byteよさそうだと思うのですが、たしかに確認してませんでした。見てみます
y_waiwai

2021/01/10 13:57

それと、BMPではたしか、1ラインの先頭オフセットは4バイトアライメントされるってこともあるので、そこんところも確認してみてください
hibin0bin0

2021/01/10 14:08

>1ラインの先頭オフセットは4バイトアライメントされる このキーワードで検索したところ、strideというパラメーターにあたりました! これが答えになりそうなのでこれから詳しく確認してからお返事いたします。
hibin0bin0

2021/01/10 14:30

確認しました。 bitmapデータは1pxの行の情報量はかならず4バイトの倍数で、 ①これまでは偶然4の倍数ではない横幅で画像の出力を検証していたためにpxのズレが発生していた ②32bit画像はそもそも1pxが4バイトのため問題なかった ということが理解できました。 質問に書いたプログラムも、配列の要素数を[画像横幅を超える4の倍数のpx] * [縦幅px]にすることで 78px幅でもしっかり半分にわけて黒く塗れていることが確認できたので 当初のFFT出力に生かすことができると思います、ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.35%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問