Film negative processing: first usable version. Only supports bayer raw files, thumbnails don't work

Added performance improvements suggested by heckflosse. Lowered median sampling step from 7 to 5 since calculation is now much faster.

Added support for Fuji X-Trans raw files.

Applied SSE2 patch provided by @heckflosse, improves performance in main processing loop.

Moved film negative processing stuff in its own compilation unit.

Code cleanup: removed redundant omp directives.

Added check for dead pixels, going above threshold after inversion. ST_BAYER only for now.

Reverted leftover hack in cropwindow.cc
This commit is contained in:
rom9 2019-06-04 21:31:03 +02:00
parent 3b19b9f55b
commit 9df8008949
32 changed files with 1033 additions and 2 deletions

1
.gitignore vendored
View File

@ -5,6 +5,7 @@
.project
.settings
.directory
.vscode
CMakeCache.txt
CMakeFiles

View File

@ -1314,6 +1314,8 @@ ZOOMPANEL_ZOOMOUT;Allunya\nDrecera: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1851,6 +1853,13 @@ ZOOMPANEL_ZOOMOUT;Allunya\nDrecera: <b>-</b>
!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -1361,6 +1361,8 @@ ZOOMPANEL_ZOOMOUT;缩放拉远\n快捷键: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1798,6 +1800,13 @@ ZOOMPANEL_ZOOMOUT;缩放拉远\n快捷键: <b>-</b>
!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -2360,3 +2360,16 @@ ZOOMPANEL_ZOOMFITSCREEN;An Bildschirm anpassen.\nTaste: <b>Alt</b> + <b>f</b>
ZOOMPANEL_ZOOMIN;Hineinzoomen\nTaste: <b>+</b>
ZOOMPANEL_ZOOMOUT;Herauszoomen\nTaste: <b>-</b>
!!!!!!!!!!!!!!!!!!!!!!!!!
! Untranslated keys follow; remove the ! prefix after an entry is translated.
!!!!!!!!!!!!!!!!!!!!!!!!!
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots

View File

@ -838,6 +838,8 @@ TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behaviour of "wh
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1665,6 +1667,13 @@ TP_WBALANCE_EQBLUERED_TOOLTIP;Allows to deviate from the normal behaviour of "wh
!TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -748,6 +748,8 @@
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1636,6 +1638,13 @@
!TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -1539,6 +1539,8 @@ ZOOMPANEL_ZOOMOUT;Rimpicciolisci.\nScorciatoia: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1903,6 +1905,13 @@ ZOOMPANEL_ZOOMOUT;Rimpicciolisci.\nScorciatoia: <b>-</b>
!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -1248,6 +1248,8 @@ ZOOMPANEL_ZOOMOUT;Kicsinyítés <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1816,6 +1818,13 @@ ZOOMPANEL_ZOOMOUT;Kicsinyítés <b>-</b>
!TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -2036,6 +2036,8 @@ ZOOMPANEL_ZOOMOUT;Zoom uit\nSneltoets: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -2230,6 +2232,13 @@ ZOOMPANEL_ZOOMOUT;Zoom uit\nSneltoets: <b>-</b>
!TP_EXPOSURE_CLAMPOOG;Clip out-of-gamut colors
!TP_EXPOSURE_HISTMATCHING;Auto-Matched Tone Curve
!TP_EXPOSURE_HISTMATCHING_TOOLTIP;Automatically adjust sliders and curves (except exposure compensation) to match the look of the embedded JPEG thumbnail.
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_ICM_WORKING_TRC;Tone response curve:
!TP_ICM_WORKING_TRC_CUSTOM;Custom
!TP_ICM_WORKING_TRC_GAMMA;Gamma

View File

@ -1621,6 +1621,8 @@ ZOOMPANEL_ZOOMOUT;Oddal\nSkrót: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1929,6 +1931,13 @@ ZOOMPANEL_ZOOMOUT;Oddal\nSkrót: <b>-</b>
!TP_EXPOSURE_HISTMATCHING_TOOLTIP;Automatically adjust sliders and curves (except exposure compensation) to match the look of the embedded JPEG thumbnail.
!TP_EXPOSURE_TCMODE_LUMINANCE;Luminance
!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_ICM_APPLYBASELINEEXPOSUREOFFSET;Baseline exposure
!TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP;Employ the embedded DCP baseline exposure offset. The setting is only available if the selected DCP has one.

View File

@ -2258,6 +2258,8 @@ ZOOMPANEL_ZOOMOUT;Menos Zoom\nAtalho: <b>-</b>
!FILEBROWSER_EMPTYTRASHHINT;Permanently delete all files in trash.
!HISTORY_MSG_COLORTONING_LABREGION_OFFSET;CT - region offset
!HISTORY_MSG_COLORTONING_LABREGION_POWER;CT - region power
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!MAIN_FRAME_PLACES_DEL;Remove
!PREFERENCES_APPEARANCE_PSEUDOHIDPI;Pseudo-HiDPI mode
!PREFERENCES_CACHECLEAR_SAFETY;Only files in the cache are cleared. Processing profiles stored alongside the source images are not touched.
@ -2271,6 +2273,13 @@ ZOOMPANEL_ZOOMOUT;Menos Zoom\nAtalho: <b>-</b>
!TP_COLORTONING_LABREGION_OFFSET;Offset
!TP_COLORTONING_LABREGION_POWER;Power
!TP_CROP_PPI;PPI
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_LENSPROFILE_CORRECTION_AUTOMATCH;Automatically selected
!TP_LENSPROFILE_CORRECTION_MANUAL;Manually selected
!TP_LENSPROFILE_LENS_WARNING;Warning: the crop factor used for lens profiling is larger than the crop factor of the camera, the results might be wrong.

View File

@ -1706,6 +1706,8 @@ ZOOMPANEL_ZOOMOUT;Отдалить\nГорячая клавиша: <b>-</b>
!HISTORY_MSG_COLORTONING_LABREGION_SLOPE;CT - region slope
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
!HISTORY_MSG_ICM_OUTPUT_TYPE;Output - Type
@ -1974,6 +1976,13 @@ ZOOMPANEL_ZOOMOUT;Отдалить\nГорячая клавиша: <b>-</b>
!TP_DISTORTION_AUTO_TIP;Automatically corrects lens distortion in raw files by matching it against the embedded JPEG image if one exists and has had its lens disortion auto-corrected by the camera.
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FLATFIELD_CLIPCONTROL;Clip control
!TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, clip control can lead to color cast.

