Table of Contents
The symbol returns the reader to the top of the Table of Contents.
Introduction
During the development of the Gradient Color Picker V2 [^] a significant modification to the algorithm used in the earlier version of the software occurred. In the original implementation, colors for the selection buttons were retrieved from a panel that contained a color gradient implemented using a LinearGradientBrush [^]. Two readers suggested the use of a different method, i.e., use colors obtained from an interpolation from a starting to an ending color.
The Question
How well does the interpolation method match the Microsoft's linear gradient brush?
Validation Method
The validation was limited to a small set of colors. Twenty colors participated in each test. The starting and ending colors were chosen using the Color Dialog [^]. For each test, colors were chosen from the following gradients.
The validation method was:
- Start and end colors were chosen for a test.
- A linear gradient panel was filled based on the start and end colors.
bool fill_gradient_PAN ( )
{
bool have_colors = ( have_end_color &&
have_start_color );
if ( have_colors )
{
gradient_PAN.Visible = true;
gradient_PAN.Invalidate ( );
compare_BUT.Visible = true;
}
return ( have_colors );
}
- On clicking Compare, the interpolated colors are computed; the selection color buttons are created, and the buttons are properly spaced along the interpolated gradient panel. get_interpolation_colors computed the interpolated colors.
int MinMax ( float start,
float difference,
float i )
{
int result = ( int ) ( start - ( i * difference ) + 0.5F );
return ( Math.Max ( 0, Math.Min ( 255, result ) ) );
}
List < Color > get_interpolation_colors (
Color start_color,
Color end_color,
int number_of_colors )
{
List < Color > list = new List < Color > ( );
float count = ( float ) number_of_colors - 1.0F;
float start_R = ( float ) start_color.R;
float difference_R = ( start_R -
( float ) end_color.R ) /
count;
float start_G = ( float ) start_color.G;
float difference_G = ( start_G -
( float ) end_color.G ) /
count;
float start_B = ( float ) start_color.B;
float difference_B = ( start_B -
( float ) end_color.B ) /
count;
for ( int i = 0; ( i < number_of_colors ); i++ )
{
int B = MinMax ( start_B, difference_B, ( float ) i );
int G = MinMax ( start_G, difference_G, ( float ) i );
int R = MinMax ( start_R, difference_R, ( float ) i );
list.Add ( Color.FromArgb ( R, G, B ) );
}
return ( list );
}
The spacing of the selection color buttons must be correct because the centerline of the button will be used to determine what color in the linear gradient panel will be compared with the color of the selection color button.
We now have enough information to perform the validation: the colors of the selection color buttons in the List interpolation_colors and the colors of the linear gradient pixels directly above the selection color buttons in the List pixel_colors.
- The results of the comparisons between the members of these two Lists is presented in a table-like form.
Each pair of color values contains the linear gradient color (upper) and the interpolated color (lower). The difference between the two is computed by color_difference.
void color_difference ( Color pixel_color,
Color interpolation_color,
ref int difference,
ref Color difference_color )
{
difference = 0;
difference_color = Color.Empty;
if ( interpolation_color.R != pixel_color.R )
{
difference++;
}
if ( interpolation_color.G != pixel_color.G )
{
difference++;
}
if ( interpolation_color.B != pixel_color.B )
{
difference++;
}
if ( difference == 0 )
{
difference_color = Color.LightGreen;
}
else if ( difference > 1 )
{
difference_color = Color.Red;
}
else
{
difference_color = Color.Yellow;
}
}
If the components are equal, the background color of the difference box (to the right of the color pair) is LightGreen; if one component differs, the background color is Yellow; and if two or more components differ, the background color is Red. In all cases, the count of differing components is displayed as the difference box text.
The results of all tests follow. Note that each graphic is a thumbnail that when clicked presents a larger graphic.
In a perfect world the background color of the difference boxes would all be LightGreen. Since that is not the case we must seek out the reason why.
The first thing we should consider is the positioning of the buttons beneath the gradient panel. The coloring of these buttons is not dependent on the coloring in the gradient panel (unlike the algorithm used in the first version of the software). Rather, the button colors are dependent on the results of an interpolation calculation.
The positioning of the buttons is determined through an integer computation. Thus rounding may become a factor especially because the horizontal position of the button centerline was computed using a division. As a result, the spacing was recalculated using floating point arithmetic.
spacing = ( int ) (
( float ) ( interpolation_button_PAN.Size.Width -
( BUTTON_WIDTH * number_of_colors ) ) /
( float ) ( number_of_colors - 1 ) + 0.5F );
Although this change improved the results (more difference boxes has a background color of LightGreen), there were still difference boxes with Yellow and Red background colors. This led to the hypothesis that the location of the pixel in the gradient panel was slightly to the left or right of the centerline of the appropriate selection color button.
To allow testing this hypothesis, the program was modified to allow the centerline of the button to be shifted left and right, using the arrow keys. First the selection color button of interest was clicked. This caused the borders of the selected button and associated report item to be highlighted.
Now the left and/or right arrow keys are pressed until the background color of the difference box is LightGreen.
The correction box displays the number of pixels moved and the direction of movement (Pink for leftward; PaleGreen for rightward). In this example, the centerline of the selection color button should have been positioned 2 pixels to the left.
The following are the results of all 6 tests.
In 5 of the 6 tests, a simple repositioning of the selection color button was sufficient to cause the linear gradient colors to match the interpolation colors. Although some may argue that the correction should be applied automatically, the Blue/Purple panel suggests otherwise. In the Blue/Purple test, there does not appear to be any simple left/right shift that would correct the positioning of the selection color buttons.
Note too that the human perception of the difference between interpolation and linear gradient colors is extremely small.
Answer
If we accept human perception as a factor, then the question "How well does the interpolation method match the Microsoft's linear gradient brush?" can be answered "Very Well."
References
Conclusion
This article has discussed the use of interpolated colors vs. the use of colors from a linear color gradient. The results of this study suggests that there is very little difference.
Development Environment
This project was developed in the following environment:
Microsoft Windows 7 Professional SP 1 |
Microsoft Visual Studio 2008 Professional SP1 |
Microsoft Visual C# 2008 |
Microsoft .Net Framework Version 3.5 SP1 |
History
4/24/2021 | Original article |