Edited at

C# 色相(Hue)の平均値を取得する

More than 1 year has passed since last update.


C# 色相(Hue)の平均値を取得する


0(360)をまたぐ色相の画像を作成する

色相(Hue)

339~360 0~23のグラデーションを作成する

正方形の画像を作成し、色相の平均値を取得する


単純な平均

単純に全ピクセルのHue合計から、ピクセル分で割って平均を出すスクリプト。

しかし、これでは平均値が175.6723になってしまった。


SimpleAverage.cs


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と理想的な赤の色相の値を取得することが出来た。


CalcCircleHueAverage.cs


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°)に直した値を返すようにする。


CalcCircleHueAverage.cs

        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