• ベストアンサー

VB.NETにおける二値化処理の高速化

いつも参考にさせて頂いております。 現在、VB.NET(VS2003/.NET Framework1.1)を使用して画像の二値化処理のプログラムを作成しております。 処理する事は簡単で、ビットマップファイルのRED要素を取り出し、閾値内なら白に変換して二値化するプログラムです。 以下がそのプログラムです。 ----- '変換する前の画像をファイルから読み込む Dim img1 As System.Drawing.Bitmap = New System.Drawing.Bitmap(filepath) '変換後のビットマップ Dim img2 As System.Drawing.Bitmap = New System.Drawing.Bitmap(img1.Width, img2.Height) '二値化処理 Dim b As Byte For i = 0 To img1.Width - 1 For j = 0 To img1.Height - 1 b = img1.GetPixel(i, j).R If b >= 閾値下限 And b <= 閾値上限 Then img2.SetPixel(i, j, Color.White) Else img2.SetPixel(i, j, Color.Black) End If Next Next PictureBox1.Image = img ----- これで処理は出来るのですが、ファイルが大きい場合は、非常に時間が掛かってしまいます。処理速度はCPUの速度にもよると思うのですが、できるだけ高速化したのですが、何かよい知恵があればご教授頂けると助かります。よろしくお願いいたします。 XP Pro SP2/VS2003/VB.NET/.NET Framework1.1

質問者が選んだベストアンサー

  • ベストアンサー
回答No.2

If b >= 閾値下限 And b <= 閾値上限 Then これを If b >= 閾値下限 AndAlso b <= 閾値上限 Then に変えてみる。 If 条件A And 条件B では、必ず条件A と条件B を演算してしまうが、 If 条件A AndAlso 条件B では、条件A が False なら条件B の演算は行わない。

tatumi4
質問者

お礼

早速の回答、ありがとうございます。 AndSlsoと言うキーワードがある事すら知りませんでした。 非常に有益な情報をありがとうございます。 すぐにFalseになる可能性が高い条件を最初に持ってきてAndAlsoに変更して検証してみます。

その他の回答 (1)

  • sgwjn
  • ベストアンサー率70% (47/67)
回答No.1

どこまで効果があるかはわかりませんが、以下の部分を変更すると多少高速になるかもしれません。 (1)i, j がInteger型の場合は、Long型に変更する (2)ループ処理の縦横の参照順を入替える (3)閾値判定を AND から OR に変更する (4)img2を作成せず、img1を書換える (5)(4)を前提に、With~End With を使用する (1)は、CUPが32bitの場合は、多少高速になります。 (2)は、VB.netの配列のメモリ上の配置がどうなっているか知りませんが、A(x1, y1, z1)、A(x2, y1, z1)、A(x3, y1, z1)の順に配置されていれば、メモリの参照が高速になります。そうでなければ遅くなります。 (3)は、 if b >= 閾値下限 And b <= 閾値上限 Then  img2.SetPixel(i, j, Color.White) Else  img2.SetPixel(i, j, Color.Black) End If の部分を、 if b < 閾値下限 Or 閾値上限 < b Then  img2.SetPixel(i, j, Color.Black) Else  img2.SetPixel(i, j, Color.White) End If とし、尚且つ、 if b < 閾値下限 Or 閾値上限 < b Then の判定の1つ目の条件に成立する可能性が高い条件を持ってきます。上記の例では、閾値上限 < b よりも b < 閾値下限 の方が成立しやすいと仮定しています。 これは、2つ目の判定条件をなるべく判定させないようにするためです。 (4)は、ファイルサイズが大きくなると遅くなるというのは、反復回数が増えることが主原因だと思いますが、データ量が多すぎてスワップが発生しているということもあるかもしれません。処理中に保持するデータ量を減らせばスワップが発生しにくくなり、高速になるかもしれません。 (5)はうろ覚えですが、(4)でインスタンスを img1 のみとした後で、2つのFor文を With img1 ~ End With で囲むと、インスタンスの参照回数が減って高速になるような気がします。 高速化は、やってみないと分からない部分もありますので、断定的なことは書けませんが、もし良ければお試しください。

tatumi4
質問者

お礼

