Search code examples
arraysvb.netimagepicturebox

What's the most efficient way of allowing a user to rapidly cycle 100+ images through a picturebox


Full disclosure: I have no formal training in programming, but have dabbled for many years.

I'm making a windows application for use in education/medical imaging. One of the things I would like it to do is to enable the user to scroll through a CT-scan, that is an imageset consisting of 100+ images. (I have captured the CT-scan in compressed .jpegs to conserve memory, so no need to worry about the dicom-format) I have a working solution that uses a vertical scroll bar to allow the user to select which slice of the CT-scan to observe in a picturebox. Images are named simply by numbers, ex. 1.jpeg, 2.jpeg...110.jpeg.

vsbCT = vertical scroll bar

pbxCTScan = Picturebox

Private Sub VsbCT_ValueChanged(sender As Object, e As EventArgs) Handles vsbCT.ValueChanged

Dim CTScanFileName as String
CTScanFileName = "D:\CT_Images\" & CStr(vsbCT.Value) & ".jpeg"
pbxCTScan.Image = Image.FromFile(CTScanFileName)

End Sub

This works pretty nicely as intended, at least initially. However, during testing in the visual studio environment, cycling through many images quickly seems to induce the program to crash. I don't know the cause of the crash, but since it works as intended initially and crashes as a function of how many images I view and how fast I scroll I wonder if there is an issue with memory in some form.

The question is as follows: Is this the most efficient way of accomplishing this task? I have considered entering all images in an array or a list and display them from there, but that would consume 60Mb of memory and seems less elegant than to read it from disk.

Any help will be much appreciated!

best regards

dr_glacier


Solution

  • I will address your problem of the application eventually crashing. The request for a most efficient way is topic of opinion and is thus off-topic for SO and would likely cause your question to be closed.

    You are creating a new Image every time VsbCT_ValueChanged executes. However, you are never calling the Dispose method on the old image. Theoretically, the garbage collector will clean this up, but the majority of the memory consumed by an Image is unmanaged and hence there is little likelihood that memory pressure will trigger a collection. There is also the issue of consumed GDI handles that are limited resource. This is why it is recommended that your code calls Dispose on disposable objects as soon as they are no longer needed so that the consumed resource are released.

    On way of dealing with this is to use an extension method.

    Public Module Utilities
        <Extension()>
        Public Sub SwapImage(pb As PictureBox, newImage As Image)
            If pb.Image IsNot Nothing Then
                pb.Image.Dispose()
            End If
            pb.Image = newImage
        End Sub
    End Module 
    

    Then this statement:

    pbxCTScan.Image = Image.FromFile(CTScanFileName)
    

    would be replaced with:

    pbxCTScan.SwapImage(Image.FromFile(CTScanFileName))