Theoretical Paper
- Computer Organization
- Data Structure
- Digital Electronics
- Object Oriented Programming
- Discrete Mathematics
- Graph Theory
- Operating Systems
- Software Engineering
- Computer Graphics
- Database Management System
- Operation Research
- Computer Networking
- Image Processing
- Internet Technologies
- Micro Processor
- E-Commerce & ERP
Practical Paper
Industrial Training
Introduction Image Processing
Image processing is the capability of software to manipulate images that are represented by a sequence of numeric values. Capabilities supported by most image-processing programs fall into three general categories:
Service commands, which manage the image data for computer I/O. This includes the retrieval and storage of image files, printing images, and file management.
Display commands, which support how you choose to visualize the image data. This includes displaying an image as a positive or negative picture, color palette selection, and 2-D or 3-D types of image representations.
Image-processing commands, which process the data to obtain some type of measurement from the data or to modify the data by filtering. In this case, filtering refers to the modification of data through mathematical techniques.
Unfortunately, Visual Basic, the visual-development environment I prefer to work in, often falls short in supporting these requirements, particularly when it comes to fast image plotting. However, it is possible to achieve efficient image processing by improving disk access and image plotting speeds using the techniques I'll describe in this article. I implemented these techniques to tackle deep-sky imaging and other astronomy-related applications in which my original problem was to display an image in near-real time to aid in focusing a CCD camera when mounted to a telescope. My approach to reading and saving a file is a time-tested solution for efficient disk access (I first learned it over 15 years ago). The plot routine I present uses the same display technique that is used for camera focusingdisplay an image from a computer memory location. To enhance quality, I then bring out details using histograms during post processing.
Reading the Image File
Reading a file into the program is straightforward. Many programmers read each and every byte of data, one byte at a time, and store that data into an array. However, since I sometimes grow impatient waiting on data loops, I speed things up using strings to store the data file. With either method, a memory area is defined for data storage.
First, create a module, naming it whatever you like (mine is named IMAGE.BAS), then declare string arrays in that module under the general attribute. The string declarations in my program are Global Datarray As String and Workarray As String, which define Datarray and Workarray as globally recognized string arrays.
I use strings because Basic-type programs use them efficiently. Note that a specific size is not needed for the array definition. This provides some programming flexibility if you want to enter files with different formats and lengths. This is a necessity for today's nonstandard astro-imaging formats.
To enter the data, there are several commands common to Basic and Visual Basic. I use INPUT to load data into a string. In Introduction to Astronomical Image Processing (Willmann-Bell, 1991), Richard Berry uses this command in a for-next loop in his excellent AstroIP software (written in Basic and included with his book) to load data.
The disadvantage of INPUT in a for-next loop is speed, especially when running the program on a 386SX-based PC running Windows. Speed is lost under Windows 3.x because Windows is just another layer of overhead associated with getting the data into the computer.
Like any other program, Windows 3.x communicates with the computer and its peripherals through the operating system. That means more processing for the computer, so it takes longer than executing the program directly with DOS. This isn't a terrible problem, but it becomes a nuisance.
I gained speed by reducing the number of lines of computer instructions. Example 1, the code to input raw 8-bit data files, will load the data file within a few seconds, even on a slow machine. It works fast because only four statements are executed. The first statement instructs the computer where the file is located, the second and third store the entire file into strings. The fourth statement closes the activity.
The reason for the difference in speed is obvious when you consider that this code is executed just once, whereas the INPUT statement would be executed 31,680 times in a for-next loop. For a comparison, see Example 2, which reads a raw 8-bit data file with for-next loops.
Displaying the Data
Once the image data has been loaded into the computer and filtered, the next step is to display it. Many Basic programmers use the PLOT command to do this. While PLOT's syntax is common to Basic and Visual Basic, its execution isn't the same. The key difference between each language implementation is how you tell the program where to plot.
In Visual Basic, you don't need to write specific code to define a plot area, as with Basic. The plot area is defined by a viewing area within a form. The form is created when a new program is started, by selecting New Form from the File menu, or by selecting its icon from the tool bar. When this command is executed, you simply drag to the size of the window that you want. The viewing area can be either the form itself or a graphics box placed on the form. I'll stick with the form itself.
The plot routine next needs to be associated with the form. This is almost as easy as creating the form. Simply double-click on the form, select the appropriate event to initiate execution of the code, and enter the plot routine or its subroutine call.
At this point, it's convenient to choose a 256-color palette to associate with the form. Three such palettes come bundled with the Visual Basic language set. They're okay for demonstrations, so use pastel.dib with this program. A palette can be made part of the program by selecting it through the form's Property menu. If you don't do this, you'll be stuck with the Windows default 20-color palette and your pictures won't be recognizable.
To display the image almost instantly, I rely upon the Windows API. Look at the LOAD event of Listing One and you'll see a call to the plot routine in the IMAGE1 module (Listing Two). The plot routine isn't much code, consisting only of Visual Basic declarations and Windows API function calls.
The Windows API plot code listing consists of six lines of code and is in the PLOT_IMAGE procedure of Listing Two. The last line of code, StretchBlt, is used to double the size of the original image.
Using the Windows API also makes it easy to do a 2xzoom. This can be done with only one line to call the StretchBlt API function. I use this function to double the size of the original image multiple times. Each time you want the image size doubled, select Zoom In from the Display menu. The code for the 2xzoom is found in the Zoom_Image_In procedure of Listing One.
To zoom out, you just have to call the image-plotting routine again. This simply replaces the zoomed image. See the Zoom_
Image_Out procedure in Listing One.
Image Histograms
Histograms are mathematical techniques that keep a running count of how frequently a set of values will occur. For the image data we're using, these values fall within a range of 0 to 255.
From the image file chosen, you can plot a histogram chart. This is useful for identifying the general distribution pattern of the image data.
From the histogram, you will notice that deep-sky astronomy images have similar distributions: a large number of low values (sky background) that decreases rapidly toward the higher data values (astronomical objects). Likewise, planetary and lunar images exhibit distinct histograms.
By examining the histogram chart, you can decide how to select filters to improve an image. For example, histogram operations can "amplify" a narrow range of numeric values to bring out subtle image details overpowered by bright objects or to reduce a noisy, narrowband sky background.
The technique I use to develop a histogram is conventional: I just read each byte of data and increment the appropriate cell of a data array. Each cell of the data array represents a specific numeric value from 0 to 255.
The algorithm to establish a histogram is based on a simple loop:
1. Get a byte of data.
2. Increment the count for this value.
3. If there's data remaining, go to step 1.
4. Display histogram.
To start writing code to implement this algorithm, specify an array for the histogram data. First, for ease of expansion, reserve use of the histogram array for any routine in the program. To do this, name and dimension the array in the general attributes section of the image module; I used Global Dim HistoLevel(255) As Integer. Note that the array is sized for 8-bit data. If you have 12-bit data, the array would be sized to 4095.
The core of the histogram routine is now ready. My routine is located in the Normal_Histo object in Listing One. The routine simply reads each byte of the Datarray string with a for-next loop.
The for-next loop is used as a counter. The value statement returns the numeric value of a string value. The numeric value is then used to identify and increment the appropriate cell of the histogram array.
Plotting the histogram is accomplished by calling a routine called HistoPlot, located in Listing Two. HistoPlot uses the Visual Basic graphics LINE command to draw 256 vertical lines in a picture box on FORM1. The picture box is scaled to show the first line (representing value 0) on the far left and the last line on the far right (representing value 255). The vertical length of each line corresponds to the number stored in each cell of the histogram array. This number is the count of how often a particular value occurred (the frequency). Figure 1 shows a histogram of the galaxy M51 with the corresponding image.
Since large histogram values can cause a program error with Visual Basic, I've included an error-handling routine in the histogram subroutine.
Stretching Histograms
Stretching the histogram means that pixel values above or below a user-specified threshold will be adjusted toward an upper or lower boundary, respectively. This is useful for bringing out detail in an image.
For example, Figure 2 was created from Figure 1 by stretching only the upper boundary limit from 150. In Figure 2, background stars pop out and more structure appears in the galaxy. To improve the picture more, increase image contrast by also stretching from the low end value. Using stretch values 27 (lower) and 150 (upper) works well for this image. The improvement is readily apparent in Figure 3.
The Visual Basic code to stretch an image is located in the Stretch_Histo object of Listing One. It is the only for-next loop in this subroutine. This loop implements an algorithm that produces "equalization." Simply put, the lower and upper threshold values entered (for example, 27 and 150) are multiplied by a factor to set them to 0 and 255, respectively. The data between these threshold values is then adjusted (stretched) to cover the full range of the x-axis scale (equalization). (See the code segment beginning 'Calculate the histogram in Listing One.) Data in this code is stretched by multiplying each pixel value based on a factor from the threshold values, and limiting the minimum and maximum values to 0 and 255.
The line that finds a value for Brightness stretches the data point. This line takes the lower threshold value (LoRange) and the upper threshold value (HiRange) to determine a ratio. That ratio is multiplied by 256 to get the stretched value for the data point, Level. The If statements keep the stretched values within limits. The other code lines either extract data from a string or stuff it back into a string and a data array.
Saving Images
Saving an image is just as easy as reading an image:
1. Open a file.
2. PUT a string into the file.
3. Properly close the file.
See the Save_File object in Listing One (the code segment starting 'Place data into the file). This technique will store any data format; however, I have not manipulated the string to be presented as anything other than raw 8-bit data. To store the data in another format, the string may need headers and trailers, and the data may need to be rearranged.
Conclusion
Of course, you may want more control over how data is displayed, and you may want to change or select different color palettes. A simple display feature you can add is to show the negative of an image. This is done by changing a parameter in the BitBlt Windows API function. Another addition would be the capability to read and save data in other file formats.
When using Visual Basic it is important to limit the length of for-next and do loops for displaying data and performing data I/O. Long loops for I/O are real speed killers.
Example 2: Code to read a raw 8-bit data file with for-next loops.
Open Path$ For Binary As #1 For Line = 1 To 165 For Point = 1 To 192 Position = Point + (Line - 1) * 192 Datarray$(Position) = INPUT(1,#1) Next Point Next Line Close