将HSV循环代码从Delphi转换为C# [英] Converting HSV circle code from Delphi to C#

查看:239
本文介绍了将HSV循环代码从Delphi转换为C#的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图转换一个函数来创建一个从Delphi到C#的HSV循环,但结果不是以正确的方式。



我的目标是为Windows Phone 7做一个应用程序,我只使用WP7.1 SDK,加上 WriteableBitmapEx 库。



Delphi代码:

  FUNCTION CreateHueSaturationCircle(CONST size:INTEGER; CONST ValueLevel:INTEGER; CONST BackgroundColor:TColor):TBitmap ; 
VAR
dSquared:INTEGER;
H,S,V:INTEGER;
i:INTEGER;
j:INTEGER;
半径:INTEGER;
RadiusSquared:INTEGER;
row:pRGBTripleArray;
X:INTEGER;
Y:INTEGER;
BEGIN
结果:= TBitmap.Create;
RESULT.PixelFormat:= pf24bit;
RESULT.Width:= size;
RESULT.Height:= size;

//用背景颜色填充
RESULT.Canvas.Brush.Color:= BackGroundColor;
RESULT.Canvas.FillRect(RESULT.Canvas.ClipRect);

半径:= size DIV 2;
RadiusSquared:= Radius * Radius;

V:= ValueLevel;
FOR j:= 0 TO RESULT.Height - 1 DO
BEGIN
Y:= Size - 1 - j - Radius; {center is Radius offset}
row:= RESULT.Scanline [Size -1-j];
FOR i:= 0 TO RESULT.Width - 1 DO
BEGIN
X:= i - Radius;
dSquared:= X * X + Y * Y;
IF dSquared< = RadiusSquared THEN
BEGIN
S:= ROUND((255 * SQRT(dSquared))/ Radius);
H:= ROUND(180 *(1 + ArcTan2(X,Y)/ PI)); // 0..360 degrees
//移动90度,沿X轴发生H = 0(红色)
H:= H + 90;
IF H> 360 THEN
H:= H - 360;
row [i]:= HSVtoRGBTriple(H,S,V)
END
END;
END;
END;

功能HSVtoRGBTriple(CONST H,S,V:INTEGER):TRGBTriple;
CONST
divisor:INTEGER = 255 * 60;
VAR
f:INTEGER;
hTemp:INTEGER;
p,q,t:INTEGER;
VS:INTEGER;
BEGIN
如果S = 0 THEN
结果:= RGBtoRGBTriple(V,V,V)//无色:灰色阴影
ELSE
BEGIN //有彩色
IF H = 360 THEN
hTemp:= 0
ELSE
hTemp:= H;
f:= hTemp MOD 60; // f is IN [0,59]
hTemp:= hTemp DIV 60; // h现在为IN [0,6)
VS:= V * S;
p:= V - VS DIV 255; // p = v *(1-s)
q:= V - (VS * f)DIV除数; // q = v *(1-s * f)
t:= V-(VS *(60-f))DIV除数; // t = v *(1 - s *(1 - f))
CASE hTemp OF
0:RESULT:= RGBtoRGBTriple(V,t,p)
1:RESULT:= RGBtoRGBTriple(q,V,p);
2:RESULT:= RGBtoRGBTriple(p,V,t);
3:RESULT:= RGBtoRGBTriple(p,q,V);
4:RESULT:= RGBtoRGBTriple(t,p,V);
5:RESULT:= RGBtoRGBTriple(V,p,q);
ELSE
结果:= RGBtoRGBTriple(0,0,0)//永远不会发生;
//避免编译器警告
END
END
END

Delphi代码的结果:





我的C#代码:

  public struct HSV 
{
public float h;
public float s;
public float v;
}