View File

@ -1514,6 +1514,8 @@ ZOOMPANEL_ZOOMOUT;Умањује приказ слике <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1902,6 +1904,13 @@ ZOOMPANEL_ZOOMOUT;Умањује приказ слике <b>-</b>
!TP_EXPOSURE_TCMODE_PERCEPTUAL;Perceptual
!TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
!TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FILMSIMULATION_LABEL;Film Simulation
!TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
!TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -1863,6 +1863,8 @@ ZOOMPANEL_ZOOMOUT;Förminska.\nKortkommando: <b>-</b>
!HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
!HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
!HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
!HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
!HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
!HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
!HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
!HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -2117,6 +2119,13 @@ ZOOMPANEL_ZOOMOUT;Förminska.\nKortkommando: <b>-</b>
!TP_EXPOSURE_CLAMPOOG;Clip out-of-gamut colors
!TP_EXPOSURE_HISTMATCHING;Auto-Matched Tone Curve
!TP_EXPOSURE_HISTMATCHING_TOOLTIP;Automatically adjust sliders and curves (except exposure compensation) to match the look of the embedded JPEG thumbnail.
!TP_FILMNEGATIVE_BLUE;Blue exponent
!TP_FILMNEGATIVE_GREEN;Green exponent
!TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
!TP_FILMNEGATIVE_LABEL;Film Negative
!TP_FILMNEGATIVE_PICK;Pick white and black spots
!TP_FILMNEGATIVE_RED;Red exponent
!TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
!TP_FLATFIELD_CLIPCONTROL;Clip control
!TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, clip control can lead to color cast.
!TP_ICM_APPLYBASELINEEXPOSUREOFFSET_TOOLTIP;Employ the embedded DCP baseline exposure offset. The setting is only available if the selected DCP has one.

View File

@ -747,6 +747,8 @@ HISTORY_MSG_DEHAZE_SHOW_DEPTH_MAP;Dehaze - Show depth map
HISTORY_MSG_DEHAZE_STRENGTH;Dehaze - Strength
HISTORY_MSG_DUALDEMOSAIC_AUTO_CONTRAST;Dual demosaic - Auto threshold
HISTORY_MSG_DUALDEMOSAIC_CONTRAST;Dual demosaic - Contrast threshold
HISTORY_MSG_FILMNEGATIVE_ENABLED;Film Negative
HISTORY_MSG_FILMNEGATIVE_EXPONENTS;Film negative exponents changed
HISTORY_MSG_HISTMATCHING;Auto-matched tone curve
HISTORY_MSG_ICM_OUTPUT_PRIMARIES;Output - Primaries
HISTORY_MSG_ICM_OUTPUT_TEMP;Output - ICC-v4 illuminant D
@ -1635,6 +1637,13 @@ TP_EXPOSURE_TCMODE_STANDARD;Standard
TP_EXPOSURE_TCMODE_WEIGHTEDSTD;Weighted Standard
TP_EXPOS_BLACKPOINT_LABEL;Raw Black Points
TP_EXPOS_WHITEPOINT_LABEL;Raw White Points
TP_FILMNEGATIVE_BLUE;Blue exponent
TP_FILMNEGATIVE_GREEN;Green exponent
TP_FILMNEGATIVE_GUESS_TOOLTIP;Calculate exponents by picking 2 neutral reference spots in the image; one white (light gray) and one black (dark gray).\nThe order does not matter. The exponents will be updated after the second spot is picked.
TP_FILMNEGATIVE_LABEL;Film Negative
TP_FILMNEGATIVE_PICK;Pick white and black spots
TP_FILMNEGATIVE_RED;Red exponent
TP_FILMNEGATIVE_REF_SPOTS;Film negative reference spots
TP_FILMSIMULATION_LABEL;Film Simulation
TP_FILMSIMULATION_SLOWPARSEDIR;RawTherapee is configured to look for Hald CLUT images, which are used for the Film Simulation tool, in a folder which is taking too long to load.\nGo to Preferences > Image Processing > Film Simulation\nto see which folder is being used. You should either point RawTherapee to a folder which contains only Hald CLUT images and nothing more, or to an empty folder if you don't want to use the Film Simulation tool.\n\nRead the Film Simulation article in RawPedia for more information.\n\nDo you want to cancel the scan now?
TP_FILMSIMULATION_STRENGTH;Strength

View File

@ -132,6 +132,7 @@ set(RTENGINESOURCEFILES
ipdehaze.cc
iplabregions.cc
lj92.c
filmnegativeproc.cc
)
if(LENSFUN_HAS_LOAD_DIRECTORY)

View File

