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

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

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

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

Q&A

解決済

1回答

752閲覧

二値画像で白のみの画像を高速に判定したい

xail2222

総合スコア1497

C#

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

.NET Framework

.NET Framework は、Microsoft Windowsのオペレーティングシステムのために開発されたソフトウェア開発環境/実行環境です。多くのプログラミング言語をサポートしています。

0グッド

0クリップ

投稿2022/04/20 21:43

編集2022/04/21 12:29

質問内容

二値画像で白のみの画像を高速に判定したい。
どのようにすればよいのでしょうか。

現状

現在のコード

C#

1 public static bool checkWhite(string path) 2 { 3 Bitmap img = new Bitmap(path); 4 bool flg=false; 5 for (int x = 0; x < img.Width; x++) 6 { 7 for (int y = 0; y < img.Height; y++) 8 { 9 Color c = img.GetPixel(x, y); 10 if(c.R !=255 || c.G != 255 || c.B != 255) 11 { 12 flg = true; 13 break; 14 } 15 } 16 if (flg) { break; } 17 } 18 19 //ロックを解除する 20 img.Dispose(); 21 return !flg;

これで一応は判定できています。
ただ、これだと遅いので早くしたいと考えています。

ネットで調べた所、以下のようなコードでどうにか早く出来るかもと思ったのですが

C#

1 PixelFormat pixelFormat = img.PixelFormat; 2 int pixelSize = Image.GetPixelFormatSize(pixelFormat); 3 if (pixelSize != 1) 4 { 5 throw new ArgumentException( 6 "1ピクセルあたり1ビットの形式のイメージのみ有効です。", 7 "img"); 8 } 9 10 //Bitmapをロックする 11 BitmapData bmpData = img.LockBits( 12 new Rectangle(0, 0, img.Width, img.Height), 13 ImageLockMode.ReadWrite, 14 pixelFormat); 15 16 unsafe 17 { 18 byte* pixelPtr = (byte*)bmpData.Scan0; 19 // どうしたらいいのかわかりません。 20 } 21 22 //ロックを解除する 23 img.UnlockBits(bmpData);

どうしたらいいのかわかりません。

pixelPtr がバイト配列?で、8ピクセル分ずつ入っていると思うのですが
どう入っているかがよくわかっていません。
とりあえず、白だけの画像を読み込ませると
pixelPtr の前の方は255だったのですが
改行の辺りで255以外の値が入っていました。

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

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

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

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

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

dodox86

2022/04/21 00:30

少なくとも、 > if(c.R !=255 || c.G != 255 || c.B != 255) > { > flg = true; > break; > } 白以外の画素を検出してもimg.Widthのループを無用に続行していますね。
xail2222

2022/04/21 00:38 編集

確かに。 指摘ありがとうございます。 帰宅後質問のコードも修正しておきます
episteme

2022/04/21 00:43 編集

> とりあえず、白だけの画像を読み込ませると > pixelPtr の前の方は255だったのですが > 改行の辺りで255以外の値が入っていました。 食わせた画像の幅(横pixel数)が8の倍数でなかったらそうなるのでは?
xail2222

2022/04/21 00:58

横のピクセル数は確認しなおします。1000だった気がしてます。 しかし、もしかしてy座標が変わるところで何かデータが入っていて それを含めたデータ幅がStrideなのでしょうか。
episteme

2022/04/21 03:10 編集

↑YES. 切りのいい横幅にしてパフォーマンスを上げるため、 末尾には適当に"埋め草(padding)"が挿入されます。 たとえば画像の横幅が1000だとすると125byte(1pix=1bitなら)、 これをたとえば切りのいい128byteにすべく、3byteの埋め草が入ったりとか。
xail2222

2022/04/22 18:32

コメントありがとうございました。 お陰でStrideの意味がわかりました。
guest

回答1

0

自己解決

何とかかけたので、自己回答します。

C#

1 public static bool checkWhite(string path) 2 { 3 Bitmap img = new Bitmap(path); 4 5 //1ピクセルあたりのバイト数を取得する 6 PixelFormat pixelFormat = img.PixelFormat; 7 int pixelSize = Image.GetPixelFormatSize(pixelFormat); 8 if (pixelSize != 1) 9 { 10 throw new ArgumentException( 11 "1ピクセルあたり1ビットの形式のイメージのみ有効です。", 12 "img"); 13 } 14 15 bool flg = false; 16 17 //Bitmapをロックする 18 BitmapData bmpData = img.LockBits( 19 new Rectangle(0, 0, img.Width, img.Height), 20 ImageLockMode.ReadWrite, 21 pixelFormat); 22 23 byte[] footers = new byte[] {0, 128, 128 + 64, 128 + 64 + 32, 128 + 64 + 32 + 16, 128 + 64 + 32 + 16 + 8, 128 + 64 + 32 + 16 + 8 + 4, 128 + 64 + 32 + 16 + 8 + 4 + 2, 128 + 64 + 32 + 16 + 8 + 4 + 1 }; 24 int a,rem; 25 26 a = Math.DivRem(bmpData.Width, 8, out rem); 27 28 byte footer = footers[rem]; 29 30 unsafe 31 { 32 byte* bytePtr = (byte*)bmpData.Scan0; 33 for (int y = 0; y < bmpData.Height; y++) 34 { 35 // 8ピクセルずつチェックする 36 for (int x = 0; x < a; x++) 37 { 38 int pos = y * bmpData.Stride + x; 39 if (bytePtr[pos] != 255) 40 { 41 flg = true; 42 break; 43 } 44 } 45 if (flg) { break; } 46 // 8ピクセルに満たない最終バイトは、余りビット数分1が立っている事をチェック 47 if (rem > 0) 48 { 49 if (bytePtr[a] < footer) 50 { 51 flg = true; 52 break; 53 } 54 } 55 } 56 } 57 //ロックを解除する 58 img.UnlockBits(bmpData); 59 img.Dispose(); 60 return !flg; 61 } 62

1バイトずつチェックするようにしました。
Stride の意味が分かれば何とかかけました。
1バイトに満たない最後の端っこの処理があってるか心配ですが
だいたいはいけてると思います。

30分かかった処理が10秒で終わりました。

おかしい所とかあったらコメントなど頂けると幸いです。

投稿2022/04/21 12:39

xail2222

総合スコア1497

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問