public void createHsvCircle()
{
int size = 300;

wb = new WriteableBitmap(size,size);

wb.Clear(GraphicsUtils.WhiteColor);

int radius = size / 2;
int radiusSquared = radius * radius;

int x;
int y;
int dSquared;

HSV hsv;
hsv.v = 255F;

for(int j = 0; j< size; j ++)
{
y = size - 1 -

for(int i = 0; i {
x = i - radius;
dSquared = x * x + y * y;

if(dSquared <= radiusSquared)
{
hsv.s =(float)Math.Round((255 * Math.Sqrt(dSquared))/ radius);

hsv.h =(float)Math.Round(180 *(1 + Math.Atan2(y,x)/ Math.PI));

hsv.h + = 90;
if(hsv.h> 360)
{
hsv.h - = 360;
}

颜色color = GraphicsUtils.HsvToRgb(hsv);

wb.SetPixel(i,j,color);
}
}
}

wb.Invalidate();

}

public static Color HsvToRgb(float h,float s,float v)
{
h = h / 360;
if(s> 0)
{
if(h> = 1)
h = 0;
h = 6 * h;
int hueFloor =(int)Math.Floor(h);
byte a =(byte)Math.Round(RGB_MAX * v *(1.0 - s));
byte b =(byte)Math.Round(RGB_MAX * v *(1.0 - (s *(h - hueFloor))));
byte c =(byte)Math.Round(RGB_MAX * v *(1.0 - (s *(1.0 - (h-hueFloor)))))
byte d =(byte)Math.Round(RGB_MAX * v);

switch(hueFloor)
{
case 0:return Color.FromArgb(RGB_MAX,d,c,a);
case 1:return Color.FromArgb(RGB_MAX,b,d,a);
case 2:return Color.FromArgb(RGB_MAX,a,d,c);
case 3:return Color.FromArgb(RGB_MAX,a,b,d);
case 4:return Color.FromArgb(RGB_MAX,c,a,d);
case 5:return Color.FromArgb(RGB_MAX,d,a,b);
默认值:return Color.FromArgb(RGB_MAX,0,0,0);
}
}
else
{
byte d =(byte)(v * RGB_MAX);
return Color.FromArgb(255,d,d,d);
}
}

public static Color HsvToRgb(HSV hsv)
{
return HsvToRgb(hsv.h,hsv.s,hsv.v) ;
}

我的c#结果:





我做错了?



提前感谢。



b
$ b

从@Aybe的好的答案,我可以从HSV whell做一个工作版本。



这是WP7的工作代码SDK:

  public const double PI = 3.14159265358979323846264338327950288d; 

public void createHsvCircle(double value = 1.0d)
{
if(value< 0.0d || value> 1.0d)
throw new ArgumentOutOfRangeException 值);

var size = 1024;

wb = new WriteableBitmap(size,size);

//用白色填充。
var white = Colors.White;
for(int index = 0; index< wb.Pixels.Length; index ++)
{
wb.Pixels [index] = 0xFF& 24 |白色R& 16 |白色G< 8 |白B.
}

var cx = size / 2;
var cy = size / 2;
var radius = cx;
var radiusSquared = radius * radius;
for(int i = 0; i {
for(int j = 0; j< size; j ++)
{
var x = i-cx;
var y = j - cy;
var distance =(double)x * x + y * y;
if(distance< = radiusSquared)// in circle
{
var angle = 180.0d *(1 + Math.Atan2(x,y)/ PI);

//移动90度,因此沿X轴发生H = 0(红色)
angle + = 90.0d;
if(angle> 360.0d)
{
angle - = 360.0d;
}

var hue = angle / 360.0d; // hue必须为0到1.
var saturation = Math.Sqrt(distance)/ radius; //饱和度必须为0到1。

var hsv = new HSV(hue,saturation,value);
var rgb = RGB.FromHsv(hsv.H,hsv.S,hsv.V);

wb.Pixels [j * size + i] = 0xFF< 24 | rgb.R < 16 | rgb.G < 8 | rgb.B;
}
}

}
wb.Invalidate();
}

public static RGB FromHsv(double hue,double saturation,double value)
{
if(hue< 0.0d || hue> 1.0d )
throw new ArgumentOutOfRangeException(hue);
if(饱和度< 0.0d ||饱和度> 1.0d)
throw new ArgumentOutOfRangeException(saturation);
if(value< 0.0d || value> 1.0d)
throw new ArgumentOutOfRangeException(value);

if(saturation == 0.0d)
{
var b1 =(byte)(value * 255);
return new RGB(b1,b1,b1);
}

double r;
double g;
double b;

var h = hue * 6.0d;
if(h == 6.0d)
{
h = 0.0d;
}

int i =(int)Math.Floor(h);

var v1 = value *(1.0d - saturation);
var v2 = value *(1.0d - saturation *(h - i));
var v3 = value *(1.0d - saturation *(1.0d - (h - i)));

switch(i)
{
case 0:
r = value;
g = v3;
b = v1;
break;
case 1:
r = v2;
g = value;
b = v1;
break;
case 2:
r = v1;
g = value;
b = v3;
break;
case 3:
r = v1;
g = v2;
b = value;
break;
case 4:
r = v3;
g = v1;
b = value;
break;
默认值:
r = value;
g = v1;
b = v2;
break;
}

r = r * 255.0d;
if(r> 255.0d)
{
r = 255.0d;
}
g = g * 255.0d;
if(g> 255.0d)
{
g = 255.0d;
}
b = b * 255.0d;
if(b> 255.0d)
{
b = 255.0d;
}

return new RGB((byte)r,(byte)g,(byte)b);
}

现在,新结果:





谢谢!花了一个小时左右,我在这个过程中学到了一些东西...


$

b $ b

现在的代码:(适用于任何大小)



这是HSL,但我给了你的URL有你的其他algos。

 使用System; 
using System.Diagnostics;
using System.Runtime.InteropServices;
使用System.Windows;
使用System.Windows.Media;
使用System.Windows.Media.Imaging;

namespace ColorWheel
{
///< summary>
/// MainWindow.xaml的交互逻辑
///< / summary>
public partial MainWindow:Window
{
public MainWindow()
{
InitializeComponent();
}

private void BuildWheel()
{
var width = 1024;
var height = width;
var cx = width / 2;
var cy = height / 2;
var colors = new int [width * height];
var gray = Colors.Gray.ToBgr32();
for(int index = 0; index< colors.Length; index ++)colors [index] = grey;

var radius = cx;
var radiusSquared = radius * radius;
for(int i = 0; i {
for(int j = 0; j< width; j ++)
{
var x = j-cx;
var y = i - cy;
var distanceSquared =(double)x * x + y * y;
if(distanceSquared <= radiusSquared)// in circle
{
var h = Math.Atan2(x,y).ToDegrees()+ 180.0d; // Angle
var s = 1.0d;
var l =(1.0d - ((1.0d / radiusSquared)* distanceSquared)); // 1 - (distance normalized)
var hsl = new HSL((float)h,(float)s,(float)l);
var rgb = RGB.FromHsl(hsl.H,hsl.S,hsl.L);
colors [i * width + j] = rgb.R < 16 | rgb.G < 8 | rgb.B;
}
}
}
var bitmap = new WriteableBitmap(width,height,96,96,PixelFormats.Bgr32,null);
bitmap.WritePixels(new Int32Rect(0,0,width,height),colors,width * 4,0);
image.Source = bitmap;
}

private void Window_Loaded(object sender,RoutedEventArgs e)
{
BuildWheel();
}
}

public static class Helpers
{
public static double ToDegrees(this double radians)
{
return radians * 57.2957795130823; // radians *(180.0d / Math.PI)
}

public static double ToRadians(this double degrees)
{
return degrees * 0.0174532925199433; // degrees *(Math.PI / 180.0d)
}
}

public static class ColorExtensions
{
public static Color FromBgr32颜色)
{
return Color.FromRgb((byte)((color& 0xFF0000)>> 16),(byte)((color& 0xFF00)> (字节)(颜色& 0xFF));
}

public static int ToBgr32(this Color color)
{
return color.R< 16 |颜色G< 8 |颜色B.
}
}

///< summary>
///表示HSL空间中的颜色。
///< / summary>
[StructLayout(LayoutKind.Sequential)]
public struct HSL
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _h;

[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _s;

[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _l;

///< summary>
///返回此实例的完全限定类型名称。
///< / summary>
///< returns> A< see cref =T:System.String/>包含完全限定类型名称。 < / returns>
///< filterpriority> 2< / filterpriority>
public override string ToString()
{
return string.Format(H:{0},S:{1},L:{2},_h,_s,_l) ;
}

///< summary>
///创建一个新实例< see cref =HSL/> 。
///< / summary>
///< param name =h>值< see cref =H/>零件。 < / param>
///< param name =s>值< see cref =S/>零件。 < / param>
///< param name =l>值< see cref =L/>零件。 < / param>
public HSL(double h,double s,double l)
{
_h = h;
_s = s;
_l = l;
}

///< summary>
///获取色调组件的值。
///< / summary>
public double H
{
get {return _h; }
}

///< summary>
///获取饱和度组件的值。
///< / summary>
public double S
{
get {return _s; }
}

///< summary>
///获取亮度组件的值。
///< / summary>
public double L
{
get {return _l; }
}

public override bool Equals(object obj)
{
if(ReferenceEquals(null,obj))return false;
if(obj.GetType()!= typeof(HSL))return false;
return Equals((HSL)obj);
}

public bool Equals(HSL other)
{
return other._h.Equals(_h)&& other._l.Equals(_l)&&&
other._s.Equals(_s);
}

///< summary>
///创建一个新实例< see cref =HSL/> ,从RGB值。
///< / summary>
///< param name =red>红色分量的值。 < / param>
///< param name =green>绿色组件的值。 < / param>
///< param name =blue>蓝色分量的值。 < / param>
///< returns> < see cref =HSL/>实例创建。 < / returns>
public static HSL FromRGB(字节红色,字节绿色,字节蓝色)
{
var r1 = red / 255.0d;
var g1 = green / 255.0d;
var b1 = blue / 255.0d;

var min = Math.Min(r1,Math.Min(g1,b1));
var max = Math.Max(r1,Math.Max(g1,b1));

var l =(max + min)/2.0d;

var s = 0.0d;
var h = 0.0d;
if(min == max)
{
h = 0.0d;
s = 0.0d;
}
else
{
if(l <0.5d)
{
s =(max - min)/(max + min)
}
else if(l> = 0.5d)
{
s =(max-min)/(2.0d-max-min);
}

if(r1 == max)
{
h =(g1 - b1)/(max - min);
}
else if(g1 == max)
{
h = 2.0d +(b1 - r1)/(max - min);
}
else if(b1 == max)
{
h = 4.0d +(r1 - g1)/(max - min);
}
}

h * = 60.0d;

if(h< 0.0d)
h + = 360.0d;

return new HSL(h,s,l);
}

///< summary>
///返回此实例的哈希码。
///< / summary>
///< returns>作为此实例的哈希码的32位有符号整数。 < / returns>
///< filterpriority> 2< / filterpriority>
public override int GetHashCode()
{
unchecked
{
var result = _h.GetHashCode();
result =(result * 397)^ _l.GetHashCode();
result =(result * 397)^ _s.GetHashCode();
return result;
}
}


public static BitmapSource GetHslPalette(int width = 360,int height = 100)
{
// HSL调色板图像像在Photoshop,等...
var pixels = new int [width * height];
const double saturation = 1.0d;
for(var y = 0; y< height; y ++)
{
for(var x = 0; x {
var hue =(1.0d / width)* x * 360.0d;
var lightness = 1.0d - ((1.0f / height)* y);
var rgb = RGB.FromHsl(hue,saturation,lightness);
pixels [y * width + x] = 0xFF< 24 | rgb.R < 16 | rgb.G < 8 | rgb.B;
}
}
return BitmapSource.Create(width,height,96,96,PixelFormats.Pbgra32,null,pixels,width * 4);
}

public static bool operator ==(HSL left,HSL right)
{
return left.Equals(right);
}

public static bool operator!=(HSL left,HSL right)
{
return!left.Equals(right);
}
}

///< summary>
///表示RGB空间中的颜色。
///< / summary>
[StructLayout(LayoutKind.Sequential)]
public struct RGB
{
[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _r;

[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _g;

[DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _b;

///< summary>
///创建一个新实例< see cref =RGB/> 。
///< / summary>
///< param name =r>红色成分的值。 < / param>
///< param name =g>绿色部件的值。 < / param>
///< param name =b>蓝色分量的值。 < / param>
public RGB(byte r,byte g,byte b)
{
_r = r;
_g = g;
_b = b;
}

///< summary>
///返回此实例的完全限定类型名称。
///< / summary>
///< returns> A< see cref =T:System.String/>包含完全限定类型名称。 < / returns>
///< filterpriority> 2< / filterpriority>
public override string ToString()
{
return string.Format(R:{0},G:{1},B:{2},_r,_g,_b) ;
}

///< summary>
///获取红色组件的值。
///< / summary>
public byte R
{
get {return _r; }
}

///< summary>
///获取绿色组件的值。
///< / summary>
public byte G
{
get {return _g; }
}

///< summary>
///获取蓝色组件的值。
///< / summary>
public byte B
{
get {return _b; }
}

public override bool Equals(object obj)
{
if(ReferenceEquals(null,obj))return false;
if(obj.GetType()!= typeof(RGB))return false;
return Equals((RGB)obj);
}

public bool等于(RGB其他)
{
return other._b == _b&& other._g == _g&&& other._r == _r;
}

///< summary>
///创建一个新实例< see cref =RGB/> ,从HSL值。
///< / summary>
///< param name =hue>色相,从0.0到360.0。 < / param>
///< param name =saturation>饱和度,从0.0到1.0。 < / param>
///< param name =lightness>亮度,从0.0到1.0。 < / param>
///< returns> < see cref =RGB/>实例创建。 < / returns>
public static RGB FromHsl(double hue,double saturation,double lightness)
{
if(hue< 0.0d || hue> 360.0d)throw new ArgumentOutOfRangeException(hue) ;
if(饱和度< 0.0d ||饱和度> 1.0d)throw new ArgumentOutOfRangeException(saturation);
if(lightness< 0.0d || lightness> 1.0d)throw new ArgumentOutOfRangeException(lightness);

if(saturation == 0.0d)
{
var b1 =(byte)(lightness * 255);
return new RGB(b1,b1,b1);
}

var t2 = 0.0d;

if(lightness< 0.5d)
t2 = lightness *(1.0d + saturation);
else if(lightness> = 0.5d)
t2 = lightness + saturation - lightness * saturation;

var t1 = 2.0d * lightness - t2;

var h = hue / 360.0d;

var tr = h + 1.0d / 3.0d;
var tg = h;
var tb = h - 1.0d / 3.0d;

tr = tr < 0.0d? tr + 1.0d:tr> 1.0d? tr-1.0d:tr;
tg = tg< 0.0d? tg + 1.0d:tg> 1.0d? tg - 1.0d:tg;
tb = tb< 0.0d? tb + 1.0d: 1.0d? tb-1.0d:tb;

double r;
if(6.0d * tr <1.0d)
r = t1 +(t2-t1)* 6.0d * tr;
else if(2.0d * tr <1.0d)
r = t2;
else if(3.0d * tr <2.0d)
r = t1 +(t2-t1)*((2.0d / 3.0d)-tr)* 6.0d;
else
r = t1;

double g;
if(6.0d * tg <1.0d)
g = t1 +(t2-t1)* 6.0d * tg;
else if(2.0d * tg <1.0d)
g = t2;
else if(3.0d * tg <2.0d)
g = t1 +(t2-t1)*((2.0d / 3.0d)-tg)* 6.0d;
else
g = t1;

double b;
if(6.0d * tb <1.0d)
b = t1 +(t2-t1)* 6.0d * tb;
else if(2.0d * tb <1.0d)
b = t2;
else if(3.0d * tb <2.0d)
b = t1 +(t2-t1)*((2.0d / 3.0d)-Tb)* 6.0d;
else
b = t1;

返回新的RGB((字节)(r * 255),(字节)(g * 255),(字节)(b * 255)
}

///< summary>
///返回此实例的哈希码。
///< / summary>
///< returns>作为此实例的哈希码的32位有符号整数。 < / returns>
///< filterpriority> 2< / filterpriority>
public override int GetHashCode()
{
unchecked
{
var result = _b.GetHashCode();
result =(result * 397)^ _g.GetHashCode();
result =(result * 397)^ _r.GetHashCode();
return result;
}
}

public static bool operator ==(RGB left,RGB right)
{
return left.Equals(right);
}

public static bool operator!=(RGB left,RGB right)
{
return!left.Equals(right);
}
}
}


I'm trying to convert an function to create a HSV Circle from Delphi to C#, but the result is not being in a correct way.

My target is to do an app for Windows Phone 7, and I'm only using the WP7.1 SDK, plus WriteableBitmapEx library.

Delphi Code:

FUNCTION CreateHueSaturationCircle(CONST size: INTEGER; CONST ValueLevel: INTEGER; CONST BackgroundColor: TColor): TBitmap;
VAR
  dSquared: INTEGER;
  H,S,V: INTEGER;
  i: INTEGER;
  j: INTEGER;
  Radius: INTEGER;
  RadiusSquared: INTEGER;
  row: pRGBTripleArray;
  X: INTEGER;
  Y: INTEGER;
BEGIN
    RESULT := TBitmap.Create;
    RESULT.PixelFormat := pf24bit;
    RESULT.Width := size;
    RESULT.Height := size;

    // Fill with background color
    RESULT.Canvas.Brush.Color := BackGroundColor;
    RESULT.Canvas.FillRect(RESULT.Canvas.ClipRect);

    Radius := size DIV 2;
    RadiusSquared := Radius * Radius;

    V := ValueLevel;
    FOR j := 0 TO RESULT.Height - 1 DO
    BEGIN
        Y := Size - 1 - j - Radius;  {Center is Radius offset}
        row := RESULT.Scanline[Size - 1 - j];
        FOR i := 0 TO RESULT.Width - 1 DO
        BEGIN
            X := i - Radius;
            dSquared := X * X + Y * Y;
            IF dSquared <= RadiusSquared THEN
            BEGIN
                S := ROUND((255 * SQRT(dSquared)) / Radius);
                H := ROUND(180 * (1 + ArcTan2(X, Y) / PI));   // 0..360 degrees
                // Shift 90 degrees so H=0 (red) occurs along "X" axis
                H := H + 90;
                IF H > 360 THEN
                    H := H - 360;
                row[i] := HSVtoRGBTriple(H,S,V)
            END
        END;
    END;
END;

FUNCTION HSVtoRGBTriple(CONST H,S,V: INTEGER): TRGBTriple;
CONST
  divisor: INTEGER = 255 * 60;
VAR
  f: INTEGER;
  hTemp: INTEGER;
  p,q,t: INTEGER;
  VS: INTEGER;
BEGIN
    IF S = 0 THEN
        RESULT := RGBtoRGBTriple(V, V, V)  // achromatic:  shades of gray
    ELSE
    BEGIN                              // chromatic color
        IF H = 360 THEN
            hTemp := 0
        ELSE
            hTemp := H;
        f := hTemp MOD 60;     // f is IN [0, 59]
        hTemp := hTemp DIV 60;     // h is now IN [0,6)
        VS := V * S;
        p := V - VS DIV 255;                 // p = v * (1 - s)
        q := V - (VS*f) DIV divisor;         // q = v * (1 - s*f)
        t := V - (VS*(60 - f)) DIV divisor;  // t = v * (1 - s * (1 - f))
        CASE hTemp OF
            0:   RESULT := RGBtoRGBTriple(V, t, p);
            1:   RESULT := RGBtoRGBTriple(q, V, p);
            2:   RESULT := RGBtoRGBTriple(p, V, t);
            3:   RESULT := RGBtoRGBTriple(p, q, V);
            4:   RESULT := RGBtoRGBTriple(t, p, V);
            5:   RESULT := RGBtoRGBTriple(V, p, q);
        ELSE
            RESULT := RGBtoRGBTriple(0,0,0)  // should never happen;
                                          // avoid compiler warning
        END
    END
END 

The results from Delphi code:

My C# code:

    public struct HSV
    {
        public float h;
        public float s;
        public float v;
    }


    public void createHsvCircle()
    {
        int size = 300;

        wb = new WriteableBitmap(size, size);

        wb.Clear(GraphicsUtils.WhiteColor);

        int radius = size / 2;
        int radiusSquared = radius * radius;

        int x;
        int y;
        int dSquared;

        HSV hsv;
        hsv.v = 255F;

        for (int j = 0; j < size; j++)
        {
            y = size - 1 - j - radius;

            for (int i = 0; i < size; i++)
            {
                x = i - radius;
                dSquared = x * x + y * y;

                if (dSquared <= radiusSquared)
                {
                    hsv.s = (float) Math.Round((255 * Math.Sqrt(dSquared)) / radius);

                    hsv.h = (float) Math.Round(180 * (1 + Math.Atan2(y, x) / Math.PI));

                    hsv.h += 90;
                    if (hsv.h > 360)
                    {
                        hsv.h -= 360;
                    }

                    Color color = GraphicsUtils.HsvToRgb(hsv);

                    wb.SetPixel(i, j, color);
                }
            }
        }

        wb.Invalidate();

    }

    public static Color HsvToRgb(float h, float s, float v)
    {
        h = h / 360;
        if (s > 0)
        {
            if (h >= 1)
                h = 0;
            h = 6 * h;
            int hueFloor = (int)Math.Floor(h);
            byte a = (byte)Math.Round(RGB_MAX * v * (1.0 - s));
            byte b = (byte)Math.Round(RGB_MAX * v * (1.0 - (s * (h - hueFloor))));
            byte c = (byte)Math.Round(RGB_MAX * v * (1.0 - (s * (1.0 - (h - hueFloor)))));
            byte d = (byte)Math.Round(RGB_MAX * v);

            switch (hueFloor)
            {
                case 0: return Color.FromArgb(RGB_MAX, d, c, a);
                case 1: return Color.FromArgb(RGB_MAX, b, d, a);
                case 2: return Color.FromArgb(RGB_MAX, a, d, c);
                case 3: return Color.FromArgb(RGB_MAX, a, b, d);
                case 4: return Color.FromArgb(RGB_MAX, c, a, d);
                case 5: return Color.FromArgb(RGB_MAX, d, a, b);
                default: return Color.FromArgb(RGB_MAX, 0, 0, 0);
            }
        }
        else
        {
            byte d = (byte)(v * RGB_MAX);
            return Color.FromArgb(255, d, d, d);
        }
    }

    public static Color HsvToRgb(HSV hsv)
    {
        return HsvToRgb(hsv.h, hsv.s, hsv.v);
    }       

My c# result:

What I'm doing it wrong?

Thanks in advance.

EDITED WITH SOLUTION

With the great answer from @Aybe, I could do a working version from HSV whell.

This is the working code for WP7 SDK:

    public const double PI = 3.14159265358979323846264338327950288d;

    public void createHsvCircle(double value = 1.0d)
    {
        if (value < 0.0d || value > 1.0d)
            throw new ArgumentOutOfRangeException("value");

        var size = 1024;

        wb = new WriteableBitmap(size, size);

        // fill with white.
        var white = Colors.White;
        for (int index = 0; index < wb.Pixels.Length; index++)
        {
            wb.Pixels[index] = 0xFF << 24 | white.R << 16 | white.G << 8 | white.B;
        }

        var cx = size / 2;
        var cy = size / 2;
        var radius = cx;
        var radiusSquared = radius * radius;
        for (int i = 0; i < size; i++)
        {
            for (int j = 0; j < size; j++)
            {
                var x = i - cx;
                var y = j - cy;
                var distance = (double)x * x + y * y;
                if (distance <= radiusSquared) // In circle
                {
                    var angle = 180.0d * (1 + Math.Atan2(x, y) / PI);

                    // shift 90 degrees so H=0 (red) occurs along "X" axis
                    angle += 90.0d;
                    if (angle > 360.0d)
                    {
                        angle -= 360.0d;
                    }

                    var hue = angle / 360.0d; // hue must be into 0 to 1.
                    var saturation = Math.Sqrt(distance) / radius; // saturation must be into 0 to 1.

                    var hsv = new HSV(hue, saturation, value);
                    var rgb = RGB.FromHsv(hsv.H, hsv.S, hsv.V);

                    wb.Pixels[j * size + i] = 0xFF << 24 | rgb.R << 16 | rgb.G << 8 | rgb.B;
                }
            }

        }
        wb.Invalidate();
    }

    public static RGB FromHsv(double hue, double saturation, double value)
    {
        if (hue < 0.0d || hue > 1.0d)
            throw new ArgumentOutOfRangeException("hue");
        if (saturation < 0.0d || saturation > 1.0d)
            throw new ArgumentOutOfRangeException("saturation");
        if (value < 0.0d || value > 1.0d)
            throw new ArgumentOutOfRangeException("value");

        if (saturation == 0.0d)
        {
            var b1 = (byte)(value * 255);
            return new RGB(b1, b1, b1);
        }

        double r;
        double g;
        double b;

        var h = hue * 6.0d;
        if (h == 6.0d)
        {
            h = 0.0d;
        }

        int i = (int)Math.Floor(h);

        var v1 = value * (1.0d - saturation);
        var v2 = value * (1.0d - saturation * (h - i));
        var v3 = value * (1.0d - saturation * (1.0d - (h - i)));

        switch (i)
        {
            case 0:
                r = value;
                g = v3;
                b = v1;
                break;
            case 1:
                r = v2;
                g = value;
                b = v1;
                break;
            case 2:
                r = v1;
                g = value;
                b = v3;
                break;
            case 3:
                r = v1;
                g = v2;
                b = value;
                break;
            case 4:
                r = v3;
                g = v1;
                b = value;
                break;
            default:
                r = value;
                g = v1;
                b = v2;
                break;
        }

        r = r * 255.0d;
        if (r > 255.0d)
        {
            r = 255.0d;
        }
        g = g * 255.0d;
        if (g > 255.0d)
        {
            g = 255.0d;
        }
        b = b * 255.0d;
        if (b > 255.0d)
        {
            b = 255.0d;
        }

        return new RGB((byte)r, (byte)g, (byte)b);
    }

And now, the new result:

Thanks!

解决方案

After spending an hour or so, I learned a few things in the process ...

Now the code : (works for any size)

This is HSL but I gave you the url where you have other algos.

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace ColorWheel
{
    /// <summary>
    ///   Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void BuildWheel()
        {
            var width = 1024;
            var height = width;
            var cx = width/2;
            var cy = height/2;
            var colors = new int[width*height];
            var gray = Colors.Gray.ToBgr32();
            for (int index = 0; index < colors.Length; index++) colors[index] = gray;

            var radius = cx;
            var radiusSquared = radius*radius;
            for (int i = 0; i < height; i++)
            {
                for (int j = 0; j < width; j++)
                {
                    var x = j - cx;
                    var y = i - cy;
                    var distanceSquared = (double) x*x + y*y;
                    if (distanceSquared <= radiusSquared) // In circle
                    {
                        var h = Math.Atan2(x, y).ToDegrees() + 180.0d; // Angle
                        var s = 1.0d;
                        var l = (1.0d - ((1.0d/radiusSquared)*distanceSquared)); // 1 - (distance normalized)
                        var hsl = new HSL((float) h, (float) s, (float) l);
                        var rgb = RGB.FromHsl(hsl.H, hsl.S, hsl.L);
                        colors[i*width + j] = rgb.R << 16 | rgb.G << 8 | rgb.B;
                    }
                }
            }
            var bitmap = new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr32, null);
            bitmap.WritePixels(new Int32Rect(0, 0, width, height), colors, width*4, 0);
            image.Source = bitmap;
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            BuildWheel();
        }
    }

    public static class Helpers
    {
        public static double ToDegrees(this double radians)
        {
            return radians*57.2957795130823; // radians * (180.0d / Math.PI)
        }

        public static double ToRadians(this double degrees)
        {
            return degrees*0.0174532925199433; // degrees * (Math.PI / 180.0d)
        }
    }

    public static class ColorExtensions
    {
        public static Color FromBgr32(this Int32 color)
        {
            return Color.FromRgb((byte) ((color & 0xFF0000) >> 16), (byte) ((color & 0xFF00) >> 8), (byte) (color & 0xFF));
        }

        public static int ToBgr32(this Color color)
        {
            return color.R << 16 | color.G << 8 | color.B;
        }
    }

    /// <summary>
    ///   Represents a color in an HSL space.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct HSL
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _h;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _s;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly double _l;

        /// <summary>
        ///   Returns the fully qualified type name of this instance.
        /// </summary>
        /// <returns> A <see cref="T:System.String" /> containing a fully qualified type name. </returns>
        /// <filterpriority>2</filterpriority>
        public override string ToString()
        {
            return string.Format("H: {0}, S: {1}, L: {2}", _h, _s, _l);
        }

        /// <summary>
        ///   Create a new instance of <see cref="HSL" /> .
        /// </summary>
        /// <param name="h"> Value of <see cref="H" /> component. </param>
        /// <param name="s"> Value of <see cref="S" /> component. </param>
        /// <param name="l"> Value of <see cref="L" /> component. </param>
        public HSL(double h, double s, double l)
        {
            _h = h;
            _s = s;
            _l = l;
        }

        /// <summary>
        ///   Gets the value of the hue component.
        /// </summary>
        public double H
        {
            get { return _h; }
        }

        /// <summary>
        ///   Gets the value of the saturation component.
        /// </summary>
        public double S
        {
            get { return _s; }
        }

        /// <summary>
        ///   Gets the value of the lightness component.
        /// </summary>
        public double L
        {
            get { return _l; }
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (obj.GetType() != typeof (HSL)) return false;
            return Equals((HSL) obj);
        }

        public bool Equals(HSL other)
        {
            return other._h.Equals(_h) && other._l.Equals(_l) &&
                   other._s.Equals(_s);
        }

        /// <summary>
        ///   Create a new instance of <see cref="HSL" /> , from RGB values.
        /// </summary>
        /// <param name="red"> Value of the red component. </param>
        /// <param name="green"> Value of the green component. </param>
        /// <param name="blue"> Value of the blue component. </param>
        /// <returns> <see cref="HSL" /> instance created. </returns>
        public static HSL FromRGB(byte red, byte green, byte blue)
        {
            var r1 = red/255.0d;
            var g1 = green/255.0d;
            var b1 = blue/255.0d;

            var min = Math.Min(r1, Math.Min(g1, b1));
            var max = Math.Max(r1, Math.Max(g1, b1));

            var l = (max + min)/2.0d;

            var s = 0.0d;
            var h = 0.0d;
            if (min == max)
            {
                h = 0.0d;
                s = 0.0d;
            }
            else
            {
                if (l < 0.5d)
                {
                    s = (max - min)/(max + min);
                }
                else if (l >= 0.5d)
                {
                    s = (max - min)/(2.0d - max - min);
                }

                if (r1 == max)
                {
                    h = (g1 - b1)/(max - min);
                }
                else if (g1 == max)
                {
                    h = 2.0d + (b1 - r1)/(max - min);
                }
                else if (b1 == max)
                {
                    h = 4.0d + (r1 - g1)/(max - min);
                }
            }

            h *= 60.0d;

            if (h < 0.0d)
                h += 360.0d;

            return new HSL(h, s, l);
        }

        /// <summary>
        ///   Returns the hash code for this instance.
        /// </summary>
        /// <returns> A 32-bit signed integer that is the hash code for this instance. </returns>
        /// <filterpriority>2</filterpriority>
        public override int GetHashCode()
        {
            unchecked
            {
                var result = _h.GetHashCode();
                result = (result*397) ^ _l.GetHashCode();
                result = (result*397) ^ _s.GetHashCode();
                return result;
            }
        }


        public static BitmapSource GetHslPalette(int width = 360, int height = 100)
        {
            // Creates an HSL palette image like in Photoshop, etc ...
            var pixels = new int[width*height];
            const double saturation = 1.0d;
            for (var y = 0; y < height; y++)
            {
                for (var x = 0; x < width; x++)
                {
                    var hue = (1.0d/width)*x*360.0d;
                    var lightness = 1.0d - ((1.0f/height)*y);
                    var rgb = RGB.FromHsl(hue, saturation, lightness);
                    pixels[y*width + x] = 0xFF << 24 | rgb.R << 16 | rgb.G << 8 | rgb.B;
                }
            }
            return BitmapSource.Create(width, height, 96, 96, PixelFormats.Pbgra32, null, pixels, width*4);
        }

        public static bool operator ==(HSL left, HSL right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(HSL left, HSL right)
        {
            return !left.Equals(right);
        }
    }

    /// <summary>
    ///   Represents a color in an RGB space.
    /// </summary>
    [StructLayout(LayoutKind.Sequential)]
    public struct RGB
    {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _r;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _g;

        [DebuggerBrowsable(DebuggerBrowsableState.Never)] private readonly byte _b;

        /// <summary>
        ///   Create a new instance of <see cref="RGB" /> .
        /// </summary>
        /// <param name="r"> Value of red component. </param>
        /// <param name="g"> Value of green component. </param>
        /// <param name="b"> Value of blue component. </param>
        public RGB(byte r, byte g, byte b)
        {
            _r = r;
            _g = g;
            _b = b;
        }

        /// <summary>
        ///   Returns the fully qualified type name of this instance.
        /// </summary>
        /// <returns> A <see cref="T:System.String" /> containing a fully qualified type name. </returns>
        /// <filterpriority>2</filterpriority>
        public override string ToString()
        {
            return string.Format("R: {0}, G: {1}, B: {2}", _r, _g, _b);
        }

        /// <summary>
        ///   Gets the value of the red component.
        /// </summary>
        public byte R
        {
            get { return _r; }
        }

        /// <summary>
        ///   Gets the value of the green component.
        /// </summary>
        public byte G
        {
            get { return _g; }
        }

        /// <summary>
        ///   Gets the value of the blue component.
        /// </summary>
        public byte B
        {
            get { return _b; }
        }

        public override bool Equals(object obj)
        {
            if (ReferenceEquals(null, obj)) return false;
            if (obj.GetType() != typeof (RGB)) return false;
            return Equals((RGB) obj);
        }

        public bool Equals(RGB other)
        {
            return other._b == _b && other._g == _g && other._r == _r;
        }

        /// <summary>
        ///   Create a new instance of <see cref="RGB" /> , from HSL values.
        /// </summary>
        /// <param name="hue"> Hue, from 0.0 to 360.0. </param>
        /// <param name="saturation"> Saturation, from 0.0 to 1.0. </param>
        /// <param name="lightness"> Lightness, from 0.0 to 1.0. </param>
        /// <returns> <see cref="RGB" /> instance created. </returns>
        public static RGB FromHsl(double hue, double saturation, double lightness)
        {
            if (hue < 0.0d || hue > 360.0d) throw new ArgumentOutOfRangeException("hue");
            if (saturation < 0.0d || saturation > 1.0d) throw new ArgumentOutOfRangeException("saturation");
            if (lightness < 0.0d || lightness > 1.0d) throw new ArgumentOutOfRangeException("lightness");

            if (saturation == 0.0d)
            {
                var b1 = (byte) (lightness*255);
                return new RGB(b1, b1, b1);
            }

            var t2 = 0.0d;

            if (lightness < 0.5d)
                t2 = lightness*(1.0d + saturation);
            else if (lightness >= 0.5d)
                t2 = lightness + saturation - lightness*saturation;

            var t1 = 2.0d*lightness - t2;

            var h = hue/360.0d;

            var tr = h + 1.0d/3.0d;
            var tg = h;
            var tb = h - 1.0d/3.0d;

            tr = tr < 0.0d ? tr + 1.0d : tr > 1.0d ? tr - 1.0d : tr;
            tg = tg < 0.0d ? tg + 1.0d : tg > 1.0d ? tg - 1.0d : tg;
            tb = tb < 0.0d ? tb + 1.0d : tb > 1.0d ? tb - 1.0d : tb;

            double r;
            if (6.0d*tr < 1.0d)
                r = t1 + (t2 - t1)*6.0d*tr;
            else if (2.0d*tr < 1.0d)
                r = t2;
            else if (3.0d*tr < 2.0d)
                r = t1 + (t2 - t1)*((2.0d/3.0d) - tr)*6.0d;
            else
                r = t1;

            double g;
            if (6.0d*tg < 1.0d)
                g = t1 + (t2 - t1)*6.0d*tg;
            else if (2.0d*tg < 1.0d)
                g = t2;
            else if (3.0d*tg < 2.0d)
                g = t1 + (t2 - t1)*((2.0d/3.0d) - tg)*6.0d;
            else
                g = t1;

            double b;
            if (6.0d*tb < 1.0d)
                b = t1 + (t2 - t1)*6.0d*tb;
            else if (2.0d*tb < 1.0d)
                b = t2;
            else if (3.0d*tb < 2.0d)
                b = t1 + (t2 - t1)*((2.0d/3.0d) - tb)*6.0d;
            else
                b = t1;

            return new RGB((byte) (r*255), (byte) (g*255), (byte) (b*255));
        }

        /// <summary>
        ///   Returns the hash code for this instance.
        /// </summary>
        /// <returns> A 32-bit signed integer that is the hash code for this instance. </returns>
        /// <filterpriority>2</filterpriority>
        public override int GetHashCode()
        {
            unchecked
            {
                var result = _b.GetHashCode();
                result = (result*397) ^ _g.GetHashCode();
                result = (result*397) ^ _r.GetHashCode();
                return result;
            }
        }

        public static bool operator ==(RGB left, RGB right)
        {
            return left.Equals(right);
        }

        public static bool operator !=(RGB left, RGB right)
        {
            return !left.Equals(right);
        }
    }
}

这篇关于将HSV循环代码从Delphi转换为C#的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