CS333 Lab P1-2:
Pipelined Medical Image Processing

Goals of this lab:

Introduction:

In this assignment, you will construct a distributed pipeline for digital filtering and enhancement of medical images. The images will be nuclear medicine beating heart studies. The images were taken by injecting a patent with a radioactive substance (Tc-99m) that attaches to the red blood cells and then placing the patient under a gamma camera that detects the gamma radiation emitted from the patient. By collecting the data in time slices corresponding to the patients electrocardiogram, a sequence of 32 "frames," each corresponding to one part of the heartbeat, were produced. Each frame consists of a 64x64 array of pixels with values in the range 0-255. When shown in succession, the result is a movie of the beating heart that can be "read" by radiologists to determine the extent of heart damage after a heart attack, for example. These beating heart movies are called RVGs, which stands for Radionuclide VentriculoGram.

One problem is that there is a lot of ambient radiation that causes the images to be rather noisy, and thus difficult to read. A solution to this problem is to reduce the noise by digitally filter the images. Images can be filtered spatially, meaning that each frame is filtered independently, and they can be filtered temporally, meaning that each pixel is filtered across a number of frames so that transitions between frames are smoother. More details on filtering are in the paper handed out in class.

Filtering images on demand requires substantial processing power. One way to accomplish this is to harness the power of several workstations by arranging them in a processing pipeline. In this lab, you will write modules that perform digital filtering, both spatially and temporally, and you will organize your modules into a pipeline so that some of the computation can be done in parallel in order to improve the overall response time. You will also experiment with other kinds of image processing operations that the users can control dynamically in order to adjust the appearance of the images.

Directions:

Read over the entire assignment before starting.

  1. Try the sender and counter modules: We have provided two Playground modules that you will use in your pipeline. In addition, EUPHORIA can be used to visualize and control the filtering process.
    fsender
    An executable module called fsender is available for serving RVG images from files. The first presentation variable is the frame that is being output by the sender. The second is the file name. When this is changed, the sender reads the given file and sends out the sequence of 32 image frames.
    EUPHORIA
    EUPHORIA can be used to display and control the filtered heart images. See Section 5.1 of the EUPHORIA Reference manual for instructions on how to create a movie in EUPHORIA. Click here for a picture of EUPHORIA being used to display the images.
    fcounter
    An executable module called fcounter is available for specifying the playback sequence and rate of play of frames. It generates an integer value which is incremented over time. Minimum and maximum value variables are supplied, allowing you to view only a certain range of frames. When the counter reaches the maximum, it is reset to the minimum. Another variable allows you to set the frames per second (i.e. how fast values are incremented). Connecting this module to EUPHORIA allows you to control how fast the frames are viewed. You may also connect it to multiple EUPHORIAs, effectively synchronizing their displays (approximately).

    Try bringing up these modules to display an image. The image files are in the directory /home/cec/class/cs333/rvg, so you should change to that directory when you run the sender module. A README file in that directory explains the images in the various data files.

  2. Spatial filter module: Write a Playground module that takes in an image frame (see the files PGimage.hh and PGimage.cc for the definition of the frame object), filters the frame by applying a filter mask to the image, and then outputting the frame. The module should be reactive, so that each frame is filtered as it arrives.

    You will use an 11-by-11 filter whose coefficients are defined by the two-dimensional array in this data file. The filter is symmetric, with entry 0,0 corresponding to the pixel being filtered. Because of the symmetry, the array only has values for one quadrant of the filter. To determine the new value for each pixel, you can imagine centering the filter mask over the image at that pixel, multiplying each coefficient in the filter by the pixel value that is "under" it and then summing. You should do all the intermediate computation in a two-dimensional array of doubles, and then normalize the image to a maximum pixel value of 255 to avoid overflow.

  3. Temporal filter module: Write a module to filter the images temporally using this symmetric filter of length 7, as defined by the one-dimensional array in this data file. Since the filter is symmetric, only 4 distinct coefficients are given. For a given pixel, the calculation is similar to the spatial filter, except that your filter "mask" is length 7 in the temporal dimension. That is, to compute each pixel, you'll need the values of the corresponding pixels for the three frames behind and in front of it, wrapping around for the first three and last three frames. Again, to avoid overflow, normalize each frame to a maximum pixel value of 255.

  4. Concurrent processing: The bottleneck in your system is probably the spatial filter, since it performs many floating point computations per pixel. To improve this, you should add a branch to the pipeline so that some of the processing is done concurrently on different processors. For example, you might have one module filter the even-numbered frames and another module filter the odd-numbered frames before passing them on to the temporal filter module. You won't need to change any of the modules you've already written. Just write a dispatch module that forward frames to two different places depending on the frame number. Be sure to run the spatial filter modules on different machines. Do you notice a speed-up? In the extreme case, you could filter each frame on a different machine. Think about how you might partition the work for temporal filtering on different machines.

  5. Eliminating background pixels: Write a module that will eliminate background by dropping to 0 all pixel values below a certain threshhold value. Make the threshhold value interactively controlled by the user (you might use EUPHORIA for this, if you want). Experiment with putting this module at different stages of the pipeline (before and after filtering).

  6. Changing the gray scale (optional): Our eyes actually respond to light in a non-linear way. For example, if you are in a room lit by one candle and you light another, you'll notice a big difference. However, if you are in a brightly lit room and you light a candle, the room won't seem any brighter. Try recalibrating your image using a logarithmic scale, so that differences in brighter pixels are "magnified" at the expense of compressing the differences for smaller pixel values. Let the user control the contrast interactively. Try this at the end of the pipeline. What happens if you put it earlier?

To receive credit for this lab, you should:

  1. Clean up and print out your code. (Don't turn it in, but save it for your code/design review.)

  2. Turn in a Project Evaluation Form near the beginning of class on the day you want to do your demonstration and code/design review. You should be prepared to demonstrate your working application, explain your design and code, and answer questions.