在WPF用户控件中,我写了3个滑块代表RGB,值为0 - 255.标准的东西!还显示了一个色样
基类是
private class SwatchPixels
{
public Point P { get; set; }
public int X { get; set; }
public int Y { get; set; }
public int R { get; set; }
public int G { get; set; }
public int B { get; set; }
public int A { get; set; }
}
private List<SwatchPixels> _points = new List<SwatchPixels>();
现在我想做的是(我有什么工作但不够准确!)
使用颜色样本中像素的所有RGB值加载列表,然后找到与提供的RGB值集合最接近的像素颜色。然后我可以将椭圆移动到该像素的x,y位置。我当然希望这样做的原因是色样通常不会包含所有1600万种颜色!
因此,如果有人能提出更好的方法,我会非常感激!
样本位于相同大小的画布对象中。
<Canvas Name="CanvasImage" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3" Width="150" Height="150"
HorizontalAlignment="Center" Background="Transparent" VerticalAlignment="Top" Margin="2"
MouseMove="CanvasImage_MouseMove" MouseDown="CanvasImage_MouseDown" MouseUp="CanvasImage_MouseUp">
<Ellipse Name="EllipsePixel" Width="8" Height="8" Stroke="Black" Fill="White"
Canvas.Left="0" Canvas.Top="0"/>
</Canvas>
加载所有像素值的方法
private List<SwatchPixels> FindAllPixelLocations()
{
// http://stackoverflow.com/questions/1176910/finding-specific-pixel-colors-of-a-bitmapimage
var img = new BitmapImage(new Uri(@"Resources/Cws.png", UriKind.RelativeOrAbsolute));
Image Ti = new Image();
Ti.Source = img;
ImageSource ims = Ti.Source;
BitmapImage bitmapImage = (BitmapImage)ims;
try
{
int stride = bitmapImage.PixelWidth * 4;
int size = bitmapImage.PixelHeight * stride; // stride
pixels = new byte[size];
bitmapImage.CopyPixels(pixels, stride, 0);
for (int y = 0; y < bitmapImage.PixelHeight; y++)
{
for (int x = 0; x < bitmapImage.PixelWidth; x++)
{
int index = y * stride + 4 * x;
byte red = pixels[index];
byte green = pixels[index + 1];
byte blue = pixels[index + 2];
byte alpha = pixels[index + 3];
var swatchPixels = new SwatchPixels
{
X = x,
Y = y,
P = new Point(x, y),
R = red,
G = green,
B = blue,
A = alpha
};
_points.Add(swatchPixels);
}
}
}
catch (Exception e)
{
MessageBox.Show(e.Message);
}
return _points;
}
找到一个点方法(我不满意!)
private const int initVariance = 40;
private const int dropPercent = 5;
private SwatchPixels FindXy(string a, string r, string g, string b)
{
var iR = 0;
var iG = 0;
var iB = 0;
if (RgbDec.IsChecked == true)
{
iR = Convert.ToByte(r);
iG = Convert.ToByte(g);
iB = Convert.ToByte(b);
}
else
{
// Number in hex format so convert to dec first
iR = Convert.ToByte(int.Parse(r, NumberStyles.HexNumber));
iG = Convert.ToByte(int.Parse(g, NumberStyles.HexNumber));
iB = Convert.ToByte(int.Parse(b, NumberStyles.HexNumber));
}
List<SwatchPixels> closepoints = new List<SwatchPixels>();
List<SwatchPixels> prevCp = new List<SwatchPixels>(closepoints);
var v = Convert.ToInt32(initVariance);
foreach (var p in _points)
{
if ((iR >= p.R - v && iR <= p.R + v) &&
(iG >= p.G - v && iG <= p.G + v) &&
(iB >= p.B - v && iB <= p.B + v))
{
closepoints.Add(p);
}
}
var c = closepoints.Count;
while (c > 10)
{
v = v - (v * dropPercent / 100);
closepoints = LoopAgain(closepoints, v, iR, iG, iB);
c = closepoints.Count;
//Variance.Text += c.ToString() + Environment.NewLine;
if (c == 0)
{
closepoints = new List<SwatchPixels>(prevCp);
break;
}
else
{
prevCp = new List<SwatchPixels>(closepoints);
}
}
if (c > 1)
return closepoints[0];
return null;
}
private List<SwatchPixels> LoopAgain(IEnumerable<SwatchPixels> cpoints, int v, int iR, int iG, int iB)
{
var closepoints = new List<SwatchPixels>();
foreach (var p in cpoints)
{
if ((iR >= p.R - v && iR <= p.R + v) &&
(iG >= p.G - v && iG <= p.G + v) &&
(iB >= p.B - v && iB <= p.B + v))
{
closepoints.Add(p);
}
}
return closepoints;
}
这是我修改过的ColorCanvas。 更改包括RGB的单个颜色矩形,将差异应用于所选颜色,并使用不同的颜色模型进行输入。您也可以单击一下将十六进制内容复制到剪贴板。
答案 0 :(得分:1)
请勿重新发明轮子,尝试使用Extended WPF Toolkit™ Community Edition,您有两个控件ColorPicker和ColorCanvas。
答案 1 :(得分:0)
我不完全确定,但是,让我们看看我是否可以帮助你:
你的&#34;色样&#34;看起来很多,但不完全像一个控件来选择HSL颜色选择器的HUE组件,除了奇怪的阴影。这也意味着它中只有一个RGB子集,你已经知道了。
现在我看到你的照片有两个主要缺点:
当给定某种颜色时,无法确定是否将椭圆放置在中心附近或边界附近,因为颜色在所有半径都是相同的。
色板从绿色开始,以蓝色结束。 Hue-Selector白色从红色开始,以红色结束:以下是来自Inkscape:
通常,您可以轻松地从RGB颜色中提取HSL组件,例如使用以下功能:
public static void FromRGB(byte ARed, byte AGreen, byte ABlue, out double AHue, out double ASaturation, out double AValue)
{
double h = 0;
double s = 0;
double r = (double)ARed / 255;
double g = (double)AGreen / 255;
double b = (double)ABlue / 255;
double max = Math.Max(r, Math.Max(g, b));
double min = Math.Min(r, Math.Min(g, b));
if (r == g && g == b) h = 0;
if (r == max) h = 60.0 * ((g - b) / (max - min));
else if (g == max) h = 60.0 * (2.0 + (b - r) / (max - min));
else if (b == max) h = 60.0 * (4.0 + (r - g) / (max - min));
if (max != 0) s = (max - min) / max;
AHue = h;
ASaturation = s;
AValue = max;
}
让我们来看看另一个颜色选择器,它看起来几乎和你的一样:
这个选择器有一些优点:
回答你的实际问题:
当您将RGB转换为HSV时,您会在选择器中找到最佳匹配像素,将饱和度和值组件设置为最大值并将其转换回RGB。
希望它对你有所帮助......
修改强>
根据要求,我将提供一个关于如何制作自己的rgb选择器图像的示例:
if (w <= 0 || h <= 0) return;
WriteableBitmap wb = new WriteableBitmap(w, h, 96, 96, PixelFormats.Rgb24, null);
byte[] pixels = new byte[wb.PixelWidth * wb.PixelHeight * 3];
Color base_color = GetBaseColorFromHue(Hue * 1.5);
for (int y = 0; y < h; y++)
{
double pos_v = (double)y / (double)h;
for (int x = 0; x < w; x++)
{
double pos_s = (double)x / (double)w;
pixels[(y * wb.PixelWidth + x) * 3] = (byte)((base_color.R * (pos_s) + 255 * (1 - pos_s)) * (1.0 - pos_v));
pixels[(y * wb.PixelWidth + x) * 3 + 1] = (byte)((base_color.G * (pos_s) + 255 * (1 - pos_s)) * (1.0 - pos_v));
pixels[(y * wb.PixelWidth + x) * 3 + 2] = (byte)((base_color.B * (pos_s) + 255 * (1 - pos_s)) * (1.0 - pos_v));
}
}
wb.WritePixels(new Int32Rect(0, 0, wb.PixelWidth, wb.PixelHeight), pixels, wb.PixelWidth * wb.Format.BitsPerPixel / 8, 0);