@ -0,0 +1,321 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <cmath>
#include <iostream>
#include "rtengine.h"
#include "rawimagesource.h"
#include "mytime.h"
#include "procparams.h"
#ifdef _OPENMP
#include <omp.h>
#endif
#include "opthelper.h"
#include "rt_algo.h"
namespace rtengine
{
extern const Settings* settings;
bool RawImageSource::channelsAvg(Coord spotPos, int spotSize, float avgs[3], const FilmNegativeParams &params)
{
avgs[0] = avgs[1] = avgs[2] = 0.f; // Channel averages
if(ri->getSensorType() != ST_BAYER && ri->getSensorType() != ST_FUJI_XTRANS)
return false;
if (settings->verbose)
printf("Spot coord: x=%d y=%d\n", spotPos.x, spotPos.y);
int x1 = spotPos.x - spotSize / 2;
int x2 = spotPos.x + spotSize / 2;
int y1 = spotPos.y - spotSize / 2;
int y2 = spotPos.y + spotSize / 2;
if(x1<0 || x2>W || y1<0 || y2>H)
return false; // Spot goes outside bounds, bail out.
int pxCount[3] = {0}; // Per-channel sample counts
for(int c=spotPos.x-spotSize; c<spotPos.x+spotSize; c++) {
for(int r=spotPos.y-spotSize; r<spotPos.y+spotSize; r++) {
int ch = (ri->getSensorType() == ST_BAYER) ? FC(r,c) : ri->XTRANSFC(r,c);
pxCount[ch]++;
// If film negative is currently enabled, undo the effect by elevating to 1/exp,
// in order to sample the original, linear value
if(params.enabled)
avgs[ch] += powf(rawData[r][c], -1 / (ch==0 ? params.redExp : ch==1 ? params.greenExp : params.blueExp));
else
avgs[ch] += rawData[r][c];
}
}
for(int ch=0; ch<3; ch++)
avgs[ch] = avgs[ch] / (pxCount[ch]);
return true;
}
// Calculate logarithms in arbitrary base
float logBase(float base, float num) {
return log(num) / log(base);
}
bool RawImageSource::getFilmNegativeExponents (Coord2D spotA, Coord2D spotB, int tran, const FilmNegativeParams &currentParams, float newExps[3])
{
float clearVals[3], denseVals[3];
newExps[0] = currentParams.redExp;
newExps[1] = currentParams.greenExp;
newExps[2] = currentParams.blueExp;
int spotSize = 32; // TODO : make this confugurable ?
Coord spot;
// Sample first spot
transformPosition (spotA.x, spotA.y, tran, spot.x, spot.y);
if(!channelsAvg(spot, spotSize, clearVals, currentParams))
return false;
// Sample second spot
transformPosition (spotB.x, spotB.y, tran, spot.x, spot.y);
if(!channelsAvg(spot, spotSize, denseVals, currentParams))
return false;
// Detect which one is the dense spot, based on green channel
if(clearVals[1] < denseVals[1])
std::swap(clearVals, denseVals);
if (settings->verbose) {
printf("Clear film values: R=%f G=%f B=%f\n", clearVals[0], clearVals[1], clearVals[2]);
printf("Dense film values: R=%f G=%f B=%f\n", denseVals[0], denseVals[1], denseVals[2]);
}
float denseGreenRatio = clearVals[1] / denseVals[1];
// Calculate exponents for each channel, based on the ratio between the bright and dark values,
// compared to the ratio in the reference channel (green)
for(int ch=0; ch<3; ch++)
if(ch==1)
newExps[ch] = 1.f; // Green is the reference channel
else
newExps[ch] = CLAMP(logBase(clearVals[ch] / denseVals[ch], denseGreenRatio), 0.3f, 3.f);
if (settings->verbose)
printf("New exponents: R=%f G=%f B=%f\n", newExps[0], newExps[1], newExps[2]);
return true;
}
void RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams &params)
{
if(!params.enabled)
return;
float exps[3] = { (float)params.redExp, (float)params.greenExp, (float)params.blueExp };
MyTime t1, t2, t3,t4, t5, t6;
t1.set();
if(ri->getSensorType() == ST_BAYER) {
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 16)
#endif
for (int row = 0; row < H; row ++) {
int col = 0;
// Exponents are expressed as positive in the parameters, so negate them in order
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
const float exps0 = -exps[FC(row, col)];
const float exps1 = -exps[FC(row, col + 1)];
#ifdef __SSE2__
const vfloat expsv = _mm_setr_ps(exps0, exps1, exps0, exps1);
const vfloat onev = F2V(1.f);
for (; col < W - 3; col+=4) {
STVFU(rawData[row][col], pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv));
}
#endif // __SSE2__
for (; col < W - 1; col+=2) {
rawData[row][col] = pow_F(max(rawData[row][col], 1.f), exps0);
rawData[row][col + 1] = pow_F(max(rawData[row][col + 1], 1.f), exps1);
}
if (col < W) {
rawData[row][col] = pow_F(max(rawData[row][col], 1.f), exps0);
}
}
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic, 16)
#endif
for (int row = 0; row < H; row ++) {
int col = 0;
// Exponents are expressed as positive in the parameters, so negate them in order
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
const float expsc[6] = {-exps[ri->XTRANSFC(row, 0)], -exps[ri->XTRANSFC(row, 1)], -exps[ri->XTRANSFC(row, 2)], -exps[ri->XTRANSFC(row, 3)], -exps[ri->XTRANSFC(row, 4)], -exps[ri->XTRANSFC(row, 5)]};
#ifdef __SSE2__
const vfloat expsv0 = _mm_setr_ps(expsc[0], expsc[1], expsc[2], expsc[3]);
const vfloat expsv1 = _mm_setr_ps(expsc[4], expsc[5], expsc[0], expsc[1]);
const vfloat expsv2 = _mm_setr_ps(expsc[2], expsc[3], expsc[4], expsc[5]);
const vfloat onev = F2V(1.f);
for (; col < W - 11; col+=12) {
STVFU(rawData[row][col], pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv0));
STVFU(rawData[row][col + 4], pow_F(vmaxf(LVFU(rawData[row][col + 4]), onev), expsv1));
STVFU(rawData[row][col + 8], pow_F(vmaxf(LVFU(rawData[row][col + 8]), onev), expsv2));
}
#endif // __SSE2__
for (; col < W - 5; col+=6) {
for (int c = 0; c < 6; ++c) {
rawData[row][col + c] = pow_F(max(rawData[row][col + c], 1.f), expsc[c]);
}
}
for (int c = 0; col < W; col++, c++) {
rawData[row][col + c] = pow_F(max(rawData[row][col + c], 1.f), expsc[c]);
}
}
}
t2.set();
if (settings->verbose)
printf("Pow loop time us: %d\n", t2.etime(t1));
// Channel vectors to calculate medians
std::vector<float> cvs[3] = {
std::vector<float>(),
std::vector<float>(),
std::vector<float>()
};
// Sample one every 5 pixels, and push the value in the appropriate channel vector.
// Chose an odd step, not multiple of the CFA size, to get a chance to visit each channel.
if(ri->getSensorType() == ST_BAYER) {
for (int row = 0; row < H; row+=5) {
for (int col = 0; col < W; col+=5) {
int c = FC(row, col); // three colors, 0=R, 1=G, 2=B
cvs[c].push_back(rawData[row][col]);
}
}
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
for (int row = 0; row < H; row+=5) {
for (int col = 0; col < W; col+=5) {
int c = ri->XTRANSFC(row, col); // three colors, 0=R, 1=G, 2=B
cvs[c].push_back(rawData[row][col]);
}
}
}
const float MAX_OUT_VALUE = 65000.f;
t3.set();
if (settings->verbose)
printf("Median vector fill loop time us: %d\n", t3.etime(t2));
float medians[3]; // Channel median values
float mults[3] = { 1.f }; // Channel normalization multipliers
for (int c=0; c<3; c++) {
// Find median values for each channel using a histogram search function
findMinMaxPercentile(&cvs[c][0], cvs[c].size(), 0.5f, medians[c], 0.5f, medians[c], true);
// Determine the channel multipler so that N times the median becomes 65k. This clips away
// the values in the dark border surrounding the negative (due to the film holder, for example),
// the reciprocal of which have blown up to stellar values.
mults[c] = MAX_OUT_VALUE / (medians[c] * 24);
}
t4.set();
if (settings->verbose) {
printf("Sample count : %lu, %lu, %lu\n", cvs[0].size(), cvs[1].size(), cvs[2].size());
printf("Medians : %f %f %f\n", medians[0], medians[1], medians[2] );
printf("Computed multipliers : %f %f %f\n", mults[0], mults[1], mults[2] );
printf("Median calc time us: %d\n", t4.etime(t3));
}
if(ri->getSensorType() == ST_BAYER) {
#ifdef _OPENMP
#pragma omp for nowait
#endif
for (int row = 0; row < H; row ++) {
for (int col = 0; col < W; col++) {
int c = FC(row, col); // three colors, 0=R, 1=G, 2=B
// Apply the multipliers
rawData[row][col] *= mults[c];
}
}
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
#ifdef _OPENMP
#pragma omp for nowait
#endif
for (int row = 0; row < H; row ++) {
for (int col = 0; col < W; col++) {
int c = ri->XTRANSFC(row, col); // three colors, 0=R, 1=G, 2=B
// Apply the multipliers
rawData[row][col] *= mults[c];
}
}
}
t5.set();
if (settings->verbose)
printf("Mult loop time us: %d\n", t5.etime(t4));
PixelsMap bitmapBads(W, H);
int totBP = 0; // Hold count of bad pixels to correct
if(ri->getSensorType() == ST_BAYER) {
#ifdef _OPENMP
#pragma omp parallel for reduction(+:totBP) schedule(dynamic,16)
#endif
for(int i = 0; i < H; i++)
for(int j = 0; j < W; j++) {
if (rawData[i][j] >= MAX_OUT_VALUE) {
bitmapBads.set(j, i);
totBP++;
}
}
if (totBP > 0) {
interpolateBadPixelsBayer( bitmapBads, rawData );
}
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
// TODO
}
t6.set();
if (settings->verbose) {
printf("Bad pixels count: %d\n", totBP);
printf("Bad pixels interpolation time us: %d\n", t6.etime(t5));
}
}
}

