解释颜色的验证





5.00/5 (6投票s)
颜色插值与 Microsoft 线性渐变画笔产生的颜色匹配程度如何?
引言
在开发渐变颜色选择器 V2 [^]时,软件早期版本中使用的算法发生了重大修改。在原始实现中,选择按钮的颜色是从一个包含使用LinearGradientBrush [^]实现的颜色渐变的面板中检索的。两位读者建议使用不同的方法,即使用从起始颜色到结束颜色的插值获得的颜色。
问题
插值方法与 Microsoft 的线性渐变画笔匹配程度如何?
验证方法
验证仅限于少量颜色。每次测试有二十种颜色参与。起始颜色和结束颜色使用颜色对话框 [^]选择。对于每次测试,颜色从以下渐变中选择。
验证方法是
- 为测试选择了开始和结束颜色。
- 基于开始和结束颜色填充线性渐变面板。
// ***************************************** fill_gradient_PAN 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 ); } // fill_gradient_PAN
- 点击比较时,将计算插值颜色;创建选择颜色按钮,并将按钮正确地间隔在插值渐变面板上。get_interpolation_colors 计算插值颜色。
// **************************************************** MinMax int MinMax ( float start, float difference, float i ) { int result = ( int ) ( start - ( i * difference ) + 0.5F ); return ( Math.Max ( 0, Math.Min ( 255, result ) ) ); } // MinMax // ********************************** get_interpolation_colors // See https://codeproject.org.cn/Articles/5267129/ // Gradient-Color-Picker Bill Woodward comment modified 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 ); } // get_interpolation_colors
选择颜色按钮的间距必须正确,因为按钮的中心线将用于确定线性渐变面板中的哪种颜色将与选择颜色按钮的颜色进行比较。
现在我们有了足够的信息来执行验证:列表 interpolation_colors 中选择颜色按钮的颜色,以及列表 pixel_colors 中选择颜色按钮正上方的线性渐变像素的颜色。 - 这两个列表成员之间的比较结果以表格形式呈现。
每对颜色值包含线性渐变颜色(上)和插值颜色(下)。差异由 color_difference 计算。// ****************************************** 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; } } // color_difference
如果分量相等,则差异框(颜色对右侧)的背景颜色为浅绿色;如果一个分量不同,则背景颜色为黄色;如果两个或多个分量不同,则背景颜色为红色。在所有情况下,不同分量的计数都显示为差异框的文本。
所有测试结果如下。请注意,每个图形都是一个缩略图,点击后会显示一个更大的图形。
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() |
在理想情况下,差异框的背景颜色都应该是浅绿色。既然不是这样,我们就必须找出原因。
我们首先应该考虑的是按钮在渐变面板下的定位。这些按钮的着色不依赖于渐变面板中的着色(与软件第一版使用的算法不同)。相反,按钮颜色依赖于插值计算的结果。
按钮的定位是通过整数计算确定的。因此,舍入可能成为一个因素,特别是当按钮中心线的水平位置是通过除法计算出来的。结果,间距使用浮点算术重新计算。
// compute initial spacing
// between buttons
spacing = ( int ) (
( float ) ( interpolation_button_PAN.Size.Width -
( BUTTON_WIDTH * number_of_colors ) ) /
( float ) ( number_of_colors - 1 ) + 0.5F );
虽然这个改变改善了结果(更多的差异框背景颜色为浅绿色),但仍然存在背景颜色为黄色和红色的差异框。这导致了一个假设,即渐变面板中像素的位置略微偏离了相应选择颜色按钮中心线的左侧或右侧。
为了测试这个假设,程序被修改为允许使用箭头键左右移动按钮的中心线。首先点击感兴趣的选择颜色按钮。这会导致选定按钮和相关报告项的边框被高亮显示。
现在按下左键和/或右键,直到差异框的背景颜色变为浅绿色。
校正框显示移动的像素数和移动方向(粉色表示左移;浅绿色表示右移)。在此示例中,选择颜色按钮的中心线应向左移动 2 个像素。
以下是所有 6 次测试的结果。
![]() | ![]() | |
![]() | ![]() | |
![]() | ![]() |
在 6 次测试中的 5 次,只需简单地重新定位选择颜色按钮即可使线性渐变颜色与插值颜色匹配。虽然有人可能认为应该自动应用校正,但蓝色/紫色面板表明情况并非如此。在蓝色/紫色测试中,似乎没有任何简单的左右移动可以纠正选择颜色按钮的定位。
同时也要注意,人类感知插值颜色和线性渐变颜色之间的差异非常小。
答案
如果我们接受人类感知作为一个因素,那么“插值方法与 Microsoft 的线性渐变画笔匹配程度如何?”这个问题就可以回答:“非常好。”
参考文献
- LinearGradientBrush [^]
- 颜色渐变 [^]
结论
本文讨论了插值颜色与线性颜色渐变颜色的使用。本研究结果表明,两者之间的差异很小。
开发环境
本项目在以下环境中开发
Microsoft Windows 7 专业版 SP 1 |
Microsoft Visual Studio 2008 专业版 SP1 |
Microsoft Visual C# 2008 |
Microsoft .Net Framework Version 3.5 SP1 |
历史
4/24/2021 | 原文 |