Contents ...
udn網路城邦
使用C#繪製CIE 1931色度圖
2018/03/09 02:34
瀏覽1,239
迴響0
推薦0
引用0

1.媒介:
在很多應用中,例如LED照明就需要操縱色度圖來視察發光的顏色,色溫等趨向,本文計議若何哄騙C#程式繪製色度圖,為簡化程式,僅討論CIE 1931 標準色度2度視角調查者的色度圖,色彩系統採用NTSC。

2.申明:
RGB色采空間系統參考wiki的說明
http://en.wikipedia.org/wiki/RGB_color_space
http://en.wikipedia.org/wiki/Standard_illuminant#Illuminants_B_and_C

CIE1931色采空間
http://en.wikipedia.org/wiki/CIE_1931_color_space
http://www.fourmilab.ch/documents/specrend/

CIE 1931 標準色度2度視角觀察者xyz函數的資料集
http://cvrl.ioo.ucl.ac.uk/

CIE色度圖Delphi程式碼可參考
http://www.efg2.com/Lab/Graphics/Colors/Chromaticity.htm

CIE 1931 2° Standard Observer Color Matching Functions

private void DrawColorMatchingFunctions()
{
//利用SteemaTeeChart繪製Color Matching Functions Curve
tChart1.Chart.Aspect.View3D = false;
Steema.TeeChart.Styles.Line line1 = new Steema.TeeChart.Styles.Line();
Steema.TeeChart.Styles.Line line2 = new Steema.TeeChart.Styles.Line();
Steema.TeeChart.Styles.Line line3 = new Steema.TeeChart.Styles.Line();
line1.LinePen.Width = 3;
line2.LinePen.Width = 3;
line3.LinePen.Width = 3;
line1.Color = Color.Red;
line2.Color = Color.Green;
line3.Color = Color.Blue;            
tChart1.Chart.Series.Add(line1);
tChart1.Chart.Series.Add(line2);
tChart1.Chart.Series.Add(line3);

//讀取資料
DataTable dt = TxtConvertToDataTable(@"d:\tmp\da.csv", "tmp", ",");

for (int i = 0; i < dt.Rows.Count; i++)
{
line1.Add(double.Parse(dt.Rows[i]["Lamda"].ToString()), double.Parse(dt.Rows[i]["Xt"].ToString()));
line2.Add(double.Parse(dt.Rows[i]["Lamda"].ToString()), double.Parse(dt.Rows[i]["Yt"].ToString()));
line3.Add(double.Parse(dt.Rows[i]["Lamda"].ToString()), double.Parse(dt.Rows[i]["Zt"].ToString()));
}

//設定繪圖區顯示設定
tChart1.Chart.Series[0].Title = "CIE-X(Red)";
tChart1.Chart.Series[1].Title = "CIE-Y(Green)";
tChart1.Chart.Series[2].Title = "CIE-Z(Blue)";
tChart1.Chart.Axes.Bottom.Title.Text = "Wavelength [nm]";
tChart1.Chart.Axes.Left.Title.Text = "Tristimulus values";
tChart1.Header.Text = "CIE 1931 2° Standard Observer Color Matching Functions";
tChart1.Header.TextAlign = StringAlignment.Center;
tChart1.Legend.Alignment = Steema.TeeChart.LegendAlignments.Top;
tChart1.Legend.TopLeftPos = -16;
tChart1.Chart.Axes.Left.SetMinMax(0, 2);
}

Color Matching Functions繪圖:

ColorMatchingFUnctions  

The CIE 1931 Color Space Chromaticity Diagram


NTSC系統種別

public class NTSCsystem
{
public static double xRed = 0.67;
public static double yRed = 0.33;
public static double xGreen = 0.21;
public static double yGreen = 0.71;
public static double xBlue = 0.14;
public static double yBlue = 0.08;
public static double xWhite = 0.310;
public static double yWhite = 0.316;
}

 

繪製馬蹄形圖

private void DrawHorseArea(DataTable dt, Graphics gg, Image img)
{
double x = 0, y = 0, z = 0;
double[] xy;
int[] rgb = new Int32[3];

for (int i = 0; i <= img.Width; i+=1)
{
for (int j = 0; j <= img.Height; j+=1)
{
xy = PixelToCoordinate(i, j, img.Width, img.Height);
x = xy[0];
y = xy[1];
z = 1 - x - y;

if (IsInsideHorseShape(dt, x, y) == true)
{
rgb = rgbData(x, y, z);
SolidBrush s = new SolidBrush(Color.FromArgb(rgb[0], rgb[1], rgb[2]));
RectangleF rec = new RectangleF(i, img.Height - j, 1, 1);
gg.FillRectangle(s, rec);
}                    
}
}
}

 

