VIS2 SS2013 CVD DVR
 All Classes Namespaces Functions Enumerations Properties
CVDtf.cs
1 #region Using Statements
2 using System;
3 using System.Collections.Generic;
4 using System.Linq;
5 using System.Text;
6 using System.Collections.Generic;
7 using System.Linq;
8 using System.Text;
9 using Microsoft.Xna.Framework;
10 using Microsoft.Xna.Framework.Graphics;
11 using Microsoft.Xna.Framework.Graphics.PackedVector;
12 using System.IO;
13 using ILNumerics;
14 
15 #endregion
16 
17 namespace visLU.CVD
18 {
23  class CVDtf
24  {
25  #region Variables
26 
27  Texture2D recoloredImage; //recolored Image Ir
28  Texture2D recoloredImageTest; //for debug
29  Texture2D recoloredImageMask; //selected Pixels only
30 
31  List<TransferControlPoint> colorCP; //refrence transfer function Tc color and opacity
32  List<TransferControlPoint> alphaCP;
33 
34  List<TransferControlPoint> cvdColorCP; //cvd tf Tc*
35  Texture2D cvdTransferTexture;
36 
37  int M; //control point count in the reference tf == color labels, default < 8
38  int N; //pixel count in the image
39  int Nr; //pixel to select from the recolored image, default = 200, Nr > M
40  double[] delta; //parameter for color preservation, delta[m] = [0;1], m = 0,...,#(ControlPoints - 1)
41  float lambda; //parameter for the the tf color adjustmant: lambda = [0;1], labmda = 0 : cvd image == recolored image
42  //accumulated weight for the reference tf (= matrixA)
43  ILArray<double> omegaWeightsR;
44  ILArray<double> omegaWeightsG;
45  ILArray<double> omegaWeightsB;
46 
47  Point[] selectedPixels; //selcted Pixels positions
48  //colors of Nr selected pixels from the recolored image != background pixels
49  ILArray<double> recoloredPixelsR;
50  ILArray<double> recoloredPixelsG;
51  ILArray<double> recoloredPixelsB;
52  // = Color[,] b; //==crk
53 
54  //GeneralMatrix x; //== ct*m cvd tf color set
55  ILArray<double> xR;
56  ILArray<double> xG;
57  ILArray<double> xB;
58 
59  GraphicsDevice graphics;
60 
61  #endregion
62 
63  #region Properties
64  public float Lambda
65  {
66  set { lambda = value; }
67  }
68  public double[] Delta
69  {
70  set { delta = value; }
71  }
72  public Texture2D CVDtransferFunction
73  {
74  get { return cvdTransferTexture; }
75  }
76  public Point[] SelectedPixels
77  {
78  get { return selectedPixels; }
79  }
80  public Texture2D RecoloredImageMask
81  {
82  get { return recoloredImageMask; }
83  }
84  #endregion
85 
86  #region Constructor
87  public CVDtf(Texture2D _recoloredImage, GraphicsDevice _graphics)
88  {
89  graphics = _graphics;
90  recoloredImage = _recoloredImage;
91  recoloredImageTest = _recoloredImage;
92  recoloredImageMask = new Texture2D(graphics, recoloredImage.Width, recoloredImage.Height, false, SurfaceFormat.Rgba64);
93 
94 
95  colorCP = GameProperties.Instance.colorControlPoints;
96  alphaCP = GameProperties.Instance.alphaControlPoints;
97 
98  N = recoloredImage.Width * recoloredImage.Height;
99  Nr = 200; //default value; M < Nr <= N!
100  M = colorCP.Count;
101  if (Nr <= M) Nr = M + (int)((N - M) * 0.5f); //todo optimize this Nr will be tooo big
102  if (Nr >= N) Nr = N - (int)((N - M) * 0.5f);
103  selectedPixels = new Point[Nr];
104  recoloredPixelsR = ILMath.zeros(Nr, 1);
105  recoloredPixelsG = ILMath.zeros(Nr, 1);
106  recoloredPixelsB = ILMath.zeros(Nr, 1);
107 
108  //TODO
109  delta = new double[M];
110  for (int i = 0; i < delta.Length; i++)
111  {
112  delta[i] = 0.0f;
113  }
114 
115  lambda = GameProperties.Instance.lambda; //TODO
116 
117  //omega Weights
118  omegaWeightsR = ILMath.ones(Nr, M);
119  omegaWeightsG = ILMath.ones(Nr, M);
120  omegaWeightsB = ILMath.ones(Nr, M);
121 
122  }
123  #endregion
124 
125  #region Methods
126 
127  private void saveScreenshot(Texture2D texture, String name, String ext)
128  {
129  Console.WriteLine("saving " + name);
130  try
131  {
132  if (!name.ElementAt(name.Length - 4).Equals(".")) name = name + "." + ext;
133  FileStream stream = File.OpenWrite(name);
134  switch (ext)
135  {
136  case "png":
137  texture.SaveAsPng(stream, texture.Width, texture.Height);
138  break;
139  case "jpg":
140  texture.SaveAsJpeg(stream, texture.Width, texture.Height);
141  break;
142  default:
143  if (name.ElementAt(name.Length - 4).Equals(".")) name = name.Substring(0, name.Length - 4);
144  name = name + ".png";
145  texture.SaveAsPng(stream, texture.Width, texture.Height);
146  break;
147  }
148 
149  }
150  catch (Exception e)
151  {
152  Console.WriteLine("Save Screenshot: ");
153  Console.WriteLine(e);
154  }
155 
156  }
157 
158  public void selectRecoloredPixels()
159  {
160 
161  saveScreenshot(recoloredImage, "recoloredImageForCVD", "png"); //debug
162  Rgba64[] recoloredArray = new Rgba64[recoloredImage.Width * recoloredImage.Height];
163  recoloredImage.GetData<Rgba64>(recoloredArray);
164  //Color[] recoloredArray = new Color[recoloredImageTest.Width * recoloredImageTest.Height];
165  //recoloredImageTest.GetData<Color>(recoloredArray);
166 
167  Rgba64[] recoloredArrayMask = new Rgba64[recoloredImage.Width * recoloredImage.Height];
168  recoloredArrayMask.Initialize();
169 
170  #region debug
171  Texture2D selectedPixelsMask = new Texture2D(graphics, recoloredImage.Width, recoloredImage.Height, false, SurfaceFormat.Color);
172  Color[] selectedPixelsArray = new Color[recoloredImage.Width * recoloredImage.Height];
173  for (int i = 0; i < selectedPixelsArray.Length; i++)
174  {
175  selectedPixelsArray[i] = Color.Black;
176  }
177  #endregion
178  for (int j = 0; j < recoloredArrayMask.Length; j++)
179  {
180  recoloredArrayMask[j] = new Rgba64(0, 0, 0, 1);
181  }
182 
183  Random randomPos = new Random();
184  Random randomScale = new Random();
185  int next = 0;
186  while (next < Nr)
187  {
188 
189  double xScale = randomPos.NextDouble();
190  double yScale = randomPos.NextDouble();
191  int x = (int)(randomScale.Next(recoloredImage.Width) * xScale);
192  int y = (int)(randomScale.Next(recoloredImage.Height) * yScale);
193  int selectedPos = x + y * recoloredImage.Width;
194 
195  #region median filter
196  //get the median
197  /*int filtersize = 5;
198  List<Vector3> neighbours = new List<Vector3>();
199 
200  int offsetX = (-1) * (filtersize - 1) / 2;
201  int offsetY = (-1) * (filtersize - 1) / 2;
202  for (int j = 0; j < filtersize; j++)
203  {
204  offsetX = (-1) * (filtersize - 1) / 2;
205  for (int i = 0; i < filtersize; i++)
206  {
207  //rand
208  int nX = (int)MathHelper.Clamp(x + offsetX, 0, recoloredImage.Width - 1);
209  int nY = (int)MathHelper.Clamp(y + offsetY, 0, recoloredImage.Height - 1);
210  Vector4 neighbour = recoloredArray[nX + nY*recoloredImage.Width].ToVector4();
211  neighbours.Add(new Vector3(neighbour.X, neighbour.Y, neighbour.Z));
212 
213  offsetX++;
214  }
215  offsetY++;
216  }
217 
218  //sort list
219  neighbours.Sort(delegate(Vector3 n1, Vector3 n2) { return (n1.Length().CompareTo(n2.Length())); });
220 
221  Vector3 selectedPixel = neighbours[(filtersize * filtersize - 1) / 2];*/
222  #endregion
223 
224  #region average filter
225  /*int filtersize = 11;
226  Vector3 avgColor = Vector3.Zero;
227 
228  int offsetX = (-1) * (filtersize - 1) / 2;
229  int offsetY = (-1) * (filtersize - 1) / 2;
230  for (int j = 0; j < filtersize; j++)
231  {
232  offsetX = (-1) * (filtersize - 1) / 2;
233  for (int i = 0; i < filtersize; i++)
234  {
235  //rand
236  int nX = (int)MathHelper.Clamp(x + offsetX, 0, recoloredImage.Width - 1);
237  int nY = (int)MathHelper.Clamp(y + offsetY, 0, recoloredImage.Height - 1);
238  Vector4 neighbour = recoloredArray[nX + nY * recoloredImage.Width].ToVector4();
239  avgColor.X += neighbour.X;
240  avgColor.Y += neighbour.Y;
241  avgColor.Z += neighbour.Z;
242  offsetX++;
243  }
244  offsetY++;
245  }
246 
247  Vector3 selectedPixel = new Vector3(avgColor.X / (filtersize * filtersize), avgColor.Y / (filtersize * filtersize), avgColor.Z / (filtersize * filtersize));
248  */
249  #endregion
250 
251  Vector4 selectedPixel = recoloredArray[selectedPos].ToVector4();
252  if (selectedPixel.X > 0.2f || selectedPixel.Y > 0.2f || selectedPixel.Z > 0.2f) //ignore background pixels
253  {
254 
255 
256  selectedPixels[next] = new Point(x, y);
257  recoloredPixelsR.SetValue((double)selectedPixel.X, next, 0);
258  recoloredPixelsG.SetValue((double)selectedPixel.Y, next, 0);
259  recoloredPixelsB.SetValue((double)selectedPixel.Z, next, 0);
260  //Console.WriteLine("Weights for SP:" + selectedPixelsInArray[i] + ":" + selectedPixel.X + "," + selectedPixel.Y + "," + selectedPixel.Z + "," + selectedPixel.W);
261  //Console.WriteLine("Selected Pixels: x" + x + ", y:" + y + ", pos:" + (x + y * recoloredImage.Width));
262  //Console.WriteLine("Selected Colors: R" + selectedColor.R + ", G:" + selectedColor.G + ", B:" + selectedColor.B);
263  recoloredArrayMask[selectedPos] = new Rgba64((float)x / recoloredImage.Width, (float)y / recoloredImage.Height, 0.0f, 1.0f);
264  selectedPixelsArray[selectedPos] = new Color(selectedPixel); //debug
265  next++;
266  }
267  }
268 
269 
270  #region debug
271  //Console.WriteLine("#Selected Colors:" + selectedPixelsPos.Length);
272  recoloredImageMask.SetData<Rgba64>(recoloredArrayMask);
273  selectedPixelsMask.SetData<Color>(selectedPixelsArray);
274  if (GameProperties.Instance.debugOutput)
275  {
276  saveScreenshot(recoloredImageMask, "recoloredImageMask", "png");
277  saveScreenshot(selectedPixelsMask, "selectedPixelsMask", "png");
278  }
279  //selectedPixelsMask.Dispose();
280  #endregion
281 
282  }
283 
284 
285  public Texture2D calculateCVDColors()
286  {
287 
288  #region calculate cvd colors for the tf
289  xR = ILMath.linsolve(omegaWeightsR, recoloredPixelsR);
290  xG = ILMath.linsolve(omegaWeightsG, recoloredPixelsG);
291  xB = ILMath.linsolve(omegaWeightsB, recoloredPixelsB);
292 
293  //check variance and error
294  //E1
295  ILArray<double> bTestR = ILMath.multiply(omegaWeightsR, xR);
296  ILArray<double> errR = ILMath.abs(bTestR - recoloredPixelsR);
297  ILArray<double> errRnorm = ILMath.norm(bTestR - recoloredPixelsR);
298 
299  ILArray<double> bTestG = ILMath.multiply(omegaWeightsG, xG);
300  ILArray<double> errG = ILMath.abs(bTestG - recoloredPixelsG);
301  ILArray<double> errGnorm = ILMath.norm(bTestG - recoloredPixelsG);
302 
303  ILArray<double> bTestB = ILMath.multiply(omegaWeightsB, xB);
304  ILArray<double> errB = ILMath.abs(bTestB - recoloredPixelsB);
305  ILArray<double> errBnorm = ILMath.norm(bTestB - recoloredPixelsB);
306 
307  #region debug
308  //scale
309  double max = 0.0f;
310  for (int i = 0; i < M; i++)
311  {
312  max = Math.Max(Math.Abs(xR.GetValue(i, 0)), max);
313  max = Math.Max(Math.Abs(xG.GetValue(i, 0)), max);
314  max = Math.Max(Math.Abs(xB.GetValue(i, 0)), max);
315 
316  }
317 
318  /*for (int i = 0; i < M; i++)
319  {
320  xR.SetValue((xR.GetValue(i, 0)/max) / 2 + 0.5f ,i);
321  xG.SetValue((xG.GetValue(i, 0)/max) / 2 + 0.5f, i);
322  xB.SetValue((xB.GetValue(i, 0)/max) / 2 + 0.5f, i);
323  }*/
324  #endregion
325 
326  //cvd transfer function <-> reference transfer function
327  // sort reference ControlPoints Ct by isoValue
328  List<TransferControlPoint> ctColorCP = GameProperties.Instance.colorControlPoints;
329  ctColorCP.Sort(delegate(TransferControlPoint cp1,
330  TransferControlPoint cp2) { return cp1.isoValue.CompareTo(cp2.isoValue); });
331 
332  ILArray<double> deltaWeights = ILMath.zeros(M, 1);
333  ILArray<double> referenceTFR = ILMath.zeros(M, 1);
334  ILArray<double> referenceTFG = ILMath.zeros(M, 1);
335  ILArray<double> referenceTFB = ILMath.zeros(M, 1);
336  for (int i = 0; i < M; i++)
337  {
338  deltaWeights.SetValue(delta[i], i, 0);
339  referenceTFR.SetValue(ctColorCP[i].color.X * delta[i], i, 0);
340  referenceTFG.SetValue(ctColorCP[i].color.Y * delta[i], i, 0);
341  referenceTFB.SetValue(ctColorCP[i].color.Z * delta[i], i, 0);
342  }
343 
344  ILArray<double> xR2 = ILMath.linsolve(deltaWeights, referenceTFR);
345  ILArray<double> xG2 = ILMath.linsolve(deltaWeights, referenceTFG);
346  ILArray<double> xB2 = ILMath.linsolve(deltaWeights, referenceTFB);
347 
348  //E1
349  ILArray<double> bTestR2 = ILMath.multiply(deltaWeights, xR2);
350  ILArray<double> errR2 = ILMath.abs(bTestR2 - referenceTFR);
351  ILArray<double> errRnorm2 = ILMath.norm(errR2);
352 
353  ILArray<double> bTestG2 = ILMath.multiply(deltaWeights, xG2);
354  ILArray<double> errG2 = ILMath.abs(bTestG2 - referenceTFG);
355  ILArray<double> errGnorm2 = ILMath.norm(errG2);
356 
357  ILArray<double> bTestB2 = ILMath.multiply(deltaWeights, xB2);
358  ILArray<double> errB2 = ILMath.abs(bTestB2 - referenceTFG);
359  ILArray<double> errBnorm2 = ILMath.norm(errB2);
360 
361 
362 
363  //lambda
364  for (int i = 0; i < M; i++)
365  {
366  xR.SetValue((1 - lambda) * xR.GetValue(i, 0) + lambda * xR2.GetValue(0,0) , i, 0);
367  xG.SetValue((1 - lambda) * xG.GetValue(i, 0) + lambda * xG2.GetValue(0, 0), i, 0);
368  xB.SetValue((1 - lambda) * xB.GetValue(i, 0) + lambda * xB2.GetValue(0, 0), i, 0);
369  }
370 
371  #endregion
372 
373  #region set in the cvd cp list
374  cvdColorCP = new List<TransferControlPoint>();
375  for (int i = 0; i < M; i++)
376  {
377  //cvdColorCP.Add(new TransferControlPoint((float)xR.GetValue(M - 1 - i, 0), (float)xG.GetValue(M - 1 - i, 0), (float)xB.GetValue(M - 1 - i, 0), ctColorCP[i].isoValue));
378  cvdColorCP.Add(new TransferControlPoint((float)xR.GetValue(i, 0), (float)xG.GetValue(i, 0), (float)xB.GetValue(i, 0), ctColorCP[i].isoValue));
379  }
380  GameProperties.Instance.cvdColorControlPoints = cvdColorCP;
381  #endregion
382 
383 
384  #region interpolate between ControlPoints
385  float amount = 0.0f;
386  Color[] colorArray = new Color[256];
387 
388  // sort ControlPoints by isoValue
389  cvdColorCP.Sort(delegate(TransferControlPoint p1,
390  TransferControlPoint p2) { return p1.isoValue.CompareTo(p2.isoValue); });
391 
392  // before first ControlPoint: fill with black and alpha 0.0f
393  for (int i = 0; i < cvdColorCP[0].isoValue; i++)
394  {
395  colorArray[i] = new Color(0.0f, 0.0f, 0.0f, 0.0f);
396  }
397 
398  for (int j = 0; j < cvdColorCP.Count - 1; j++)
399  {
400  for (int i = cvdColorCP[j].isoValue; i <= cvdColorCP[j + 1].isoValue; i++)
401  {
402  amount = (((float)i - cvdColorCP[j].isoValue) /
403  (cvdColorCP[j + 1].isoValue - cvdColorCP[j].isoValue));
404  colorArray[i] = Color.Lerp(new Color(cvdColorCP[j].color),
405  new Color(cvdColorCP[j + 1].color), amount);
406  }
407  }
408 
409  //after last ControlPoint: fill with black and alpha
410  for (int i = cvdColorCP[cvdColorCP.Count - 1].isoValue + 1; i < 256; i++)
411  {
412  colorArray[i] = new Color(0.0f, 0.0f, 0.0f, 0.0f);
413  }
414  #endregion
415 
416  #region set texture
417  //interpolate texture
418  cvdTransferTexture = new Texture2D(graphics, 256, 1, false, SurfaceFormat.Color);
419  cvdTransferTexture.SetData<Color>(colorArray);
420  saveScreenshot(cvdTransferTexture, "CVDTF", "png");
421  #endregion
422 
423  return cvdTransferTexture;
424  }
425 
426 
427  public void setTFWeights(Texture2D weights, int controlPointIdx)
428  {
429  if (controlPointIdx >= M) return;
430 
431  Rgba64[] weightsArray = new Rgba64[weights.Width * weights.Height];
432  weights.GetData<Rgba64>(weightsArray);
433 
434 
435  for (int i = 0; i < selectedPixels.Length; i++)
436  {
437  int pos = (selectedPixels[i].X + selectedPixels[i].Y * weights.Width);
438  Vector4 nextWeight = weightsArray[pos].ToVector4();
439 
440  omegaWeightsR.SetValue((double)nextWeight.X, i, controlPointIdx);
441  omegaWeightsG.SetValue((double)nextWeight.Y, i, controlPointIdx);
442  omegaWeightsB.SetValue((double)nextWeight.Z, i, controlPointIdx);
443 
444  if (GameProperties.Instance.debugOutput)
445  {
446  Console.WriteLine("Weights for CP:" + controlPointIdx + ":" + nextWeight.X + "," + nextWeight.Y + "," + nextWeight.Z + "," + nextWeight.W);
447  }
448 
449  }
450 
451  }
452  #endregion
453  }
454 }