View File

@ -43,6 +43,7 @@ struct LensProfParams;
struct RAWParams;
struct RetinexParams;
struct ToneCurveParams;
struct FilmNegativeParams;
}
@ -77,6 +78,8 @@ public:
~ImageSource () override {}
virtual int load (const Glib::ustring &fname) = 0;
virtual void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) {};
virtual void filmNegativeProcess (const procparams::FilmNegativeParams &params) {};
virtual bool getFilmNegativeExponents (Coord2D spotA, Coord2D spotB, int tran, const FilmNegativeParams &currentParams, float newExps[3]) { return false; };
virtual void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold) {};
virtual void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D<float, 4> &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) {};
virtual void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) {};

View File

@ -277,6 +277,11 @@ void ImProcCoordinator::updatePreviewImage(int todo, bool panningRelatedChange)
imgsrc->getRAWHistogram(histRedRaw, histGreenRaw, histBlueRaw);
highDetailPreprocessComputed = highDetailNeeded;
// After preprocess, run film negative processing if enabled
if((todo & M_RAW) && (imgsrc->getSensorType() == ST_BAYER || imgsrc->getSensorType() == ST_FUJI_XTRANS) && params->filmNegative.enabled) {
imgsrc->filmNegativeProcess (params->filmNegative);
}
}
/*
@ -1250,6 +1255,32 @@ void ImProcCoordinator::getSpotWB(int x, int y, int rect, double& temp, double&
}
}
bool ImProcCoordinator::getFilmNegativeExponents(int xA, int yA, int xB, int yB, float* newExps)
{
{
MyMutex::MyLock lock(mProcessing);
auto xlate = [this](int x, int y) {
std::vector<Coord2D> points, red, green, blue;
points.push_back(Coord2D(x, y));
ipf.transCoord(fw, fh, points, red, green, blue);
return green[0];
};
int tr = getCoarseBitMask(params->coarse);
Coord2D p1 = xlate(xA, yA);
Coord2D p2 = xlate(xB, yB);
return imgsrc->getFilmNegativeExponents(p1, p2, tr, params->filmNegative, newExps);
} // end of mutex locking
}
void ImProcCoordinator::getAutoCrop(double ratio, int &x, int &y, int &w, int &h)
{

View File

@ -269,6 +269,7 @@ public:
bool getAutoWB (double& temp, double& green, double equal, double tempBias) override;
void getCamWB (double& temp, double& green) override;
void getSpotWB (int x, int y, int rectSize, double& temp, double& green) override;
bool getFilmNegativeExponents(int xA, int yA, int xB, int yB, float* newExps) override;
void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) override;
bool getHighQualComputed() override;
void setHighQualComputed() override;

View File

@ -2735,6 +2735,32 @@ bool MetaDataParams::operator!=(const MetaDataParams &other) const
}
FilmNegativeParams::FilmNegativeParams() :
enabled(false),
redExp(1.36),
greenExp(1.0),
blueExp(0.86)
{
}
bool FilmNegativeParams::operator ==(const FilmNegativeParams& other) const
{
return
enabled == other.enabled
&& redExp == other.redExp
&& greenExp == other.greenExp
&& blueExp == other.blueExp;
}
bool FilmNegativeParams::operator !=(const FilmNegativeParams& other) const
{
return !(*this == other);
}
ProcParams::ProcParams()
{
setDefaults();
@ -3566,6 +3592,13 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo
// MetaData
saveToKeyfile(!pedited || pedited->metadata.mode, "MetaData", "Mode", metadata.mode, keyFile);
// Film negative
saveToKeyfile(!pedited || pedited->filmNegative.enabled, "Film Negative", "Enabled", filmNegative.enabled, keyFile);
saveToKeyfile(!pedited || pedited->filmNegative.redExp, "Film Negative", "RedExponent", filmNegative.redExp, keyFile);
saveToKeyfile(!pedited || pedited->filmNegative.greenExp, "Film Negative", "GreenExponent", filmNegative.greenExp, keyFile);
saveToKeyfile(!pedited || pedited->filmNegative.blueExp, "Film Negative", "BlueExponent", filmNegative.blueExp, keyFile);
// EXIF change list
if (!pedited || pedited->exif) {
for (ExifPairs::const_iterator i = exif.begin(); i != exif.end(); ++i) {
@ -5109,6 +5142,14 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited)
assignFromKeyfile(keyFile, "RAW X-Trans", "PreBlackBlue", pedited, raw.xtranssensor.blackblue, pedited->raw.xtranssensor.exBlackBlue);
}
if (keyFile.has_group("Film Negative")) {
assignFromKeyfile(keyFile, "Film Negative", "Enabled", pedited, filmNegative.enabled, pedited->filmNegative.enabled);
assignFromKeyfile(keyFile, "Film Negative", "RedExponent", pedited, filmNegative.redExp, pedited->filmNegative.redExp);
assignFromKeyfile(keyFile, "Film Negative", "GreenExponent", pedited, filmNegative.greenExp, pedited->filmNegative.greenExp);
assignFromKeyfile(keyFile, "Film Negative", "BlueExponent", pedited, filmNegative.blueExp, pedited->filmNegative.blueExp);
}
if (keyFile.has_group("MetaData")) {
int mode = int(MetaDataParams::TUNNEL);
assignFromKeyfile(keyFile, "MetaData", "Mode", pedited, mode, pedited->metadata.mode);

View File

@ -1501,6 +1501,23 @@ struct RAWParams {
static Glib::ustring getFlatFieldBlurTypeString(FlatFieldBlurType type);
};
/**
* Parameters of film negative
*/
struct FilmNegativeParams {
bool enabled;
double redExp;
double greenExp;
double blueExp;
FilmNegativeParams();
bool operator ==(const FilmNegativeParams& other) const;
bool operator !=(const FilmNegativeParams& other) const;
};
/**
* This class holds all the processing parameters applied on the images
*/
@ -1559,6 +1576,8 @@ public:
ExifPairs exif; ///< List of modifications appplied on the exif tags of the input image
IPTCPairs iptc; ///< The IPTC tags and values to be saved to the output image
FilmNegativeParams filmNegative; ///< Film negative parameters
/**
* The constructor only sets the hand-wired defaults.
*/