繪製馬蹄形界限圖

private void DrawBoundary(DataTable dt, Graphics gg, Image img)
{
int lamda = 0;
double StartPointX = 0, StartPointY = 0, StartPointZ = 0;
double EndPointX = 0, EndPointY = 0, EndPointZ = 0;
double PositionX = 0, PositionY = 0;
int[] rgb = new Int32[3];

//繪製馬蹄形界限
for (int i = 0; i < dt.Rows.Count - 1; i++)
{
StartPointX = double.Parse(dt.Rows[i]["x"].ToString());
StartPointY = double.Parse(dt.Rows[i]["y"].ToString());
StartPointZ = double.Parse(dt.Rows[i]["z"].ToString());

EndPointX = double.Parse(dt.Rows[i + 1]["x"].ToString());
EndPointY = double.Parse(dt.Rows[i + 1]["y"].ToString());
EndPointZ = double.Parse(dt.Rows[i + 1]["z"].ToString());

rgb = rgbData(StartPointX, StartPointY, StartPointZ);

SolidBrush s = new SolidBrush(Color.FromArgb(rgb[0], rgb[1], rgb[2]));
gg.DrawLine(new Pen(s, 1), (float)StartPointX * img.Width, img.Height - (float)StartPointY * img.Height, (float)EndPointX * img.Width, img.Height - (float)EndPointY * img.Height);
}

//波長從420nm到680nm,繪製mark
for (int i = 60; i <= 320; i++)
{
lamda = int.Parse(dt.Rows[i]["Lamda"].ToString());

if (lamda % 10 == 0)//每10nm繪製mark
{
if (lamda >= 460 && lamda <= 630)//430nm到450nm以及640nm到670nm不繪製,避免堆疊
{
PositionX = double.Parse(dt.Rows[i]["x"].ToString());
PositionY = double.Parse(dt.Rows[i]["y"].ToString());
SolidBrush s = new SolidBrush(Color.White);
gg.DrawLine(new Pen(s), (float)PositionX * img.Width, img.Height - (float)PositionY * img.Height, (float)PositionX * img.Width, img.Height - (float)PositionY * img.Height - 10);
gg.DrawString(lamda.ToString(), new Font("Arial", 7), s, (float)PositionX * img.Width - 5, img.Height - (float)PositionY * img.Height - 20);
}

if (lamda == 420 || lamda == 680)
{
PositionX = double.Parse(dt.Rows[i]["x"].ToString());
PositionY = double.Parse(dt.Rows[i]["y"].ToString());
SolidBrush s = new SolidBrush(Color.White);
gg.DrawLine(new Pen(s), (float)PositionX * img.Width, img.Height - (float)PositionY * img.Height, (float)PositionX * img.Width, img.Height - (float)PositionY * img.Height - 10);
gg.DrawString(lamda.ToString(), new Font("Arial", 7), s, (float)PositionX * img.Width - 5, img.Height - (float)PositionY * img.Height - 20);
}
}
}
}

 

繪製馬蹄形界限底線圖

private void DrawBottomLine(DataTable dt, Graphics gg, Image img)
{
double x = 0, y = 0, z = 0;
double x1 = 0, y1 = 0, z1 = 0;
int[] rgb = new Int32[3];

double minWavelengthXCoordinate = 0;
double minWavelengthYCoordinate = 0;
double maxWavelengthXCoordinate = 0;
double maxWavelengthYCoordinate = 0;

//360nm (x,y)
minWavelengthXCoordinate = double.Parse(dt.Rows[0]["x"].ToString());
minWavelengthYCoordinate = double.Parse(dt.Rows[0]["y"].ToString());

//830nm (x,y)
maxWavelengthXCoordinate = double.Parse(dt.Rows[dt.Rows.Count - 1]["x"].ToString());
maxWavelengthYCoordinate = double.Parse(dt.Rows[dt.Rows.Count - 1]["y"].ToString());

double XCoordinateDistance = maxWavelengthXCoordinate - minWavelengthXCoordinate;
double YCoordinateDistance = maxWavelengthYCoordinate - minWavelengthYCoordinate;
double Slope = YCoordinateDistance / XCoordinateDistance;

for (double i = minWavelengthXCoordinate; i < maxWavelengthXCoordinate; i += 0.002)
{
//直線方程式: y = (x - xmin) * Slope + ymin
x = i;
y = (x - minWavelengthXCoordinate) * Slope + minWavelengthYCoordinate;
z = 1 - x - y;

x1 = i + 0.002;
y1 = (x1 - minWavelengthXCoordinate) * Slope + minWavelengthYCoordinate;
z1 = 1 - x1 - y1;

rgb = rgbData(x, y, z);

SolidBrush s = new SolidBrush(Color.FromArgb(rgb[0], rgb[1], rgb[2]));
gg.DrawLine(new Pen(s, 1), (float)x * img.Width, img.Height - (float)y * img.Height, (float)x1 * img.Width, img.Height - (float)y1 * img.Height);
}
}

 

