protected void TestConvertLDR2HDR( System.IO.FileInfo[] _LDRImageFileNames, bool _responseCurveOnly, bool _RAW ) { try { // Load the LDR images List< ImageFile > LDRImages = new List< ImageFile >(); foreach ( System.IO.FileInfo LDRImageFileName in _LDRImageFileNames ) LDRImages.Add( new ImageFile( LDRImageFileName ) ); // Retrieve the shutter speeds List< float > shutterSpeeds = new List< float >(); foreach ( ImageFile LDRImage in LDRImages ) { shutterSpeeds.Add( LDRImage.Metadata.ExposureTime ); } // Retrieve filter type Bitmap.FILTER_TYPE filterType = Bitmap.FILTER_TYPE.NONE; if ( radioButtonFilterNone.Checked ) { filterType = Bitmap.FILTER_TYPE.NONE; } else if ( radioButtonFilterGaussian.Checked ) { filterType = Bitmap.FILTER_TYPE.SMOOTHING_GAUSSIAN; } else if ( radioButtonFilterGaussian2Pass.Checked ) { filterType = Bitmap.FILTER_TYPE.SMOOTHING_GAUSSIAN_2_PASSES; } else if ( radioButtonFilterTent.Checked ) { filterType = Bitmap.FILTER_TYPE.SMOOTHING_TENT; } else if ( radioButtonFilterCurveFitting.Checked ) { filterType = Bitmap.FILTER_TYPE.GAUSSIAN_PLUS_CURVE_FITTING; } // Check EXR save is working! // ImageFile pipo = new ImageFile(); // pipo.ConvertFrom( LDRImages[0], ImageFile.PIXEL_FORMAT.RGB32F ); // pipo.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromJPG\Result.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_DEFAULT ); // Check bitmap->tone mapped image file is working // { // Bitmap tempBitmap = new Bitmap(); // List< float > responseCurve = new List< float >( 256 ); // for ( int i=0; i < 256; i++ ) // responseCurve.Add( (float) (Math.Log( (1+i) / 256.0 ) / Math.Log(2)) ); // tempBitmap.LDR2HDR( new ImageFile[] { LDRImages[4] }, new float[] { 1.0f }, responseCurve, 1.0f ); // // ImageFile tempHDR = new ImageFile(); // tempBitmap.ToImageFile( tempHDR, new ColorProfile( ColorProfile.STANDARD_PROFILE.LINEAR ) ); // // ImageFile tempToneMappedHDR = new ImageFile(); // tempToneMappedHDR.ToneMapFrom( tempHDR,( float3 _HDRColor, ref float3 _LDRColor ) => { // // Just do gamma un-correction, don't care about actual HDR range... // _LDRColor.x = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.x ), 1.0f / 2.2f ); // Here we need to clamp negative values that we sometimes get in EXR format // _LDRColor.y = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.y ), 1.0f / 2.2f ); // (must be coming from the log encoding I suppose) // _LDRColor.z = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.z ), 1.0f / 2.2f ); // } ); // // panel1.Bitmap = tempToneMappedHDR.AsBitmap; // return; // } ////////////////////////////////////////////////////////////////////////////////////////////// // Build the HDR device-independent bitmap // uint bitsPerPixel = _RAW ? 12U : 8U; uint bitsPerPixel = _RAW ? 8U : 8U; float quality = _RAW ? 3.0f : 3.0f; Bitmap.HDRParms parms = new Bitmap.HDRParms() { _inputBitsPerComponent = bitsPerPixel, _luminanceFactor = 1.0f, _curveSmoothnessConstraint = 1.0f, _quality = quality, _responseCurveFilterType = filterType }; ImageUtility.Bitmap HDRImage = new ImageUtility.Bitmap(); // HDRImage.LDR2HDR( LDRImages.ToArray(), shutterSpeeds.ToArray(), parms ); // Compute response curve List< float > responseCurve = new List< float >(); Bitmap.ComputeCameraResponseCurve( LDRImages.ToArray(), shutterSpeeds.ToArray(), parms._inputBitsPerComponent, parms._curveSmoothnessConstraint, parms._quality, responseCurve ); // Filter List< float > responseCurve_filtered = new List< float >(); // Bitmap.FilterCameraResponseCurve( responseCurve, responseCurve_filtered, Bitmap.FILTER_TYPE.CURVE_FITTING ); Bitmap.FilterCameraResponseCurve( responseCurve, responseCurve_filtered, filterType ); // using ( System.IO.FileStream S = new System.IO.FileInfo( "../../responseCurve3.float" ).Create() ) // using ( System.IO.BinaryWriter W = new System.IO.BinaryWriter( S ) ) { // for ( int i=0; i < 256; i++ ) // W.Write( responseCurve[i] ); // } // Write info string info = "Exposures:\r\n"; foreach ( float shutterSpeed in shutterSpeeds ) info += " " + shutterSpeed + "s + "; info += "\r\nLog2 exposures (EV):\r\n"; foreach ( float shutterSpeed in shutterSpeeds ) info += " " + (float) (Math.Log( shutterSpeed ) / Math.Log(2)) + "EV + "; info += "\r\n\r\n"; if ( _responseCurveOnly ) { ////////////////////////////////////////////////////////////////////////////////////////////// // Render the response curve as a graph ImageFile tempCurveBitmap = new ImageFile( 1024, 768, ImageFile.PIXEL_FORMAT.RGB8, new ColorProfile( ColorProfile.STANDARD_PROFILE.sRGB ) ); int responseCurveSizeMax = responseCurve.Count-1; float2 rangeX = new float2( 0, responseCurveSizeMax+1 ); float2 rangeY = new float2( 0, 500 ); tempCurveBitmap.Clear( new float4( 1, 1, 1, 1 ) ); // tempCurveBitmap.PlotGraphAutoRangeY( red, rangeX, ref rangeY, ( float x ) => { tempCurveBitmap.PlotGraph( red, rangeX, rangeY, ( float x ) => { int i0 = (int) Math.Min( responseCurveSizeMax, Math.Floor( x ) ); int i1 = (int) Math.Min( responseCurveSizeMax, i0+1 ); float g0 = responseCurve[i0]; float g1 = responseCurve[i1]; float t = x - i0; // return g0 + (g1-g0) * t; return (float) Math.Pow( 2.0f, g0 + (g1-g0) * t ); } ); tempCurveBitmap.PlotGraph( blue, rangeX, rangeY, ( float x ) => { int i0 = (int) Math.Min( responseCurveSizeMax, Math.Floor( x ) ); int i1 = (int) Math.Min( responseCurveSizeMax, i0+1 ); float g0 = responseCurve_filtered[i0]; float g1 = responseCurve_filtered[i1]; float t = x - i0; // return g0 + (g1-g0) * t; return (float) Math.Pow( 2.0f, g0 + (g1-g0) * t ); } ); // tempCurveBitmap.PlotAxes( black, rangeX, rangeY, 8, 2 ); info += "• Linear range Y = [" + rangeY.x + ", " + rangeY.y + "]\r\n"; rangeY = new float2( -4, 4 ); tempCurveBitmap.PlotLogGraphAutoRangeY( black, rangeX, ref rangeY, ( float x ) => { // tempCurveBitmap.PlotLogGraph( black, rangeX, rangeY, ( float x ) => { int i0 = (int) Math.Min( responseCurveSizeMax, Math.Floor( x ) ); int i1 = (int) Math.Min( responseCurveSizeMax, i0+1 ); float g0 = responseCurve[i0]; float g1 = responseCurve[i1]; float t = x - i0; // return g0 + (g1-g0) * t; return (float) Math.Pow( 2.0f, g0 + (g1-g0) * t ); }, -1.0f, 2.0f ); tempCurveBitmap.PlotLogGraph( blue, rangeX, rangeY, ( float x ) => { // tempCurveBitmap.PlotLogGraph( black, rangeX, rangeY, ( float x ) => { int i0 = (int) Math.Min( responseCurveSizeMax, Math.Floor( x ) ); int i1 = (int) Math.Min( responseCurveSizeMax, i0+1 ); float g0 = responseCurve_filtered[i0]; float g1 = responseCurve_filtered[i1]; float t = x - i0; // return g0 + (g1-g0) * t; return (float) Math.Pow( 2.0f, g0 + (g1-g0) * t ); }, -1.0f, 2.0f ); tempCurveBitmap.PlotLogAxes( black, rangeX, rangeY, -16, 2 ); info += "• Log2 range Y = [" + rangeY.x + ", " + rangeY.y + "]\r\n"; panelOutputHDR.Bitmap = tempCurveBitmap.AsBitmap; } else { ////////////////////////////////////////////////////////////////////////////////////////////// // Recompose the HDR image HDRImage.LDR2HDR( LDRImages.ToArray(), shutterSpeeds.ToArray(), responseCurve_filtered, 1.0f ); // Display as a tone-mapped bitmap ImageFile tempHDR = new ImageFile(); HDRImage.ToImageFile( tempHDR, new ColorProfile( ColorProfile.STANDARD_PROFILE.LINEAR ) ); if ( _RAW ) { tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromRAW\Result.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_DEFAULT ); tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromRAW\Result_B44LC.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_B44 | ImageFile.SAVE_FLAGS.SF_EXR_LC ); tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromRAW\Result_noLZW.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_NONE ); } else { tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromJPG\Result.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_DEFAULT ); tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromJPG\Result_B44LC.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_B44 | ImageFile.SAVE_FLAGS.SF_EXR_LC ); tempHDR.Save( new System.IO.FileInfo( @"..\..\Images\Out\LDR2HDR\FromJPG\Result_noLZW.exr" ), ImageFile.FILE_FORMAT.EXR, ImageFile.SAVE_FLAGS.SF_EXR_NONE ); } ImageFile tempToneMappedHDR = new ImageFile(); tempToneMappedHDR.ToneMapFrom( tempHDR,( float3 _HDRColor, ref float3 _LDRColor ) => { // Just do gamma un-correction, don't care about actual HDR range... _LDRColor.x = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.x ), 1.0f / 2.2f ); // Here we need to clamp negative values that we sometimes get in EXR format _LDRColor.y = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.y ), 1.0f / 2.2f ); // (must be coming from the log encoding I suppose) _LDRColor.z = (float) Math.Pow( Math.Max( 0.0f, _HDRColor.z ), 1.0f / 2.2f ); } ); panelOutputHDR.Bitmap = tempToneMappedHDR.AsBitmap; } textBoxHDR.Text = info; } catch ( Exception _e ) { MessageBox.Show( "Error: " + _e.Message ); // Show debug image // panelLoad.Bitmap = Bitmap.DEBUG.AsBitmap; } }