View File

@ -44,6 +44,8 @@ private:
static LUTf initInvGrad ();
static void colorSpaceConversion_ (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName);
int defTransform (int tran);
bool channelsAvg(Coord spotPos, int spotSize, float avgs[3], const FilmNegativeParams &params);
protected:
MyMutex getImageMutex; // locks getImage
@ -116,6 +118,8 @@ public:
int load(const Glib::ustring &fname) override { return load(fname, false); }
int load(const Glib::ustring &fname, bool firstFrameOnly);
void preprocess (const procparams::RAWParams &raw, const procparams::LensProfParams &lensProf, const procparams::CoarseTransformParams& coarse, bool prepareDenoise = true) override;
void filmNegativeProcess (const procparams::FilmNegativeParams &params) override;
bool getFilmNegativeExponents (Coord2D spotA, Coord2D spotB, int tran, const FilmNegativeParams &currentParams, float newExps[3]) override;
void demosaic (const procparams::RAWParams &raw, bool autoContrast, double &contrastThreshold) override;
void retinex (const procparams::ColorManagementParams& cmp, const procparams::RetinexParams &deh, const procparams::ToneCurveParams& Tc, LUTf & cdcurve, LUTf & mapcurve, const RetinextransmissionCurve & dehatransmissionCurve, const RetinexgaintransmissionCurve & dehagaintransmissionCurve, multi_array2D<float, 4> &conversionBuffer, bool dehacontlutili, bool mapcontlutili, bool useHsl, float &minCD, float &maxCD, float &mini, float &maxi, float &Tmean, float &Tsigma, float &Tmin, float &Tmax, LUTu &histLRETI) override;
void retinexPrepareCurves (const procparams::RetinexParams &retinexParams, LUTf &cdcurve, LUTf &mapcurve, RetinextransmissionCurve &retinextransmissionCurve, RetinexgaintransmissionCurve &retinexgaintransmissionCurve, bool &retinexcontlutili, bool &mapcontlutili, bool &useHsl, LUTu & lhist16RETI, LUTu & histLRETI) override;

View File

@ -499,6 +499,7 @@ public:
virtual bool getAutoWB (double& temp, double& green, double equal, double tempBias) = 0;
virtual void getCamWB (double& temp, double& green) = 0;
virtual void getSpotWB (int x, int y, int rectSize, double& temp, double& green) = 0;
virtual bool getFilmNegativeExponents(int xA, int yA, int xB, int yB, float* newExps) = 0;
virtual void getAutoCrop (double ratio, int &x, int &y, int &w, int &h) = 0;
virtual void saveInputICCReference (const Glib::ustring& fname, bool apply_wb) = 0;

View File

@ -209,6 +209,11 @@ private:
imgsrc->setCurrentFrame (params.raw.bayersensor.imageNum);
imgsrc->preprocess ( params.raw, params.lensProf, params.coarse, params.dirpyrDenoise.enabled);
// After preprocess, run film negative processing if enabled
if(imgsrc->getSensorType() == ST_BAYER && params.filmNegative.enabled) {
imgsrc->filmNegativeProcess (params.filmNegative);
}
if (pl) {
pl->setProgress (0.20);
}

View File

@ -161,6 +161,7 @@ set(NONCLISOURCEFILES
labgrid.cc
softlight.cc
dehaze.cc
filmnegative.cc
)
include_directories(BEFORE "${CMAKE_CURRENT_BINARY_DIR}")

320
rtgui/filmnegative.cc Normal file
View File