繪製色溫曲線

private void DrawColorTemperatureCurve(DataTable dt, Graphics gg, Image img)
{
string temp = "";
double StartPointX = 0, StartPointY = 0;
double EndPointX = 0, EndPointY = 0;
double PositionX = 0, PositionY = 0;

for (int i = 0; i < dt.Rows.Count - 1; i++)
{
temp = dt.Rows[i]["Temp"].ToString();

StartPointX = double.Parse(dt.Rows[i]["x"].ToString());
StartPointY = double.Parse(dt.Rows[i]["y"].ToString());

EndPointX = double.Parse(dt.Rows[i + 1]["x"].ToString());
EndPointY = double.Parse(dt.Rows[i + 1]["y"].ToString());

PositionX = double.Parse(dt.Rows[i]["x"].ToString());
PositionY = double.Parse(dt.Rows[i]["y"].ToString());

SolidBrush s = new SolidBrush(Color.FromArgb(255, 255, 255));
gg.DrawLine(new Pen(s, 1), (float)StartPointX * img.Width, img.Height - (float)StartPointY * img.Height, (float)EndPointX * img.Width, img.Height - (float)EndPointY * img.Height);

if (i != 4 && i != 8 && i != 10 && i != 12)
{
gg.DrawString(temp.ToString(), new Font("Arial", 5), s, (float)PositionX * img.Width - 5, img.Height - (float)PositionY * img.Height + 10);
SolidBrush ss = new SolidBrush(Color.FromArgb(255, 0, 0));
RectangleF rec = new RectangleF((float)PositionX * img.Width - 2, img.Height - (float)PositionY * img.Height - 2, 4, 4);
gg.FillEllipse(ss, rec);
}
else//將堆疊的文字置於色溫線上方
{
gg.DrawString(temp.ToString(), new Font("Arial", 5), s, (float)PositionX * img.Width - 10, img.Height - (float)PositionY * img.Height - 15);
SolidBrush ss = new SolidBrush(Color.FromArgb(255, 0, 0));
RectangleF rec = new RectangleF((float)PositionX * img.Width - 2, img.Height - (float)PositionY * img.Height - 2, 4, 4);
gg.FillEllipse(ss, rec);
}
}
}

繪圖:

CIEColorTemperature  

CIE1931Chart  

 

3.利用:

//讀取檔案
DataTable da = TxtConvertToDataTable(@"D:\TMP\da.csv", "tmp", ",");
DataTable db = TxtConvertToDataTable(@"D:\TMP\db.csv", "tmp", ",");
//界說影象檔
Image img = new Bitmap(500, 500);
//在image上繪圖
Graphics gg = Graphics.FromImage(img);
//畫圖品質設定
gg.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
gg.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighQuality;
gg.CompositingQuality = CompositingQuality.HighQuality;
gg.SmoothingMode = SmoothingMode.AntiAlias;
gg.InterpolationMode = InterpolationMode.High;
//先將靠山色設定為黑色
gg.FillRectangle(new SolidBrush(Color.Black), 0, 0, 500, 500);

//繪製馬蹄形圖
DrawHorseArea(da, gg, img);
//繪製馬蹄形鴻溝圖
DrawBoundary(da, gg, img);
//繪製馬蹄形邊界底線圖
DrawBottomLine(da, gg, img);
//繪製色溫曲線
DrawColorTemperatureCurve(db, gg, img);

//顯示影象
pictureBox1.Image = img;
文章標籤
C# CIE 1931 色度圖


本篇文章引用自此: http://einboch.pixnet.net/blog/post/260933867-%e5%88%a9%e7%94%a8c%23%e7%b9%aa%e8%a3%bdcie-1931%e8%89

限會員,要發表迴響,請先登入