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; }
dng_vector_3 PCStoXYZ () { return XYtoXYZ (PCStoXY ()); }
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); } }