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

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

新規登録して質問してみよう
ただいま回答率
87.20%
VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

解決済

VB.netでListViewに約4100枚のjpg画像ファイルを読み込んでサムネイルを表示しているが約6分かかるのでもっと早くしたい

tada_tadaa
tada_tadaa

総合スコア100

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

4回答

0評価

2クリップ

701閲覧

投稿2021/12/30 14:17

編集2021/12/31 01:34

VB.netでListViewに約4100枚のjpg画像ファイルを読み込んでサムネイルで表示しているのですが、ボタンを押してサムネイルが表示されるまで約6分間かかります。これをもっと早く読み込めるように改良したいのですがどうすればいいのかわかりません。画質は大幅に下がっても構いません。

使用しているパソコンのスペック
使用OS Windows10
メモリ 8GB
CPU   Intel Core i5-3230M 2.60GHz
処理の実行中は実行しているプロセスのCPU使用率が35パーセントぐらいになります。

ここを参考にしました

VB

Public Class Form1 ' 幅w、高さhのImageオブジェクトを作成 Function createThumbnail(ByVal image As Image, ByVal w As Integer, ByVal h As Integer) As Image Dim canvas As New Bitmap(w, h) Dim g As Graphics = Graphics.FromImage(canvas) g.FillRectangle(New SolidBrush(Color.White), 0, 0, w, h) Dim fw As Double = CDbl(w) / CDbl(image.Width) Dim fh As Double = CDbl(h) / CDbl(image.Height) Dim scale As Double = Math.Min(fw, fh) Dim w2 As Integer = CInt(image.Width * scale) Dim h2 As Integer = CInt(image.Height * scale) g.DrawImage(image, (w - w2) \ 2, (h - h2) \ 2, w2, h2) g.Dispose() Return canvas End Function ' ButtonのClickイベントのハンドラ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim imageDir As String = "C:\Users\user\Pictures" ' 画像ディレクトリ Dim jpgFiles As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg") Dim width As Integer = 100 Dim height As Integer = 80 ImageList1.ImageSize = New Size(width, height) ListView1.LargeImageList = ImageList1   Dim original As Image For i As Integer = 0 To jpgFiles.Length - 1 Try original = Bitmap.FromFile(jpgFiles(i)) Catch original = My.Resources.Resource1._error End Try Dim thumbnail As Image = createThumbnail(original, width, height) ImageList1.Images.Add(thumbnail) ListView1.Items.Add(jpgFiles(i), i) original.Dispose() thumbnail.Dispose() Next End Sub End Class

お手数をおかけしますがよろしくお願いいたします。

追記
コードの修正によって少し早くなったのでそれを追記します。
以下のコードでほぼ2分、メモリ使用量は250メガバイトほどに短縮できました。

VB

Public Class Form1 ' 幅w、高さhのImageオブジェクトを作成 Function createThumbnail(ByVal image As Image, ByVal w As Integer, ByVal h As Integer) As Image Dim canvas As New Bitmap(w, h) Dim g As Graphics = Graphics.FromImage(canvas) g.FillRectangle(New SolidBrush(Color.White), 0, 0, w, h) Dim fw As Double = CDbl(w) / CDbl(image.Width) Dim fh As Double = CDbl(h) / CDbl(image.Height) Dim scale As Double = Math.Min(fw, fh) Dim w2 As Integer = CInt(image.Width * scale) Dim h2 As Integer = CInt(image.Height * scale) g.DrawImage(image, (w - w2) \ 2, (h - h2) \ 2, w2, h2) g.Dispose() Return canvas End Function ' ButtonのClickイベントのハンドラ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim cnt As Integer = 0 Dim imageDir As String = "C:\Users\user\Pictures" ' 画像ディレクトリ Dim jpgFiles As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg") Dim width As Integer = 100 Dim height As Integer = 80 ImageList1.ImageSize = New Size(width, height) ListView1.LargeImageList = ImageList1 Dim thumbnail(jpgFiles.Length - 1) As Image Dim original As Image For i As Integer = 0 To jpgFiles.Length - 1 '①のブレイクポイントを置く Try original = Bitmap.FromFile(jpgFiles(i)) Catch original = My.Resources.Resource1._error End Try thumbnail(i) = createThumbnail(original, width, height) original.Dispose() Next ImageList1.Images.AddRange(thumbnail) '②のブレイクポイントを置く For i As Integer = 0 To jpgFiles.Length - 1 ListView1.Items.Add(jpgFiles(i), i) Next End Sub End Class

上記のコードでブレイクポイントを
①For i As Integer = 0 To jpgFiles.Length - 1
の部分と
②ImageList1.Images.AddRange(thumbnail)
の部分に置いてみて時間を計測したところ、Button1を押してから①の部分までで約1秒かかりました。
次に①から②の所までは1分38秒かかりました。次に②から最後まで走らせたら22秒かかりました。
全体で約2分かかってますが、①から②までのサムネイルを作成する処理に時間がかかっているようです。
作ったサムネイルをImageList1に追加するのとListView1.Items.Addの部分で22秒なので、サムネイルを作成する部分をもっと改善出来れば早くなると思います。

それと作っている物ですが
「Visual Studio 2017」でプロジェクトの作成は「Visual Basic」の「Windowsフォームアプリケーション(.Net Framework)」を選択してプロジェクトを作成しています。どのような目的の物を作るかというと、jpg画像ファイルビューワーです。まずディレクトリを選択してそこにある画像ファイルの一覧をサムネイルで表示して、サムネイルのどれかをダブルクリックすると別ウィンドウでその画像が拡大表示されるといったものです。

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

vann_2921

2021/12/30 15:05

thumbnailを配列に保存しておいてForを抜けてからImageList1.Images.AddRangeで追加したら何か変わりますかね?
vann_2921