@ -0,0 +1,320 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include "filmnegative.h"
#include <iomanip>
#include "rtimage.h"
#include "options.h"
#include "editwidgets.h"
#include "eventmapper.h"
using namespace rtengine;
using namespace rtengine::procparams;
FilmNegative::FilmNegative () : FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS)
{
auto mkExponentAdjuster = [this](Glib::ustring label, double defaultVal) {
Adjuster *adj = Gtk::manage(new Adjuster (label, 0.3, 3, 0.01, defaultVal)); //exponent
adj->setAdjusterListener (this);
if (adj->delay < options.adjusterMaxDelay) {
adj->delay = options.adjusterMaxDelay;
}
adj->show();
return adj;
};
redExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_RED"), 1.36);
greenExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_GREEN"), 1.0);
blueExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_BLUE"), 0.86);
auto m = ProcEventMapper::getInstance();
EvFilmNegativeEnabled = m->newEvent(ALL, "HISTORY_MSG_FILMNEGATIVE_ENABLED");
EvFilmNegativeExponents = m->newEvent(ALL, "HISTORY_MSG_FILMNEGATIVE_EXPONENTS");
spotgrid = Gtk::manage(new Gtk::Grid());
spotgrid->get_style_context()->add_class("grid-spacing");
setExpandAlignProperties(spotgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
spotbutton = Gtk::manage (new Gtk::ToggleButton (M("TP_FILMNEGATIVE_PICK")));
setExpandAlignProperties(spotbutton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
spotbutton->get_style_context()->add_class("independent");
spotbutton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP"));
spotbutton->set_image (*Gtk::manage (new RTImage ("color-picker-small.png")));
// TODO make spot size configurable ?
// Gtk::Label* slab = Gtk::manage (new Gtk::Label (M("TP_WBALANCE_SIZE")));
// setExpandAlignProperties(slab, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
// Gtk::Grid* wbsizehelper = Gtk::manage(new Gtk::Grid());
// wbsizehelper->set_name("WB-Size-Helper");
// setExpandAlignProperties(wbsizehelper, false, false, Gtk::ALIGN_START, Gtk::ALIGN_CENTER);
// spotsize = Gtk::manage (new MyComboBoxText ());
// setExpandAlignProperties(spotsize, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
// spotsize->append ("2");
// spotsize->set_active(0);
// spotsize->append ("4");
spotgrid->attach (*spotbutton, 0, 1, 1, 1);
// spotgrid->attach (*slab, 1, 0, 1, 1);
// spotgrid->attach (*wbsizehelper, 2, 0, 1, 1);
pack_start (*redExp, Gtk::PACK_SHRINK, 0);
pack_start (*greenExp, Gtk::PACK_SHRINK, 0);
pack_start (*blueExp, Gtk::PACK_SHRINK, 0);
pack_start (*spotgrid, Gtk::PACK_SHRINK, 0 );
spotbutton->signal_toggled().connect( sigc::mem_fun(*this, &FilmNegative::editToggled) );
// spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) );
// Editing geometry; create the spot rectangle
Rectangle *spotRect = new Rectangle();
spotRect->filled = false;
EditSubscriber::visibleGeometry.push_back( spotRect );
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
// This is to make sure the getCursor call is fired everywhere.
Rectangle *imgRect = new Rectangle();
imgRect->filled = true;
EditSubscriber::mouseOverGeometry.push_back( imgRect );
}
FilmNegative::~FilmNegative()
{
// idle_register.destroy();
for (std::vector<Geometry*>::const_iterator i = visibleGeometry.begin(); i != visibleGeometry.end(); ++i) {
delete *i;
}
for (std::vector<Geometry*>::const_iterator i = mouseOverGeometry.begin(); i != mouseOverGeometry.end(); ++i) {
delete *i;
}
}
void FilmNegative::enabledChanged()
{
if (listener) {
if (get_inconsistent()) {
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_UNCHANGED"));
} else if (getEnabled()) {
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_ENABLED"));
} else {
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_DISABLED"));
}
}
}
void FilmNegative::adjusterChanged(Adjuster* a, double newval)
{
if (listener && getEnabled()) {
if(a == redExp || a == greenExp || a == blueExp) {
listener->panelChanged (EvFilmNegativeExponents, Glib::ustring::compose (
"R=%1 ; G=%2 ; B=%3", redExp->getTextValue(), greenExp->getTextValue(), blueExp->getTextValue()));
}
}
}
void FilmNegative::adjusterAutoToggled(Adjuster* a, bool newval)
{
}
void FilmNegative::setEditProvider (EditDataProvider* provider)
{
EditSubscriber::setEditProvider(provider);
}
void FilmNegative::editToggled ()
{
if (spotbutton->get_active()) {
subscribe();
int w, h;
getEditProvider()->getImageSize(w, h);
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
// This is to make sure the getCursor call is fired everywhere.
const auto imgRect = static_cast<Rectangle*>(mouseOverGeometry.at(0));
imgRect->setXYWH(0, 0, w, h);
} else {
this->refSpotCoords.clear();
unsubscribe();
}
}
void FilmNegative::read (const ProcParams* pp, const ParamsEdited* pedited)
{
disableListener ();
if(pedited) {
redExp->setEditedState(pedited->filmNegative.redExp ? Edited : UnEdited);
greenExp->setEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited);
blueExp->setEditedState(pedited->filmNegative.blueExp ? Edited : UnEdited);
set_inconsistent(multiImage && !pedited->filmNegative.enabled);
}
setEnabled(pp->filmNegative.enabled);
redExp->setValue(pp->filmNegative.redExp);
greenExp->setValue(pp->filmNegative.greenExp);
blueExp->setValue(pp->filmNegative.blueExp);
enableListener ();
}
void FilmNegative::write (ProcParams* pp, ParamsEdited* pedited)
{
pp->filmNegative.redExp = redExp->getValue();
pp->filmNegative.greenExp = greenExp->getValue();
pp->filmNegative.blueExp = blueExp->getValue();
pp->filmNegative.enabled = getEnabled();
if (pedited) {
pedited->filmNegative.redExp = redExp->getEditedState();
pedited->filmNegative.greenExp = greenExp->getEditedState();
pedited->filmNegative.blueExp = blueExp->getEditedState();
pedited->filmNegative.enabled = !get_inconsistent();
}
}
void FilmNegative::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited)
{
redExp->setValue(defParams->filmNegative.redExp);
greenExp->setValue(defParams->filmNegative.greenExp);
blueExp->setValue(defParams->filmNegative.blueExp);
if (pedited) {
redExp->setDefaultEditedState (pedited->filmNegative.redExp ? Edited : UnEdited);
greenExp->setDefaultEditedState (pedited->filmNegative.greenExp ? Edited : UnEdited);
blueExp->setDefaultEditedState (pedited->filmNegative.blueExp ? Edited : UnEdited);
} else {
redExp->setDefaultEditedState (Irrelevant);
greenExp->setDefaultEditedState (Irrelevant);
blueExp->setDefaultEditedState (Irrelevant);
}
}
void FilmNegative::setBatchMode (bool batchMode)
{
spotConn.disconnect();
removeIfThere(this, spotgrid, false);
ToolPanel::setBatchMode (batchMode);
redExp->showEditedCB ();
greenExp->showEditedCB ();
blueExp->showEditedCB ();
}
bool FilmNegative::mouseOver(int modifierKey)
{
EditDataProvider *provider = getEditProvider();
const auto spotRect = static_cast<Rectangle*>(visibleGeometry.at(0));
spotRect->setXYWH(provider->posImage.x - 16, provider->posImage.y - 16, 32, 32);
return true;
}
bool FilmNegative::button1Pressed(int modifierKey)
{
EditDataProvider *provider = getEditProvider();
if(provider) { // debug. remove me
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
}
EditSubscriber::action = EditSubscriber::Action::NONE;
if (listener) {
refSpotCoords.push_back(provider->posImage);
if(refSpotCoords.size() == 2) {
// User has selected 2 reference gray spots. Calculating new exponents
// from channel values and updating parameters.
float newExps[3];
if(fnp->getFilmNegativeExponents(refSpotCoords[0], refSpotCoords[1], newExps)) {
disableListener();
redExp->setValue(newExps[0]);
greenExp->setValue(newExps[1]);
blueExp->setValue(newExps[2]);
enableListener();
if (listener && getEnabled()) {
listener->panelChanged (EvFilmNegativeExponents, Glib::ustring::compose (
"R=%1 ; G=%2 ; B=%3", redExp->getTextValue(), greenExp->getTextValue(), blueExp->getTextValue()));
}
}
switchOffEditMode();
}
}
return true;
}
bool FilmNegative::button1Released ()
{
EditDataProvider *provider = getEditProvider();
if(provider) { // debug. remove me
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
}
EditSubscriber::action = EditSubscriber::Action::NONE;
return true;
}
// TODO remove me ; couldn't make Action::PICKING work
bool FilmNegative::pick1 (bool picked) {
EditDataProvider *provider = getEditProvider();
if(provider) { // debug. remove me
printf("Picked pick=%d x=%d y=%d pv1=%f pv2=%f pv3=%f\n", picked, provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
}
return true;
}
CursorShape FilmNegative::getCursor(int objectID) const
{
return CSSpotWB;
}
void FilmNegative::switchOffEditMode ()
{
refSpotCoords.clear();
unsubscribe();
spotbutton->set_active(false);
}

91
rtgui/filmnegative.h Normal file
View File

@ -0,0 +1,91 @@
/*
* This file is part of RawTherapee.
*
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
*
* RawTherapee is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* RawTherapee is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _NEG_H_
#define _NEG_H_
#include <gtkmm.h>
#include "toolpanel.h"
#include "adjuster.h"
#include "guiutils.h"
#include "wbprovider.h"
#include "editcallbacks.h"
#include "../rtengine/procparams.h"
class FilmNegProvider
{
public:
virtual ~FilmNegProvider() = default;
virtual bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, float* newExps) = 0;
};
class FilmNegative : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public EditSubscriber
{
private:
rtengine::ProcEvent EvFilmNegativeExponents;
rtengine::ProcEvent EvFilmNegativeEnabled;
std::vector<rtengine::Coord> refSpotCoords;
FilmNegProvider *fnp;
Adjuster* redExp;
Adjuster* greenExp;
Adjuster* blueExp;
Gtk::Grid* spotgrid;
Gtk::ToggleButton* spotbutton;
sigc::connection spotConn;
void editToggled ();
public:
FilmNegative ();
~FilmNegative () override;
void setFilmNegProvider(FilmNegProvider* p)
{
fnp = p;
};
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override;
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override;
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override;
void setBatchMode (bool batchMode) override;
void adjusterChanged (Adjuster* a, double newval) override;
void adjusterAutoToggled(Adjuster* a, bool newval) override;
void spotPressed ();
void enabledChanged() override;
void setEditProvider (EditDataProvider* provider) override;
// EditSubscriber interface
CursorShape getCursor(int objectID) const override;
bool mouseOver(int modifierKey) override;
bool button1Pressed(int modifierKey) override;
bool button1Released() override;
void switchOffEditMode () override;
bool pick1(bool picked) override;
};
#endif

View File

@ -580,6 +580,10 @@ void ParamsEdited::set(bool v)
dehaze.showDepthMap = v;
dehaze.depth = v;
metadata.mode = v;
filmNegative.enabled = v;
filmNegative.redExp = v;
filmNegative.greenExp = v;
filmNegative.blueExp = v;
exif = v;
iptc = v;
@ -1142,6 +1146,10 @@ void ParamsEdited::initFrom(const std::vector<rtengine::procparams::ProcParams>&
dehaze.showDepthMap = dehaze.showDepthMap && p.dehaze.showDepthMap == other.dehaze.showDepthMap;
dehaze.depth = dehaze.depth && p.dehaze.depth == other.dehaze.depth;
metadata.mode = metadata.mode && p.metadata.mode == other.metadata.mode;
filmNegative.enabled = filmNegative.enabled && p.filmNegative.enabled == other.filmNegative.enabled;
filmNegative.redExp = filmNegative.redExp && p.filmNegative.redExp == other.filmNegative.redExp;
filmNegative.greenExp = filmNegative.greenExp && p.filmNegative.greenExp == other.filmNegative.greenExp;
filmNegative.blueExp = filmNegative.blueExp && p.filmNegative.blueExp == other.filmNegative.blueExp;
// How the hell can we handle that???
// exif = exif && p.exif==other.exif
@ -3175,6 +3183,22 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng
toEdit.metadata.mode = mods.metadata.mode;
}
if (filmNegative.enabled) {
toEdit.filmNegative.enabled = mods.filmNegative.enabled;
}
if (filmNegative.redExp) {
toEdit.filmNegative.redExp = mods.filmNegative.redExp;
}
if (filmNegative.greenExp) {
toEdit.filmNegative.greenExp = mods.filmNegative.greenExp;
}
if (filmNegative.blueExp) {
toEdit.filmNegative.blueExp = mods.filmNegative.blueExp;
}
// Exif changes are added to the existing ones
if (exif)
for (procparams::ExifPairs::const_iterator i = mods.exif.begin(); i != mods.exif.end(); ++i) {
@ -3216,3 +3240,8 @@ bool RetinexParamsEdited::isUnchanged() const
{
return enabled && retinexcolorspace && gammaretinex && gam && slope;
}
bool FilmNegativeParamsEdited::isUnchanged() const
{
return enabled && redExp && greenExp && blueExp;
}

View File

@ -666,6 +666,15 @@ struct MetaDataParamsEdited {
bool mode;
};
struct FilmNegativeParamsEdited {
bool enabled;
bool redExp;
bool greenExp;
bool blueExp;
bool isUnchanged() const;
};
struct ParamsEdited {
GeneralParamsEdited general;
ToneCurveParamsEdited toneCurve;
@ -710,6 +719,7 @@ struct ParamsEdited {
SoftLightParamsEdited softlight;
DehazeParamsEdited dehaze;
MetaDataParamsEdited metadata;
FilmNegativeParamsEdited filmNegative;
bool exif;
bool iptc;

View File

@ -92,6 +92,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
bayerrawexposure = Gtk::manage (new BayerRAWExposure ());
xtransrawexposure = Gtk::manage (new XTransRAWExposure ());
fattal = Gtk::manage (new FattalToneMapping ());
filmNegative = Gtk::manage (new FilmNegative ());
// So Demosaic, Line noise filter, Green Equilibration, Ca-Correction (garder le nom de section identique!) and Black-Level will be moved in a "Bayer sensor" tool,
// and a separate Demosaic and Black Level tool will be created in an "X-Trans sensor" tool
@ -154,6 +155,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
addfavoritePanel (rawPanel, preprocess);
addfavoritePanel (rawPanel, darkframe);
addfavoritePanel (rawPanel, flatfield);
addfavoritePanel (rawPanel, filmNegative);
int favoriteCount = 0;
for(auto it = favorites.begin(); it != favorites.end(); ++it) {
@ -255,6 +257,7 @@ ToolPanelCoordinator::ToolPanelCoordinator (bool batch) : ipc (nullptr), favorit
distortion->setLensGeomListener (this);
crop->setCropPanelListener (this);
icm->setICMPanelListener (this);
filmNegative->setFilmNegProvider (this);
toolBar = new ToolBar ();
toolBar->setToolBarListener (this);
@ -305,6 +308,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt
sensorbayer->FoldableToolPanel::show();
preprocess->FoldableToolPanel::show();
flatfield->FoldableToolPanel::show();
filmNegative->FoldableToolPanel::show();
retinex->FoldableToolPanel::setGrayedOut(false);
return false;
@ -320,6 +324,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt
sensorbayer->FoldableToolPanel::hide();
preprocess->FoldableToolPanel::show();
flatfield->FoldableToolPanel::show();
filmNegative->FoldableToolPanel::show();
retinex->FoldableToolPanel::setGrayedOut(false);
return false;
@ -335,6 +340,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt
sensorxtrans->FoldableToolPanel::hide();
preprocess->FoldableToolPanel::hide();
flatfield->FoldableToolPanel::show();
filmNegative->FoldableToolPanel::hide();
retinex->FoldableToolPanel::setGrayedOut(false);
return false;
@ -349,6 +355,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt
sensorxtrans->FoldableToolPanel::hide();
preprocess->FoldableToolPanel::hide();
flatfield->FoldableToolPanel::hide();
filmNegative->FoldableToolPanel::hide();
retinex->FoldableToolPanel::setGrayedOut(false);
return false;
@ -360,6 +367,7 @@ void ToolPanelCoordinator::imageTypeChanged (bool isRaw, bool isBayer, bool isXt
[this]() -> bool
{
rawPanelSW->set_sensitive(false);
filmNegative->FoldableToolPanel::hide();
retinex->FoldableToolPanel::setGrayedOut(true);
return false;
@ -476,7 +484,7 @@ void ToolPanelCoordinator::profileChange(
lParams[1] = *mergedParams;
pe.initFrom (lParams);
filterRawRefresh = pe.raw.isUnchanged() && pe.lensProf.isUnchanged() && pe.retinex.isUnchanged();
filterRawRefresh = pe.raw.isUnchanged() && pe.lensProf.isUnchanged() && pe.retinex.isUnchanged() && pe.filmNegative.isUnchanged();
}
*params = *mergedParams;
@ -1014,3 +1022,11 @@ void ToolPanelCoordinator::setEditProvider (EditDataProvider *provider)
toolPanels.at (i)->setEditProvider (provider);
}
}
bool ToolPanelCoordinator::getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, float* newExps)
{
if(!ipc)
return false;
return ipc->getFilmNegativeExponents(spotA.x, spotA.y, spotB.x, spotB.y, newExps);
}

View File

@ -82,6 +82,7 @@
#include "softlight.h"
#include "dehaze.h"
#include "guiutils.h"
#include "filmnegative.h"
class ImageEditorCoordinator;
@ -97,7 +98,8 @@ class ToolPanelCoordinator :
public CropPanelListener,
public ICMPanelListener,
public ImageAreaToolListener,
public rtengine::ImageTypeListener
public rtengine::ImageTypeListener,
public FilmNegProvider
{
protected:
WhiteBalance* whitebalance;
@ -152,6 +154,7 @@ protected:
XTransRAWExposure* xtransrawexposure;
FattalToneMapping *fattal;
MetaDataPanel* metadata;
FilmNegative* filmNegative;
std::vector<PParamsChangeListener*> paramcListeners;
@ -288,6 +291,9 @@ public:
rtengine::RawImage* getFF() override;
Glib::ustring GetCurrentImageFilePath() override;
// FilmNegProvider interface
bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, float* newExps) override;
// rotatelistener interface
void straightenRequested () override;
void autoCropRequested () override;