C# 色相(Hue)の平均値を取得する
0(360)をまたぐ色相の画像を作成する
単純な平均
単純に全ピクセルのHue合計から、ピクセル分で割って平均を出すスクリプト。
しかし、これでは平均値が175.6723になってしまった。
private void btnImageAverageHue_Click(object sender, EventArgs e)
{
CalcSimpleHueAverage(@"画像のフルパス");
}
private void CalcSimpleHueAverage(string imgFilePath)
{
Bitmap bmp = new Bitmap(imgFilePath);
List<float> HueList = new List<float>();
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color color = bmp.GetPixel(x, y);
HueList.Add(color.GetHue());
}
}
float avrageHue = 0;
foreach(float hue in HueList)
{
avrageHue += hue;
}
avrageHue /= (float)HueList.Count;
Console.WriteLine(avrageHue.ToString());
}
色相を円形として計算する
灰色部分に色が分布されているので、このエリアから色の平均を取る
まだ、あまり理解していないが、sin,cosを使用して、X,y座標からベクトルを算出して、その平均を求めることで、0の境界線の平均が取れるようだ。
0.742729783566296と理想的な赤の色相の値を取得することが出来た。
private void btnImageAverageHue_Click(object sender, EventArgs e)
{
//CalcSimpleHueAverage(@"画像のフルパス");
CalcCircleHueAverage(@"画像のフルパス");
}
private void CalcCircleHueAverage(string imgFilePath)
{
Bitmap bmp = new Bitmap(imgFilePath);
List<double> HueList = new List<double>();
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color color = bmp.GetPixel(x, y);
HueList.Add(color.GetHue());
}
}
double X = 0.0;
double Y = 0.0;
for (int hue = 0; hue < HueList.Count; ++hue)
{
//Add the X and Y values to the sum X and Y
X += Math.Cos(HueList[hue] / 180.0d * Math.PI);
Y += Math.Sin(HueList[hue] / 180.0d * Math.PI);
}
X /= HueList.Count;
Y /= HueList.Count;
double AverageColor = Math.Atan2(Y, X) * 180.0d / Math.PI;
Console.WriteLine(AverageColor.ToString());
}
Atan2は-nからnの値を取る
Atan2は-nからnの値を取るため、degree(0°~360°)に直した値を返すようにする。
private void btnImageAverageHue_Click(object sender, EventArgs e)
{
//CalcSimpleHueAverage(@"D:\Projects\private\CSharp\Color\HueAverageTest.png");
Bitmap bmp = new Bitmap(@"D:\Projects\private\CSharp\Color\HueAverageTest.png");
List<double> HueList = new List<double>();
for (int y = 0; y < bmp.Height; y++)
{
for (int x = 0; x < bmp.Width; x++)
{
Color color = bmp.GetPixel(x, y);
HueList.Add(color.GetHue());
}
}
CalcCircleHueAverage(HueList);
}
private double fmod(double a, double b)
{
return a - Math.Floor(a / b) * b;
}
private double CalcCircleHueAverage(List<double> HueList)
{
double X = 0.0;
double Y = 0.0;
for (int hue = 0; hue < HueList.Count; ++hue)
{
//Add the X and Y values to the sum X and Y
X += Math.Cos(HueList[hue] / 180.0d * Math.PI);
Y += Math.Sin(HueList[hue] / 180.0d * Math.PI);
}
X /= HueList.Count;
Y /= HueList.Count;
double AverageColor = fmod(Math.Atan2(Y, X) * 180.0d / Math.PI, 360d);
return AverageColor;
}
参照
Averaging circular values (particularly Hues in HSL color scheme)
http://stackoverflow.com/questions/13959276/averaging-circular-values-particularly-hues-in-hsl-color-scheme
How can i average Hue value in image?
https://jp.mathworks.com/matlabcentral/answers/111370-how-can-i-average-hue-value-in-image?requestedDomain=www.mathworks.com
色相の平均値の算出方法
http://okwave.jp/qa/q3582670.html
How to map atan2() to degrees 0-360
http://stackoverflow.com/questions/1311049/how-to-map-atan2-to-degrees-0-360