Many applications need to obtain some type of image statistic to condense a frame of pixels into a smaller, more functional set of values for analysis. The statistic might be required to perform some subsequent operation and/or might be used to summarize the effect of some image operation. The MIL Image Processing module offers a variety of functions to extract statistical information from an image. These functions allow you, for example, to:
Generate the intensity histogram of an image buffer (MimHistogram()).
Calculate a variety of general statistics for all pixels in an image that satisfy a specified condition (MimStat()).
Calculate and accumulate a variety of general statistics for all pixels in a series of specified images (MimStatMultiple()).
Find the minimum and maximum values of an image buffer (MimFindExtreme()).
Find the location of certain pixel values (MimLocateEvent()).
Find the number of differences between two image buffers (MimCountDifference()).
Perform an image projection from two dimensions to one dimension (MimProject()).
Note that, with the exception of MimHistogram(), these functions are not available with MIL-Lite.
A histogram is the intensity distribution of pixel values in an image and is generated by counting the number of times each pixel intensity occurs. Histograms store this information in bins, each of which represents an intensity. For example, if a histogram has 100 bins, it can represent 100 intensities.
Information about the intensity distribution of pixel values in an image is useful for several applications. In particular, it is useful to help select a threshold level when binarizing an image (discussed later) and to change the image intensity distribution when trying to increase the image contrast.
You can generate an image histogram using MimHistogram(), which takes an image buffer and stores the results in a previously allocated histogram result buffer. To allocate the result buffer, use MimAllocResult() with M_HIST_LIST. Ensure that you specify enough histogram bins to store the required number of intensities in the result, using the NbEntries parameter. For example, if you are using an 8-bit unsigned source image, and you want to have one bin for every possible intensity value, you should specify 256 entries.
To read results, use MimGetResult(). Once results have been read from the result structure, you can release the it, using MimFree().
If you require further control over the generated histogram, you can specify the number of values that a histogram bin can hold, using MimControl() with M_HIST_BIN_SIZE_MODE, before calling MimHistogram(). You can also apply a smoothing factor to the histogram with the M_HIST_SMOOTHING_ITERATIONS control. Since the smoothing is an integer-based averaging of the histogram, the resulting number of values might be different than the number of values in the source image. To retrieve this type of information, use MimGetResult() with M_HIST_REAL_SIZE, M_HIST_VALUE_OFFSET, and M_HIST_VALUE_RANGE.
The following example shows how to load an image, and calculate and draw its intensity histogram.
You can use the MIL graphics functions to plot the histogram results on a graph, as shown below. The graphics functions (Mgra...()) are discussed later in this manual.
You can calculate various statistics for all pixels that satisfy a specified condition in an image, using MimStat(). Setting the condition limits the number of pixels for which the statistics will be calculated. However, the condition can also be set to use all of the pixels in the image.
The types of statistics that can be calculated include the following:
Maximum pixel value.
Maximum absolute pixel value.
Mean pixel value.
Minimum pixel value.
Minimum absolute pixel value.
Number of pixels (that satisfy the condition).
Standard deviation value.
Sum of pixel values.
Sum of absolute pixel values.
Sum of squared pixel values.
Note that MimStat() stores results in a result buffer that should have been previously allocated, using MimAllocResult() with M_STAT_LIST.
If pixel values in your image represent angles instead of intensities, you can also choose to have MIL treat the pixels as unit vectors, where the angular value of a pixel is considered to be the angle of a vector with a length of one. Treating the pixels as unit vectors allows MIL to calculate directional statistics, which take into account the wrap-around characteristic of angles (so that, for example, the mean of 0 and 360 is either 0 or 360, not 180). This is useful, for example, when calculating color statistics of HSL images because the hue of an HSL image is measured on an angular scale, as opposed to a linear scale.
The angles are considered to have been scaled to the type of the image buffer. For unsigned buffers, the minimum pixel value is considered as angle of 0, and one plus the maximum possible pixel value is considered an angle of 360. For example, an 8-bit buffer would have 0° mapped to a value of 0, while 360° would be mapped to a value of 256 (since the maximum pixel value is 255). For signed buffers, the minimum pixel value is considered as an angle of -180° while one plus the maximum pixel value is considered as angle of 180°. Floating point buffers have intensity values anywhere between 0 and 1, and these values are linearly mapped between 0° and 360°.
Using MimStat(), there are three main statistics that can be calculated when pixel values that satisfy a specified condition are considered as unit vectors:
The coherence of the unit vectors.
The dominant angle of the unit vectors.
The dominant orientation of the unit vectors.
The coherence represents the directional trend of all the unit vectors in the image. It is a measure of how coherent or parallel the unit vectors are with respect to each other. To quantify this idea, MimStat() with M_ANGULAR_DATA_COHERENCE first performs a vector addition on all the unit vectors. The vector that results from this addition is known as the vector sum, and the length component of this vector sum is known as the norm. The function then calculates the ratio between the norm, or length, of the vector sum and its maximum possible length (which corresponds to the number of pixels considered, since each pixel is presumed to have a length of one). Numerically, this quantity lies between 0 and 1, where 0 represents absolutely no coherence (unit vectors pointing in random directions) and 1 is total coherence (unit vectors pointing in same direction). Below are images depicting three different coherences: perfect coherence, high coherence, and low coherence, respectively.
In the following image, the coherence of 4 unit vectors with the same angle is calculated. Since the ratio between the norm and the maximum possible length is equal to 1, there is total coherence between individual unit vectors, confirming all unit vectors are pointing in the same direction.
In the following image, the coherence of 4 unit vectors with differing angles is calculated. Since the ratio between the norm and the maximum possible length is equal to 0.905, there is high (but not total) coherence between individual unit vectors. Therefore, it can be concluded that the unit vectors are pointing in similar directions.
In the following image, the coherence of 4 unit vectors with differing angles is calculated. Since the ratio between the norm and the maximum possible length is equal to 0.105, there is very low coherence between the individual unit vectors. Therefore, it can be concluded that the unit vectors are pointing in seemingly opposite or random directions.
In addition to calculating the coherence (M_ANGULAR_DATA_COHERENCE), by treating the pixels as unit vectors, you can also calculate the dominant angle in the data. To do so, use MimStat() with M_ANGULAR_DATA_MEAN; this considers the angular component of the vector sum as the average angle. When the average angle is analyzed in context with the coherence of the unit vectors, it is much more representative of the average angle. For example, if your image has a coherence of 0.1 and an average angle of 65°, the average angle is not very meaningful because the unit vectors are pointing in random, incoherent directions. However, if your image has a coherence of 0.9 and an average angle of 65°, this indicates that the unit vectors are more or less pointing in the same direction, and their average value is around 65°.
If you are only interested in the dominant orientation of the unit vectors, you should use MimStat() with M_ORIENTATION_DATA_MEAN; this only takes into consideration the inclination of the unit vectors, without their direction, returning their dominant orientation within the image (for example, are they horizontal, vertical, diagonal). For unit vectors that are antipodal to each other (for example, 45° and 225°), the resulting orientation angle will be one of the original angles (for the previous example, 45°). Whereas for unit vectors that have an angular distance of 90° (for example, 0° and 90°), the vectors will cancel each other out. The orientation operation does not typically deal with only 2 unit vectors, but with all unit vectors within an image; as such, it is very unlikely that all the resulting unit vectors' orientations will cancel each other out. Furthermore, because the operation deals with the average orientation of all unit vectors in an image, the approximate, dominant orientation of the image is returned. For a more accurate orientation operation, use the MimFindOrientation() function.
The following image illustrates the difference between taking the dominant angle (M_ANGULAR_DATA_MEAN) and the dominant orientation (M_ORIENTATION_DATA_MEAN). The calculation of M_ANGULAR_DATA_MEAN results in a dominant angle of 45 o . Whereas, the calculation of M_ORIENTATION_DATA_MEAN results in a dominant orientation of 90 o .
You can calculate statistics for each pixel location across multiple source images, passed upon iterative calls to MimStatMultiple(). One value is calculated for every pixel in the source image, for each statistical operation specified to be performed. This function stores results in a result buffer that should have been previously allocated using MimAllocResult() with M_STAT_MULTIPLE_RESULT. The same result buffer should be specified for each call to MimStatMultiple().
Specify the statistics to perform using a multiple statistics image processing context, allocated using MimAlloc() with M_STAT_MULTIPLE_CONTEXT. Initialize the context with the type of statistics to calculate using MimControl() with M_TYPE.
MIL can calculate one or more of the following types of statistics for each pixel position in the sequence of images:
Maximum pixel value at the position.
Maximum absolute pixel value at the position.
Mean pixel value at the position.
Minimum pixel value at the position.
Minimum absolute pixel value at the position.
Number of pixel values, at the position, that match the given condition.
Standard deviation value at the position.
Sum of pixel values at the position.
Sum of absolute pixel values at the position.
Sum of squared pixel values at the position.
To limit the area of the source buffer to use when calculating statistics, use MimControl() with M_SIZE_X and M_SIZE_Y.
When you are ready to calculate the statistics for the source images, you must preprocess the context and result buffer. The preprocessing stage uses the specified source image and result buffer (if specified) to determine how to optimally calculate the specified statistics. If the preprocessing operation was not done explicitly (using M_PREPROCESS) it will be done when MimStatMultiple() is first called.
You can find the minimum and maximum pixel values of your image with MimFindExtreme(). Perhaps the most common use for finding the minimum and maximum image pixel values is to fine-tune the black and white reference levels of your frame grabber, ensuring full-range digitization. Another use for finding the maximum image pixel value is to find the number of objects in a labeled image. If all objects in an image are labeled with unique consecutive values, using MimLabel() (discussed later in this chapter), the largest label value also corresponds to the number of objects in your image.
MimFindExtreme() stores results in a result buffer that should have been previously allocated, using MimAllocResult() with M_EXTREME_LIST. You can get the resulting values, using MimGetResult(), and free the result buffer, using MimFree().
Once you have established certain values of interest in an image, you can find the location of pixels that satisfy conditions based on these values, using MimLocateEvent(). For example, you can use MimLocateEvent() to find the location of all pixels in an image equal to the image's maximum pixel value.
Note that MimLocateEvent() stores results in a result buffer that should have been previously allocated, using MimAllocResult() with M_EVENT_LIST.
You can find the number of differences between two images, using MimCountDifference(). MimCountDifference() stores results in a result buffer that should have been previously allocated, using MimAllocResult() with M_COUNT_LIST. You can get the resulting values, using MimGetResult(), and free the result buffer, using MimFree().
The MimProject() function projects an image buffer into a one dimensional buffer, generated by adding all pixel values along each diagonal in the image at the specified angle. This projection is referred to as the pixel value density of each diagonal. The 90° projection of the image is known as the row profile, and the 0° projection is known as the column profile.
The MimProject() function can perform both grayscale and binary image projections. On simple binary images, the projection is useful to detect object locations.
You allocate the result buffer, using MimAllocResult() with M_PROJ_LIST. You should define a result buffer with as many locations as there are diagonals in the image at the specified angle. You can then get the resulting values, using MimGetResult(), and free the result structure, using MimFree().