Ejemplo n.º 1
0
        /// <summary>
        /// Uses the white reference image to retrieve the luminance factor to apply based on the position in the image
        /// </summary>
        /// <param name="_U">The U coordinate in the image (U=X/Width)</param>
        /// <param name="_V">The V coordinate in the image (V=Y/Height)</param>
        /// <returns>The luminance factor to apply to correct the spatial luminance discrepancies</returns>
        public float    GetSpatialLuminanceCorrectionFactor(float _U, float _V)
        {
            if (m_WhiteReferenceImage == null)
            {
                return(1.0f);
            }

            ImageUtility.float4 XYZ         = m_WhiteReferenceImage.BilinearSample(_U * m_WhiteReferenceImage.Width, _V * m_WhiteReferenceImage.Height);
            float SpatialWhiteRefCorrection = m_WhiteReflectanceImageMax / Math.Max(1e-6f, XYZ.y);

            return(SpatialWhiteRefCorrection);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Captures the calibrated texture
        /// </summary>
        /// <param name="_Source">The source image to capture</param>
        /// <param name="_Database">Database to perform proper calibration</param>
        /// <param name="_Parms">Parameters for the capture</param>
        public void             Capture(ImageUtility.Bitmap _Source, CameraCalibrationDatabase _Database, CaptureParms _Parms)
        {
            if (_Source == null)
            {
                throw new Exception("Invalid source bitmap to build texture from!");
            }
            if (_Database == null)
            {
                throw new Exception("Invalid calibration database found in parameters!");
            }
            if (_Parms == null)
            {
                throw new Exception("Invalid calibration parameters!");
            }
            if (m_SwatchWidth <= 0 || m_SwatchHeight <= 0)
            {
                throw new Exception("Invalid swatch size! Must be > 0!");
            }

            // Save parameters as they're associated to this texture
            m_CaptureParameters                = _Parms;
            m_WhiteReflectanceReference        = _Database.WhiteReflectanceReference;
            m_WhiteReflectanceCorrectionFactor = _Database.WhiteReflectanceCorrectionFactor;
            m_SpatialCorrectionEnabled         = _Database.WhiteReferenceImage != null;

            //////////////////////////////////////////////////////////////////////////
            // Setup the database to find the most appropriate calibration data for our image infos
            _Database.PrepareCalibrationFor(_Parms.ISOSpeed, _Parms.ShutterSpeed, _Parms.Aperture);


            //////////////////////////////////////////////////////////////////////////
            // Build target texture
            ImageUtility.float4 AvgXYZ = new ImageUtility.float4(0, 0, 0, 0);
//DEBUG
// float	MinLuminance_Raw = float.MaxValue;
// float	MaxLuminance_Raw = -float.MaxValue;

            const int EXTREME_VALUES_COUNT = 100;

            ImageUtility.float3[] ArrayMin = new ImageUtility.float3[EXTREME_VALUES_COUNT];
            ImageUtility.float3[] ArrayMax = new ImageUtility.float3[EXTREME_VALUES_COUNT];
            for (int i = 0; i < EXTREME_VALUES_COUNT; i++)
            {
                ArrayMin[i] = new ImageUtility.float3(0, 1, 0);
                ArrayMax[i] = new ImageUtility.float3(0, 0, 0);
            }

            if (_Parms.CropSource)
            {
                float fImageWidth  = 2.0f * _Parms.CropRectangleHalfSize.x * _Source.Height;
                float fImageHeight = 2.0f * _Parms.CropRectangleHalfSize.y * _Source.Height;
                int   W            = (int)Math.Floor(fImageWidth);
                int   H            = (int)Math.Floor(fImageHeight);

                ImageUtility.float2 AxisX = new ImageUtility.float2((float)Math.Cos(_Parms.CropRectangleRotation), -(float)Math.Sin(_Parms.CropRectangleRotation));
                ImageUtility.float2 AxisY = new ImageUtility.float2((float)Math.Sin(_Parms.CropRectangleRotation), (float)Math.Cos(_Parms.CropRectangleRotation));

                ImageUtility.float2 TopLeftCorner = new ImageUtility.float2(0.5f * (_Source.Width - _Source.Height) + _Parms.CropRectangleCenter.x * _Source.Height, _Source.Height * _Parms.CropRectangleCenter.y)
                                                    + _Source.Height * (-_Parms.CropRectangleHalfSize.x * AxisX - _Parms.CropRectangleHalfSize.y * AxisY);

                m_Texture = new ImageUtility.Bitmap(W, H, new ImageUtility.ColorProfile(ImageUtility.ColorProfile.STANDARD_PROFILE.sRGB));
                ImageUtility.float4 XYZ;
                ImageUtility.float3 ShortXYZ;
                ImageUtility.float3 xyY;

                ImageUtility.float2 CurrentScanlinePixel = TopLeftCorner + 0.5f * (fImageWidth - W) * AxisX + 0.5f * (fImageHeight - H) * AxisY;
                if (Math.Abs(_Parms.CropRectangleRotation) < 1e-6f)
                {                       // Use integer pixels to avoid attenuated values due to bilinear filtering
                    CurrentScanlinePixel.x = (float)Math.Floor(CurrentScanlinePixel.x);
                    CurrentScanlinePixel.y = (float)Math.Floor(CurrentScanlinePixel.y);
                }
                for (int Y = 0; Y < H; Y++)
                {
                    ImageUtility.float2 CurrentPixel = CurrentScanlinePixel;
                    for (int X = 0; X < W; X++)
                    {
                        float U = CurrentPixel.x / _Source.Width;
                        float V = CurrentPixel.y / _Source.Height;

                        XYZ = _Source.BilinearSample(CurrentPixel.x, CurrentPixel.y);

//DEBUG
// float	L = XYZ.y * _Database.GetSpatialLuminanceCorrectionFactor( U, V );
// if ( L < MinLuminance_Raw )
//  MinLuminance_Raw = L;
// if ( L > MaxLuminance_Raw )
//  MaxLuminance_Raw = L;
//DEBUG

                        xyY      = ImageUtility.ColorProfile.XYZ2xyY((ImageUtility.float3)XYZ);
                        xyY      = _Database.CalibrateWithSpatialCorrection(U, V, xyY);                         // Apply luminance calibration
                        ShortXYZ = ImageUtility.ColorProfile.xyY2XYZ(xyY);
                        XYZ      = new ImageUtility.float4(ShortXYZ, XYZ.w);
                        m_Texture.ContentXYZ[X, Y] = XYZ;

                        // Update min/max/avg values
                        InsertMinMax(ShortXYZ, ArrayMin, ArrayMax, EXTREME_VALUES_COUNT);
                        AvgXYZ += XYZ;

                        CurrentPixel += AxisX;
                    }
                    CurrentScanlinePixel += AxisY;
                }
            }
            else
            {                   // Simple texture copy, with luminance calibration
                m_Texture = new ImageUtility.Bitmap(_Source.Width, _Source.Height, new ImageUtility.ColorProfile(ImageUtility.ColorProfile.STANDARD_PROFILE.sRGB));
                ImageUtility.float4 XYZ;
                ImageUtility.float3 ShortXYZ;
                ImageUtility.float3 xyY;

                int W = m_Texture.Width;
                int H = m_Texture.Height;

                int X0 = 0;
                int X1 = W;
                int Y0 = 0;
                int Y1 = H;

//DEBUG
// X0 = 1088; Y0 = 764;
// X1 = X0 + 1100; Y1 = Y0 + 632;

                for (int Y = Y0; Y < Y1; Y++)
                {
                    float V = (float)Y / H;
                    for (int X = X0; X < X1; X++)
                    {
                        float U = (float)X / W;

                        XYZ = _Source.ContentXYZ[X, Y];

//DEBUG
// float	L = XYZ.y * _Database.GetSpatialLuminanceCorrectionFactor( U, V );
// if ( L < MinLuminance_Raw )
//  MinLuminance_Raw = L;
// if ( L > MaxLuminance_Raw )
//  MaxLuminance_Raw = L;
//DEBUG

                        xyY      = ImageUtility.ColorProfile.XYZ2xyY((ImageUtility.float3)XYZ);
                        xyY      = _Database.CalibrateWithSpatialCorrection(U, V, xyY);                         // Apply luminance calibration
                        ShortXYZ = ImageUtility.ColorProfile.xyY2XYZ(xyY);
                        XYZ      = new ImageUtility.float4(ShortXYZ, XYZ.w);
                        m_Texture.ContentXYZ[X, Y] = XYZ;

                        // Update min/max/avg values
                        InsertMinMax(ShortXYZ, ArrayMin, ArrayMax, EXTREME_VALUES_COUNT);
                        AvgXYZ += XYZ;
                    }
                }
            }

            // Normalize average swatch color
            float Normalizer = 1.0f / (m_Texture.Width * m_Texture.Height);

            ImageUtility.float3 avgxyY = ImageUtility.ColorProfile.XYZ2xyY(Normalizer * ((ImageUtility.float3)AvgXYZ));
            m_SwatchAvg.xyY = avgxyY;

            // Compute min & max using statistical norm
            ImageUtility.float3 BestXYZ_Min;
            ImageUtility.float3 BestXYZ_Max;

            if (_Parms.UseModeInsteadOfMean)
            {                   // Use mode
                BestXYZ_Min = ComputeMode(ArrayMin);
                BestXYZ_Max = ComputeMode(ArrayMax);
            }
            else
            {                   // Use mean
                BestXYZ_Min = ComputeMean(ArrayMin);
                BestXYZ_Max = ComputeMean(ArrayMax);
            }
            m_SwatchMin.xyY = ImageUtility.ColorProfile.XYZ2xyY(BestXYZ_Min);
            m_SwatchMax.xyY = ImageUtility.ColorProfile.XYZ2xyY(BestXYZ_Max);

            m_SwatchMin.Texture = BuildSwatch(m_SwatchWidth, m_SwatchHeight, m_SwatchMin.xyY);
            m_SwatchMax.Texture = BuildSwatch(m_SwatchWidth, m_SwatchHeight, m_SwatchMax.xyY);
            m_SwatchAvg.Texture = BuildSwatch(m_SwatchWidth, m_SwatchHeight, m_SwatchAvg.xyY);

            // Rebuild custom swatches
            foreach (CustomSwatch CS in m_CustomSwatches)
            {
                CS.Texture = BuildSwatch(m_SwatchWidth, m_SwatchHeight, CS.xyY);
            }

            //////////////////////////////////////////////////////////////////////////
            // Feed some purely informational shot infos to the main texture, probably won't be saved anyway...
            m_Texture.HasValidShotInfo = true;
            m_Texture.ISOSpeed         = _Parms.ISOSpeed;
            m_Texture.ShutterSpeed     = _Parms.ShutterSpeed;
            m_Texture.Aperture         = _Parms.Aperture;
        }