public DNGMatrix4x4(DNGMatrix m) : base(m) { // Input must be either 3x3 or 4x4. bool is3by3 = (m.Rows == 3 && m.Cols == 3); bool is4by4 = (m.Rows == 4 && m.Cols == 4); if (!is3by3 && !is4by4) { throw new ArgumentException("This is not a 3x3 or 4x4 Matrix"); } // For 3x3 case, pad to 4x4 (equivalent 4x4 matrix). if (is3by3) { _rows = 4; _cols = 4; _data[0, 3] = 0.0; _data[1, 3] = 0.0; _data[2, 3] = 0.0; _data[3, 0] = 0.0; _data[3, 1] = 0.0; _data[3, 2] = 0.0; _data[3, 3] = 1.0; } }
public static DNGMatrix operator *(DNGMatrix vec, double scale) { DNGMatrix ret = new DNGMatrix(vec); ret.Scale(scale); return(ret); }
public static DNGMatrix Identity(uint size) { DNGMatrix mat = new DNGMatrix(); mat.SetIdentity(size); return(mat); }
public DNGMatrix4x3(DNGMatrix m) : base(m) { if (Rows != 4 || Cols != 3) { throw new ArgumentException("This is not a 4x3 Matrix"); } }
public DNGMatrix AsDiagonal() { DNGMatrix M = new DNGMatrix(Count, Count); for (uint j = 0; j < Count; j++) { M[j, j] = _data[j]; } return(M); }
public DNGMatrix AsColumn() { DNGMatrix M = new DNGMatrix(Count, 1); for (uint j = 0; j < Count; j++) { M[j, 0] = _data[j]; } return(M); }
public DNGMatrix(DNGMatrix aMatrix) { _rows = aMatrix.Rows; _cols = aMatrix.Cols; for (int row = 0; row < _rows; row++) { for (int col = 0; col < _cols; col++) { _data[row, col] = aMatrix._data[row, col]; } } }
public DNGMatrix Invert(DNGMatrix hint) { if (Rows == Cols || Rows != hint.Cols || Cols != hint.Rows) { return(Invert()); } else { // Use the specified hint matrix. return((hint * this).Invert() * hint); } }
public DNGMatrix Transpose() { DNGMatrix B = new DNGMatrix(Cols, Rows); for (uint j = 0; j < B.Rows; j++) { for (uint k = 0; k < B.Cols; k++) { B[j, k] = this[k, j]; } } return(B); }
private DNGMatrix Invert3x3() { if (Cols != 3 && Rows != 3) { throw new Exception("This only works on 3x3 matrices."); } double a00 = this[0, 0]; double a01 = this[0, 1]; double a02 = this[0, 2]; double a10 = this[1, 0]; double a11 = this[1, 1]; double a12 = this[1, 2]; double a20 = this[2, 0]; double a21 = this[2, 1]; double a22 = this[2, 2]; double[,] temp = new double[3, 3]; temp[0, 0] = a11 * a22 - a21 * a12; temp[0, 1] = a21 * a02 - a01 * a22; temp[0, 2] = a01 * a12 - a11 * a02; temp[1, 0] = a20 * a12 - a10 * a22; temp[1, 1] = a00 * a22 - a20 * a02; temp[1, 2] = a10 * a02 - a00 * a12; temp[2, 0] = a10 * a21 - a20 * a11; temp[2, 1] = a20 * a01 - a00 * a21; temp[2, 2] = a00 * a11 - a10 * a01; double det = (a00 * temp[0, 0] + a01 * temp[1, 0] + a02 * temp[2, 0]); if (Math.Abs(det) < NEAR_ZERO) { throw new Exception("The matrix determinant is too close to zero."); } DNGMatrix B = new DNGMatrix(3, 3); for (uint j = 0; j < 3; j++) { for (uint k = 0; k < 3; k++) { B[j, k] = temp[j, k] / det; } } return(B); }
public override bool Equals(object obj) { if (obj == null) { return(false); } if (!(obj is DNGMatrix)) { return(false); } DNGMatrix value = (DNGMatrix)obj; return(Equals(value)); }
public static DNGMatrix operator +(DNGMatrix a, DNGMatrix b) { if (a.Cols != b.Cols || a.Rows != b.Rows) { throw new ArgumentException("Matrices don't have the same size."); } DNGMatrix ret = new DNGMatrix(a); for (uint j = 0; j < ret.Rows; j++) { for (uint k = 0; k < ret.Cols; k++) { ret[j, k] += b[j, k]; } } return(ret); }
private DNGMatrix NormalizeForwardMatrix(DNGMatrix m) { if (m == null) { return(new DNGMatrix()); } if (m.NotEmpty()) { DNGVector cameraOne = DNGVector.Identity(m.Cols); DNGVector xyz = m * cameraOne; m = DNGxyCoord.PCStoXYZ.AsDiagonal() * (xyz.AsDiagonal().Invert()) * m; } return(m); }
public bool AlmostEqual(DNGMatrix m, double slop = 1.0e-8) { if (_rows != m._rows || _cols != m._cols) { return(false); } for (uint j = 0; j < _rows; j++) { for (uint k = 0; k < _cols; k++) { if (Math.Abs(_data[j, k] - m[j, k]) > slop) { return(false); } } } return(true); }
public bool Equals(DNGMatrix value) { if (_rows != value._rows || _cols != value._cols) { return(false); } for (int row = 0; row < _rows; row++) { for (int col = 0; col < _cols; col++) { if (_data[row, col] != value._data[row, col]) { return(false); } } } return(true); }
public DNGColorSpace(DNGMatrix3x3 toPCS) { // The matrix values are often rounded, so adjust to // get them to convert device white exactly to the PCS. DNGVector W1 = toPCS * new DNGVector3(1.0, 1.0, 1.0); DNGVector W2 = DNGxyCoord.PCStoXYZ; double s0 = W2[0] / W1[0]; double s1 = W2[1] / W1[1]; double s2 = W2[2] / W1[2]; DNGMatrix3x3 S = new DNGMatrix3x3(s0, 0, 0, 0, s1, 0, 0, 0, s2); mToPCS = S * toPCS; // Find reverse matrix. mFromPCS = mToPCS.Invert(); }
/// Return the XY value to use for SetWhiteXY for a given camera color /// space coordinate as the white point. /// \param neutral A camera color space value to use for white point. /// Components range from 0.0 to 1.0 and should be normalized such that /// the largest value is 1.0 . /// \retval White point in XY space that makes neutral map to this /// XY value as closely as possible. public DNGxyCoord NeutralToXY(DNGVector neutral) { const uint kMaxPasses = 30; if (fChannels == 1) { return(DNGxyCoord.PCStoXY); } DNGxyCoord last = DNGxyCoord.D50; for (uint pass = 0; pass < kMaxPasses; pass++) { DNGMatrix nullMat = null; DNGMatrix xyzToCamera = FindXYZtoCamera(last, ref nullMat, ref nullMat, ref nullMat); DNGMatrix inv = xyzToCamera.Invert(); DNGVector vec = inv * neutral; DNGVector3 vec3 = new DNGVector3(vec); DNGxyCoord next = DNGxyCoord.XYZtoXY(new DNGVector3(xyzToCamera.Invert() * neutral)); if (Math.Abs(next.X - last.X) + Math.Abs(next.Y - last.Y) < 0.0000001) { return(next); } // If we reach the limit without converging, we are most likely // in a two value oscillation. So take the average of the last // two estimates and give up. if (pass == kMaxPasses - 1) { next.X = (last.X + next.X) * 0.5; next.Y = (last.Y + next.Y) * 0.5; } last = next; } return(last); }
public DNGMatrix Invert() { if (Rows < 2 || Cols < 2) { throw new Exception("Can't invert a matrix smaller than 2x2"); } if (Rows == Cols) { if (Rows == 3) { return(Invert3x3()); } return(InvertNxN()); } else { // Compute the pseudo inverse. DNGMatrix B = Transpose(); return((B * this).Invert() * B); } }
public static DNGMatrix operator *(DNGMatrix a, DNGMatrix b) { if (a.Cols != b.Rows) { throw new ArgumentException("Matrix dimensions don't match."); } DNGMatrix ret = new DNGMatrix(a.Rows, b.Cols); for (uint j = 0; j < ret.Rows; j++) { for (uint k = 0; k < ret.Cols; k++) { ret[j, k] = 0.0; for (uint m = 0; m < a.Cols; m++) { double aa = a[j, m]; double bb = b[m, k]; ret[j, k] += aa * bb; } } } return(ret); }
private DNGMatrix FindXYZtoCamera(DNGxyCoord white, ref DNGMatrix forwardMatrix, ref DNGMatrix reductionMatrix, ref DNGMatrix cameraCalibration) { // Convert to temperature/offset space. DNGTemperature td = new DNGTemperature(white); // Find fraction to weight the first calibration. double g; if (td.Temperature <= fTemperature1) { g = 1.0; } else if (td.Temperature >= fTemperature2) { g = 0.0; } else { double invT = 1.0 / td.Temperature; g = (invT - (1.0 / fTemperature2)) / ((1.0 / fTemperature1) - (1.0 / fTemperature2)); } // Interpolate the color matrix. DNGMatrix colorMatrix; if (g >= 1.0) { colorMatrix = fColorMatrix1; } else if (g <= 0.0) { colorMatrix = fColorMatrix2; } else { colorMatrix = (g) * fColorMatrix1 + (1.0 - g) * fColorMatrix2; } // Interpolate forward matrix, if any. if (forwardMatrix != null) { bool has1 = fForwardMatrix1.NotEmpty(); bool has2 = fForwardMatrix2.NotEmpty(); if (has1 && has2) { if (g >= 1.0) { forwardMatrix = fForwardMatrix1; } else if (g <= 0.0) { forwardMatrix = fForwardMatrix2; } else { forwardMatrix = (g) * fForwardMatrix1 + (1.0 - g) * fForwardMatrix2; } } else if (has1) { forwardMatrix = fForwardMatrix1; } else if (has2) { forwardMatrix = fForwardMatrix2; } else { forwardMatrix.Clear(); } } // Interpolate reduction matrix, if any. if (reductionMatrix != null) { bool has1 = fReductionMatrix1.NotEmpty(); bool has2 = fReductionMatrix2.NotEmpty(); if (has1 && has2) { if (g >= 1.0) { reductionMatrix = fReductionMatrix1; } else if (g <= 0.0) { reductionMatrix = fReductionMatrix2; } else { reductionMatrix = (g) * fReductionMatrix1 + (1.0 - g) * fReductionMatrix2; } } else if (has1) { reductionMatrix = fReductionMatrix1; } else if (has2) { reductionMatrix = fReductionMatrix2; } else { reductionMatrix.Clear(); } } // Interpolate camera calibration matrix. if (cameraCalibration != null) { if (g >= 1.0) { cameraCalibration = fCameraCalibration1; } else if (g <= 0.0) { cameraCalibration = fCameraCalibration2; } else { cameraCalibration = (g) * fCameraCalibration1 + (1.0 - g) * fCameraCalibration2; } } // Return the interpolated color matrix. return(colorMatrix); }
public DNGColorSpec(uint aChannels, ImageFileDirectory ifd0, ImageFileDirectory raw) { fChannels = aChannels; if (GetTag <IFDDNGCalibrationIlluminant1>(ifd0, raw) != null) { fTemperature1 = ConvertIlluminantToTemperature(GetTag <IFDDNGCalibrationIlluminant1>(ifd0, raw).Value); } else { fTemperature1 = 0.0; } if (GetTag <IFDDNGCalibrationIlluminant2>(ifd0, raw) != null) { fTemperature2 = ConvertIlluminantToTemperature(GetTag <IFDDNGCalibrationIlluminant2>(ifd0, raw).Value); } else { fTemperature2 = 0.0; } fColorMatrix1 = GetTag <IFDDNGColorMatrix1>(ifd0, raw)?.Matrix; if (fColorMatrix1 == null) { fColorMatrix1 = DNGMatrix.Identity(fChannels); //best choice if nothing is given... } fColorMatrix2 = GetTag <IFDDNGColorMatrix2>(ifd0, raw)?.Matrix; if (fColorMatrix2 == null) { fColorMatrix2 = new DNGMatrix(); } fForwardMatrix1 = GetTag <IFDDNGForwardMatrix1>(ifd0, raw)?.Matrix; if (fForwardMatrix1 == null) { fForwardMatrix1 = new DNGMatrix(); } fForwardMatrix2 = GetTag <IFDDNGForwardMatrix2>(ifd0, raw)?.Matrix; if (fForwardMatrix2 == null) { fForwardMatrix2 = new DNGMatrix(); } fReductionMatrix1 = GetTag <IFDDNGReductionMatrix1>(ifd0, raw)?.Matrix; if (fReductionMatrix1 == null) { fReductionMatrix1 = new DNGMatrix(); } fReductionMatrix2 = GetTag <IFDDNGReductionMatrix2>(ifd0, raw)?.Matrix; if (fReductionMatrix2 == null) { fReductionMatrix2 = new DNGMatrix(); } fCameraCalibration1 = GetTag <IFDDNGCameraCalibration1>(ifd0, raw)?.Matrix; fCameraCalibration2 = GetTag <IFDDNGCameraCalibration1>(ifd0, raw)?.Matrix; if (fCameraCalibration1 == null) { fCameraCalibration1 = DNGMatrix.Identity(fChannels); } if (fCameraCalibration2 == null) { fCameraCalibration2 = DNGMatrix.Identity(fChannels); } fAnalogBalance = GetTag <IFDDNGAnalogBalance>(ifd0, raw)?.Vector.AsDiagonal(); if (fAnalogBalance == null) { fAnalogBalance = DNGMatrix.Identity(fChannels); } fForwardMatrix1 = NormalizeForwardMatrix(fForwardMatrix1); fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1; if (fColorMatrix2.IsEmpty() || fTemperature1 <= 0.0 || fTemperature2 <= 0.0 || fTemperature1 == fTemperature2) { fTemperature1 = 5000.0; fTemperature2 = 5000.0; fColorMatrix2 = fColorMatrix1; fForwardMatrix2 = fForwardMatrix1; fReductionMatrix2 = fReductionMatrix1; fCameraCalibration2 = fCameraCalibration1; } else { fForwardMatrix2 = NormalizeForwardMatrix(fForwardMatrix2); fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2; // Swap values if temperatures are out of order. if (fTemperature1 > fTemperature2) { double temp = fTemperature1; fTemperature1 = fTemperature2; fTemperature2 = temp; DNGMatrix T = fColorMatrix1; fColorMatrix1 = fColorMatrix2; fColorMatrix2 = T; T = fForwardMatrix1; fForwardMatrix1 = fForwardMatrix2; fForwardMatrix2 = T; T = fReductionMatrix1; fReductionMatrix1 = fReductionMatrix2; fReductionMatrix2 = T; T = fCameraCalibration1; fCameraCalibration1 = fCameraCalibration2; fCameraCalibration2 = T; } } IFDDNGAsShotNeutral neutral = GetTag <IFDDNGAsShotNeutral>(ifd0, raw); IFDDNGAsShotWhiteXY asShot = GetTag <IFDDNGAsShotWhiteXY>(ifd0, raw); DNGxyCoord white; if (asShot == null) { if (neutral == null) { throw new ArgumentException("The DNG spec says that one of the As Shot White balance tags must be present."); } DNGVector vec = new DNGVector((uint)neutral.Value.Length); for (uint c = 0; c < neutral.Value.Length; c++) { vec[c] = neutral.Value[c].Value; } double unify = 1.0 / vec.MaxEntry(); vec = unify * vec; white = NeutralToXY(vec); } else { double x = asShot.Value[0].Value; double y = asShot.Value[1].Value; white = new DNGxyCoord(x, y); } WhiteXY = white; }
public DNGColorSpec(double[] colorMatrix1, double[] colorMatrix2, IFDDNGCalibrationIlluminant.Illuminant illuminant1, IFDDNGCalibrationIlluminant.Illuminant illuminant2, float[] whiteBalance) { fChannels = 3; fTemperature1 = ConvertIlluminantToTemperature(illuminant1); fTemperature2 = ConvertIlluminantToTemperature(illuminant2); if (colorMatrix1 == null) { fColorMatrix1 = DNGMatrix.Identity(fChannels); //best choice if nothing is given... } else { fColorMatrix1 = new DNGMatrix3x3(colorMatrix1); } if (colorMatrix2 == null) { fColorMatrix2 = new DNGMatrix(); } else { fColorMatrix2 = new DNGMatrix3x3(colorMatrix2); } fForwardMatrix1 = new DNGMatrix(); fForwardMatrix2 = new DNGMatrix(); fReductionMatrix1 = new DNGMatrix(); fReductionMatrix2 = new DNGMatrix(); fCameraCalibration1 = DNGMatrix.Identity(fChannels); fCameraCalibration2 = DNGMatrix.Identity(fChannels); fAnalogBalance = DNGMatrix.Identity(fChannels); fForwardMatrix1 = NormalizeForwardMatrix(fForwardMatrix1); fColorMatrix1 = fAnalogBalance * fCameraCalibration1 * fColorMatrix1; if (fColorMatrix2.IsEmpty() || fTemperature1 <= 0.0 || fTemperature2 <= 0.0 || fTemperature1 == fTemperature2) { fTemperature1 = 5000.0; fTemperature2 = 5000.0; fColorMatrix2 = fColorMatrix1; fForwardMatrix2 = fForwardMatrix1; fReductionMatrix2 = fReductionMatrix1; fCameraCalibration2 = fCameraCalibration1; } else { fForwardMatrix2 = NormalizeForwardMatrix(fForwardMatrix2); fColorMatrix2 = fAnalogBalance * fCameraCalibration2 * fColorMatrix2; // Swap values if temperatures are out of order. if (fTemperature1 > fTemperature2) { double temp = fTemperature1; fTemperature1 = fTemperature2; fTemperature2 = temp; DNGMatrix T = fColorMatrix1; fColorMatrix1 = fColorMatrix2; fColorMatrix2 = T; T = fForwardMatrix1; fForwardMatrix1 = fForwardMatrix2; fForwardMatrix2 = T; T = fReductionMatrix1; fReductionMatrix1 = fReductionMatrix2; fReductionMatrix2 = T; T = fCameraCalibration1; fCameraCalibration1 = fCameraCalibration2; fCameraCalibration2 = T; } } DNGxyCoord white; DNGVector vec = new DNGVector((uint)whiteBalance.Length); for (uint c = 0; c < whiteBalance.Length; c++) { //white point is given as a multiplicatice factor //actual white point is hence 1/value vec[c] = 1.0f / whiteBalance[c]; } double unify = 1.0 / vec.MaxEntry(); vec = unify * vec; white = NeutralToXY(vec); WhiteXY = white; }
public bool AlmostIdentity(double slop = 1.0e-8) { return(AlmostEqual(DNGMatrix.Identity(_rows), slop)); }
private DNGMatrix InvertNxN() { uint i; uint j; uint k; uint n = Rows; uint augmented_cols = 2 * n; double[,] temp = new double[MAX_COLOR_PLANES, MAX_COLOR_PLANES * 2]; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { temp[i, j] = this[i, j]; temp[i, j + n] = (i == j? 1.0 : 0.0); } } for (i = 0; i < n; i++) { // Find row iMax with largest absolute entry in column i. uint iMax = i; double vMax = -1.0; for (k = i; k < n; k++) { double v = Math.Abs(this[k, i]); if (v > vMax) { vMax = v; iMax = k; } } double alpha = temp[iMax, i]; if (Math.Abs(alpha) < NEAR_ZERO) { throw new Exception("This matrix is not invertible"); } // Swap rows i and iMax, column by column. if (i != iMax) { for (j = 0; j < augmented_cols; j++) { double t = temp[iMax, j]; temp[iMax, j] = temp[i, j]; temp[i, j] = t; } } for (j = 0; j < augmented_cols; j++) { temp[i, j] /= alpha; } for (k = 0; k < n; k++) { if (i != k) { double beta = temp[k, i]; for (j = 0; j < augmented_cols; j++) { temp[k, j] -= beta * temp[i, j]; } } } } DNGMatrix B = new DNGMatrix(n, n); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { B[i, j] = temp[i, j + n]; } } return(B); }