real64 dng_1d_concatenate::Evaluate (real64 x) const { real64 y = Pin_real64 (0.0, fFunction1.Evaluate (x), 1.0); return fFunction2.Evaluate (y); }
dng_vector_3 XYtoXYZ (const dng_xy_coord &coord) { dng_xy_coord temp = coord; // Restrict xy coord to someplace inside the range of real xy coordinates. // This prevents math from doing strange things when users specify // extreme temperature/tint coordinates. temp.x = Pin_real64 (0.000001, temp.x, 0.999999); temp.y = Pin_real64 (0.000001, temp.y, 0.999999); if (temp.x + temp.y > 0.999999) { real64 scale = 0.999999 / (temp.x + temp.y); temp.x *= scale; temp.y *= scale; } return dng_vector_3 (temp.x / temp.y, 1.0, (1.0 - temp.x - temp.y) / temp.y); }
dng_matrix_3by3 MapWhiteMatrix (const dng_xy_coord &white1, const dng_xy_coord &white2) { // Use the linearized Bradford adaptation matrix. dng_matrix_3by3 Mb ( 0.8951, 0.2664, -0.1614, -0.7502, 1.7135, 0.0367, 0.0389, -0.0685, 1.0296); dng_vector_3 w1 = Mb * XYtoXYZ (white1); dng_vector_3 w2 = Mb * XYtoXYZ (white2); // Negative white coordinates are kind of meaningless. w1 [0] = Max_real64 (w1 [0], 0.0); w1 [1] = Max_real64 (w1 [1], 0.0); w1 [2] = Max_real64 (w1 [2], 0.0); w2 [0] = Max_real64 (w2 [0], 0.0); w2 [1] = Max_real64 (w2 [1], 0.0); w2 [2] = Max_real64 (w2 [2], 0.0); // Limit scaling to something reasonable. dng_matrix_3by3 A; A [0] [0] = Pin_real64 (0.1, w1 [0] > 0.0 ? w2 [0] / w1 [0] : 10.0, 10.0); A [1] [1] = Pin_real64 (0.1, w1 [1] > 0.0 ? w2 [1] / w1 [1] : 10.0, 10.0); A [2] [2] = Pin_real64 (0.1, w1 [2] > 0.0 ? w2 [2] / w1 [2] : 10.0, 10.0); dng_matrix_3by3 B = Invert (Mb) * A * Mb; return B; }
real64 dng_1d_function::EvaluateInverse (real64 y) const { const uint32 kMaxIterations = 30; const real64 kNearZero = 1.0e-10; real64 x0 = 0.0; real64 y0 = Evaluate (x0); real64 x1 = 1.0; real64 y1 = Evaluate (x1); for (uint32 iteration = 0; iteration < kMaxIterations; iteration++) { if (Abs_real64 (y1 - y0) < kNearZero) { break; } real64 x2 = Pin_real64 (0.0, x1 + (y - y1) * (x1 - x0) / (y1 - y0), 1.0); real64 y2 = Evaluate (x2); x0 = x1; y0 = y1; x1 = x2; y1 = y2; } return x1; }
void dng_color_spec::SetWhiteXY (const dng_xy_coord &white) { fWhiteXY = white; // Deal with monochrome cameras. if (fChannels == 1) { fCameraWhite.SetIdentity (1); fCameraToPCS = PCStoXYZ ().AsColumn (); return; } // Interpolate an matric values for this white point. dng_matrix colorMatrix; dng_matrix forwardMatrix; dng_matrix reductionMatrix; dng_matrix cameraCalibration; colorMatrix = FindXYZtoCamera (fWhiteXY, &forwardMatrix, &reductionMatrix, &cameraCalibration); // Find the camera white values. fCameraWhite = colorMatrix * XYtoXYZ (fWhiteXY); real64 whiteScale = 1.0 / MaxEntry (fCameraWhite); for (uint32 j = 0; j < fChannels; j++) { // We don't support non-positive values for camera neutral values. fCameraWhite [j] = Pin_real64 (0.001, whiteScale * fCameraWhite [j], 1.0); } // Find PCS to Camera transform. Scale matrix so PCS white can just be // reached when the first camera channel saturates fPCStoCamera = colorMatrix * MapWhiteMatrix (PCStoXY (), fWhiteXY); real64 scale = MaxEntry (fPCStoCamera * PCStoXYZ ()); fPCStoCamera = (1.0 / scale) * fPCStoCamera; // If we have a forward matrix, then just use that. if (forwardMatrix.NotEmpty ()) { dng_matrix individualToReference = Invert (fAnalogBalance * cameraCalibration); dng_vector refCameraWhite = individualToReference * fCameraWhite; fCameraToPCS = forwardMatrix * Invert (refCameraWhite.AsDiagonal ()) * individualToReference; } // Else we need to use the adapt in XYZ method. else { // Invert this PCS to camera matrix. Note that if there are more than three // camera channels, this inversion is non-unique. fCameraToPCS = Invert (fPCStoCamera, reductionMatrix); } }