早速のアドバイスに感謝しております。 (1)は直ぐに実践してみます。 (2)も試して検証をしてみます。 (3)はAndAlsoを使用して2つ目の条件を判定しないように工夫してみます。 (4)はimg1を後で使用するので今回は実践できませんが、他で応用ができます。 (5)も試して検証をしてみます。 確かに高速化は試行錯誤の繰り返しだと思いますので、色々と試してみて活路を見出すしかないですね。 今回は、有益なヒントを頂き、ありがとうございました。

関連するQ&A

  • VB2005での画像処理

    各ピクセルの色情報を取得し,そのままコピーするプログラムです. 同じ大きさのPictureBox1とPictureBox2,それとButton1があります. エラーや警告は出ませんが,Button1をクリックしてもまったく動きません. 最終的にはPictureBox1を画像処理してPictureBox2に結果を表示させたいのですが,そのままコピーも出来ないため原因を探しています. A = picture1.GetPixel(i, j).ToArgb() picture2.SetPixel(i, j, color.FromArgb(A)) ではだめなのでしょうか.ご教授ください. -----以下プログラム------ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim i As Integer Dim j As Integer Dim A As Integer Dim picture1 As New Bitmap(PictureBox1.Image) Dim picture2 As New Bitmap(PictureBox2.Image) For j = 0 To PictureBox1.Width - 1 For i = 0 To PictureBox1.Height - 1 A = picture1.GetPixel(i, j).ToArgb() picture2.SetPixel(i, j, color.FromArgb(A)) Next Next End Sub

  • VB.NET2003とVB.NET2005の処理速度について

    お世話になります。VB.NET2003,2005の処理速度・処理方法について分かる方がいましたら、教えていただきたく質問します。 もともとVB.NET2003で作成されていたプログラムをVB.NET2005に変換して実行した所、ある処理が元の10倍ぐらい遅くなってしまいました。 コードはRadioボタンを動的に作成してPanelにAddして表示する簡単な物です。 以下にコードを乗せます。 For i as integer = 0 to 99 Dim redio As New System.Window.Forms.RadioButton redio.Size = New System.Drawing.Size(120, 40) redio.Top = 8 + (57 * x) redio.Left = 8 + (137 * y) redio.Appearance = Appearance.Button redio.AutoCheck = False 'フォント関連の設定 redio.TextAlign = ContentAlignment.MiddleCenter redio.Font = New System.Drawing.Font(redio.Font.FontFamily, 17.25!, FontStyle.Bold) redio.BackColor = System.Drawing.SystemColors.Control redio.Name = "Check-" & i redio.Text = i.ToString() redio.Visible = True AddHandler redio.Click, AddressOf RadioButton_Click ’※※↓の処理が遅くなった Me.PanelRackControl.Controls.Add(redio) redio = Nothing If y = 4 Then x += 1 y = 0 Else y += 1 End If Next 2003から2005で遅くなるものなのか、処理が悪いのか分かる方がいらっしゃいましたらご教授下さい。 宜しくお願いします。

  • 8bit(256色)グレースケール画像の保存

    32bitのRGB画像ではなく、8bitのグレースケール画像を保存したいと考えています。 保存形式は、tiffとbmpのどちらでも構いません。 ですが、以下のような方法では、 アルファチャンネルを含んだ32bitのRGB画像が保存されてしまいます。 (作成中のプログラムの一例)    Dim img As Bitmap    Dim x As Integer    Dim y As Integer    img = New Bitmap(256, 50)    For x = 0 To 255       For y = 0 To 49          img.SetPixel(x, y, Color.FromArgb(x, x, x))       Next    Next    img.Save("gradation.tif", System.Drawing.Imaging.ImageFormat.Tiff) なお、一例として単純なグラデーション画像を保存していますが、 あくまでも一例であり、グラデーション画像を作成することが目的ではありません。 最終的には、VisualBasicのBitmapクラスで作成したbitmap画像を Photoshopで、8bitのグレースケール画像として開けることが理想です。 どうか、アドバイスをよろしくお願い致しますm(__)m

  • VB6のTYPE文をVB.NETのStructureに変えるとき

    VB6のTYPE文をVB.NETのStructureに変えるとき 下記VB6のコードをVB.NETのStructureに変える場合 Type kouzou1 i As Integer j As Integer a As String * 20 b As String * 50 End Type を下記にしてみたのですが *20,*50のところは、どのように表現するのでしょうか。 Structure kouzou1 Dim i As Integer Dim j As Integer Dim a As String * 20 <- ステートメントの終わりを示してくださいのエラーになる。 Dim b As String * 50 <- ステートメントの終わりを示してくださいのエラーになる。 End Structure お教え下さい。

  • VB.netでのPictuerBoxに描写した内容の保存について。

    VB.netでのPictuerBoxに描写した内容の保存について。 PictureBoxに描写した内容を保存してみると、描写した項目事態は正しく保存されているのですが、背景が真っ黒になってしまいますこれは、なぜなのでしょうか? ソースは以下の様な感じです。 Dim bmp As Bitmap Dim g As Graphics bmp = New Bitmap(PictureBox1.Width, PictureBox1.Height) PictureBox1.Image = bmp g = Graphics.FromImage(PictureBox1.Image) g.DrawLine(Pens.AliceBlue, 0, 10, 20, 10) PictureBox1.Refresh() PictureBox1.Image.Save("test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg) どなたかわかる方よろしくお願いいたします。

  • VB.NETでのPictureBoxによる画像保存について

    またお世話になります。 VB.NETでプログラムでPictureBoxに絵を描かせているのですが、そこまでは表示させることができました。このできた画像をBitmapなりjpegなりに保存させて、ほかの画像ビューワ等でも見れる形にしたいのですがうまくいきません。 ちなみに今はこのように書いて、 Dim gra1 As Graphics = PictureBox1.CreateGraphics FileOpen(2, myfile2, OpenMode.Output) (絵を描かせるプログラム) PictureBox1.Image.Save(myfile2, System.Drawing.Imaging.ImageFormat.Bmp) FileClose(2) としてまわしたところ、 System.Runtime.InteropServices.ExternalException' のハンドルされていない例外が system.drawing.dll で発生しました。 追加情報 : GDI+ で一般的なエラーが発生しました。 といわれました。 どなたかご教授いただけたらお願いしますm(__)m

  • 動的に画像を作成し保存するには?

    Visual Basic 2012を使用しています。 下記プログラムを実行するとエラーが表示されてしまいます。 Dim img As New Bitmap(200, 100) Dim g As Graphics = Graphics.FromImage(img) g.FillRectangle(Brushes.Black, g.VisibleClipBounds) g.Dispose() PictureBox1.Image = img img.Save("E:\EPUB_test\test.jpg", System.Drawing.Imaging.ImageFormat.Jpeg) img.Dispose() 表示されるエラーは下記です。 型 'System.ArgumentException' のハンドルされていない例外が System.Drawing.dll で発生しました どこが間違っているのでしょうか? 正しく動作させるにはどこを修正すべきかをお教え下さい。

  • [VB.NET] 処理の高速化を行いたい。

    教えて下さい。 あるファイルの1バイトづつローテートを行いファイルの書き出しを行っています。(ビット演算による暗号化) しかし以下の処理の場合、サイズの大きいファイルを扱った場合に多くの処理時間がかかってしまいます。 もっと処理を高速化する事は可能でしょうか? ----------------------------------------------------------------- ' 読み込みファイル Private Const READ_FILE As String = "c:\temp\date.Text" ' 書き込みファイル Private WRIT_FILE As String = "c:\temp\date.dat" ' オブジェクト作成 Dim br As New System.IO.FileStream(READ_FILE, IO.FileMode.Open, IO.FileAccess.Read) Dim bw As New System.IO.StreamWriter(WRIT_FILE, False, System.Text.Encoding.GetEncoding("iso-8859-1")) Dim m As Integer = 3 ' 3ビット左回転 Dim n As Integer ' 1バイトづつ処理 For I As Integer = 0 To CType(br.Length, Integer) - 1 ' 16進数を10進数へ変換 n = ("&h" & String.Format("{0:X2}", br.ReadByte)) ' mビット左へローテート処理を行いファイルへ書き込み bw.Write(ChrW("&h" & Hex(Int((n / 2 ^ (8 - m)) + (n * 2 ^ m And 255))))) Next ' 閉じる bw.Close() br.Close() ----------------------------------------------------------------- よろしくお願いします。

  • VB.NETのことで困っています。

    VB.NETのプログラムで白黒判別プログラムを作成することになったのですが、GetPicxelの使い方が間違っているらしく正しくカウントしてくれません。 ちなみに今作成している問題のプログラムは以下のプログラムです。 Function CountNumColor(ByRef DotWW As Long, ByRef DotHH As Long, ByRef CHECK_C As Long) As Integer Dim Form1 As Object Dim NumEQ As Double Dim NumNot As Long Dim x, y As Long NumEQ = 0 NumNot = 0 System.Windows.Forms.Application.DoEvents() For x = 0 To DotHH - 1 For y = 0 To DotWW - 1 System.Windows.Forms.Application.DoEvents() If CHECK_C = Val("Bitmap.GetPixel(x,y)") Then NumEQ = NumEQ + 1 Else NumNot = NumNot + 1 Debug.Write("x,y,Val(Bitmap.GetPixel(x, y)") End If Next y Next x CountNumColor = NumEQ End Function このプログラムで問題がありましたらぜひとも教えてください。GetPicxel以外の間違いに気づいた人がいた場合もご意見をお待ちしております。また、この質問で分からないことがございましたら遠慮なく書き込んでください。気づき次第返答いたします。

  • VB2005 でビットの深さ8の画像を処理したい。

    VB2005を使って簡単な画像処理のツールを制作しています。 処理内容は、画像ファイル(jpg)を読み込み、画像を縦に区切って 左側と右側を別のファイルに保存する、という処理です。 縦に区切る位置(x 座標)は、自由に指定できます。 上記のような処理を「任意の解像度(0~300 dpi)、ビットの深さ 8 」 の画像で行うには、どのようにしたらよいのでしょうか。 (ビットの深さ 8 の image からは Graphics オブジェクトを  作ることができず、そのため、読み込んだ画像の解像度を  保てませんでした。) ビットの深さが 24 の画像は、以下のようにして問題なく動きました。 "scanfile01.jpg" は、 解像度 300dpi / ビットの深さ 24 / 縦1500 × 横1200 ピクセル の画像ファイルです。 --------------- private sub splitImage()  '画像(src)の読み込み  Dim fs As New IO.FileStream("scanfile01.jpg", _     IO.FileMode.Open)  Dim src As Image = Image.FromStream(fs, False, False)  Dim srcG As Graphics = Graphics.FromImage(src) '解像度の取得用  'src を分割する位置(x座標)  '(横幅1500 の scanfile01.jpg を左右半分に分ける)  Dim cutx As Integer = 750   'src の左側を格納する Bitmap を新規作成  '(src の解像度を引き継ぐ)  Dim destLeft As Image = New Bitmap(cutx, src.Height, srcG)  Dim rect As New Rectangle(0, 0, cutx, src.Height)  Dim destLeftG As Graphics = Graphics.FromImage(destLeft)  Dim rect As New Rectangle(0, 0, cutx, src.Height)  destLeftG.DrawImage(src, 0, 0, rect, GraphicsUnit.Pixel)  'src の左側をファイルに保存  destLeft.Save("scanfile01-left.jpg" _         , System.Drawing.Imaging.ImageFormat.Jpeg)  destLeft.Dispose()  destLeftG.Dispose()  'src の右側を格納する Bitmap を新規作成  ~省略~  srcG.Dispose()  src.Dispose()  fs.Dispose() End Sub ---------------- ビットの深さ 8 の画像を読み込むと、実行時に  Dim srcG As Graphics = Graphics.FromImage(src) '解像度の取得用 の部分で「インデックス付きのピクセルから Graphics オブジェクトを作成できません」というエラーが発生します。 そこで、解像度は引き継がずに、以下のように変更してみました。 ・srcG の定義文を削除 ・destLeft の定義時に解像度は指定せず、以下のように変更   Dim destLeft As Image = New Bitmap(cutx, src.Height) すると、エラーは発生せずファイルが作成されましたが、 解像度が引き継がれずに元の画像よりずっと小さな画像になって 作成されていました。 (作成されたファイルを開くと、イメージが小さくなった分、  黒い隙間ができていました。) 300 dpi の画像を読み込んだので、VB2005 で作成される?Bitmap のデフォルトの解像度 96 dpi に変換される際にピクセル抜けが 発生して画像が小さくなったのだと思います。 ビットの深さ 8 の画像を半分に区切ってファイルに保存する方法は ないのでしょうか。また、任意の解像度でピクセル抜けが 発生しないようにしたいです。

専門家に質問してみよう