2021/12/30 15:35

手元の環境で試してみたのですが、ListViewの描画の遅さが原因のようでこれを解決するのは難しいかと思われます。軽くする方法としてListViewには仮想モードというのがあるようなので調べてみてください。 ちなみにそのサムネイルは絶対に4100枚同時に表示しないといけないものでしょうか?
tada_tadaa

2021/12/30 15:59

コメントありがとうございます。 >thumbnailを配列に保存しておいてForを抜けてからImageList1.Images.AddRangeで追加したら何か変わりますかね? 以下のように変更してみて試してみましたが、実行プロセスがメモリを4Gバイト以上消費して、途中でエラーで(おそらくメモリオーバーだと思います)止まってしまいました。 ' ButtonのClickイベントのハンドラ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim cnt As Integer = 0 Dim imageDir As String = "C:\Users\user\Pictures" ' 画像ディレクトリ Dim jpgFiles As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg") Dim width As Integer = 100 Dim height As Integer = 80 ImageList1.ImageSize = New Size(width, height) ListView1.LargeImageList = ImageList1 Dim thumbnail(jpgFiles.Length) As Image Dim original As Image For i As Integer = 0 To jpgFiles.Length - 1 Try original = Bitmap.FromFile(jpgFiles(i)) Catch original = My.Resources.Resource1._error End Try thumbnail(i) = createThumbnail(original, width, height) Next For i As Integer = 0 To jpgFiles.Length - 1 ListView1.Items.Add(jpgFiles(i), i) Next ImageList1.Images.AddRange(thumbnail) End Sub >ListViewには仮想モードというのがあるようなので調べてみてください。 調べてみようと思います。ただ今日は遅いので明日調べる事になると思います。 >ちなみにそのサムネイルは絶対に4100枚同時に表示しないといけないものでしょうか? 絶対にというわけではないです。例えば、先頭の画像ファイル千枚を読み込んだ時点でListViewにサムネイルで表示して、バックグラウンドでは残りの三千枚を処理して、順番に処理が終わった画像ファイルからListViewに追加していくというふうに、同時にではなく、時間をずらしても大丈夫です。
tada_tadaa

2021/12/30 16:43

以下のコードでほぼ2分、メモリ使用量は250メガバイトほどに短縮できました。 ' ButtonのClickイベントのハンドラ Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click Dim cnt As Integer = 0 Dim imageDir As String = "C:\Users\user\Pictures" ' 画像ディレクトリ Dim jpgFiles As String() = System.IO.Directory.GetFiles(imageDir, "*.jpg") Dim width As Integer = 100 Dim height As Integer = 80 ImageList1.ImageSize = New Size(width, height) ListView1.LargeImageList = ImageList1 Dim thumbnail(jpgFiles.Length - 1) As Image Dim original As Image For i As Integer = 0 To jpgFiles.Length - 1 Try original = Bitmap.FromFile(jpgFiles(i)) Catch original = My.Resources.Resource1._error End Try thumbnail(i) = createThumbnail(original, width, height) original.Dispose() Next ImageList1.Images.AddRange(thumbnail) For i As Integer = 0 To jpgFiles.Length - 1 ListView1.Items.Add(jpgFiles(i), i) Next End Sub KOZ6.0様、コメントありがとうございます。仮想化について調べてみます。ただ情報量が少ないようで、いろいろと試してみないといけないようで今日は遅いので明日になるかと思います。
SurferOnWww

2021/12/30 23:24

ボトルネックがどこにあるかの調べはついているのでしょうか? サムネイルの作成か、ListView への表示か、どっちでしょう? 何を作っているか (WinForms? ASP.NET Web Forms? その他?) を書いてください。
tada_tadaa

2021/12/31 00:29

SurferOnWww様 >ボトルネックがどこにあるかの調べはついているのでしょうか? 僕の2021/12/31 01:43 の上記のコードでブレイクポイントを ①For i As Integer = 0 To jpgFiles.Length - 1 の部分と ②ImageList1.Images.AddRange(thumbnail) の部分に置いてみて時間を計測したところ、Button1を押してから①の部分までで約1秒かかりました。 次に①から②の所までは1分38秒かかりました。次に②から最後まで走らせたら22秒かかりました。 全体で約2分かかってますが、①から②までのサムネイルを作成する処理に時間がかかっているようです。 作ったサムネイルをImageList1に追加するのとListView1.Items.Addの部分で22秒なので、サムネイルを作成する部分をもっと改善出来れば早くなると思います。
tada_tadaa

2021/12/31 00:37

>何を作っているか (WinForms? ASP.NET Web Forms? その他?) を書いてください。 「Visual Studio 2017」でプロジェクトの作成は「Visual Basic」の「Windowsフォームアプリケーション(.Net Framework)」を選択してプロジェクトを作成しています。どのような目的の物を作るかというと、jpg画像ファイルビューワーです。まずディレクトリを選択してそこにある画像ファイルの一覧をサムネイルで表示して、サムネイルのどれかをダブルクリックすると別ウィンドウでその画像が拡大表示されるといったものです。
SurferOnWww

2021/12/31 01:05

上記(ボトルネックと何を作っているか)は質問欄を編集して追加情報として追記願います。また「僕の2021/12/31 01:43 の上記のコード」も質問欄を編集して追記願います(元のコードはそのままにして、追記という形でお願いします)。ここコメント欄は「質問への追記・修正の依頼」の場所ですので。 サムネイルの作成にタスク並列ライブラリ (TPL) などの使用は検討されたでしょうか?
SurferOnWww

2021/12/31 01:58 編集

このコメントは回答欄に移しました。

まだ回答がついていません

会員登録して回答してみよう

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。