Skip to content

Add RL output sharpening script #231

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Mar 22, 2020

Conversation

Mark-64
Copy link
Contributor

@Mark-64 Mark-64 commented Mar 10, 2020

Added RL_out_sharp.lua
Richardson-Lucy output sharpening using GMic
This script provides a new target storage "RL output sharpen".
Images exported will be sharpened using GMic (RL deblur algorithm)

Cattura15

local MODULE_NAME = "RL_out_sharp"

-- check API version
du.check_min_api_version("5.0.2", MODULE_NAME) -- darktable 3.x
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be "5.0.0". API versions 5.0.1 and 5.0.2 introduced some functions to control panel visibility, darkroom image selected, and collection manipulations. Since you're not using any of those things, you the minimum API version is 5.0.0 since you are using dt.configuration.running_os. This way the script will be compatible with darktable 2.6.x, for those who haven't upgraded yet.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


USAGE
* require this script from main lua file
* in lua preferences, select the GMic cli executable
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

After you select the executable, you have to restart darktable so that the darktablerc file, with the new preference gets read, otherwise the preference isn't available.

My preference is to do a df.check_if_bin_exists() then add the df.executable_path_widget() if it doesn't so the user can add the executable and then proceed to use the script without having to restart darktable. If the executable does exist, then don't show the widget.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I considered that option.
Personally, I prefer not to clutter the GUI with a widget that you use only once and forget
Moreover, df.check_if_bin_exists() adds a separator and a label that takes some space in the panel.
Maybe I can say to restart DT in the instructions, is that OK ?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You would use the widget the first time and then it wouldn't appear because the value is already set.

But, adding restart to the instructions is fine too.

local input_file, output_file, options

-- read parameters
local gmic = df.sanitize_filename(dt.preferences.read(MODULE_NAME, "gmic_exe", "string"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the user didn't go to the preferences and set this value, or if the user didn't restart after setting the preference, then this will return an empty string, IIRC, which will cause a crash when you try and execute the command. You should add a check to make sure there is something.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To my surprise, you don't need to restart DT when configuring GMic from lua preferences. It works just fine.
But it's true that if the user does not configure GMic there is an error, so I added a test anyway

dt.preferences.write(MODULE_NAME, "iterations", "string", iterations_str)
dt.preferences.write(MODULE_NAME, "jpg_quality", "string", jpg_quality_str)

local gmic_operation = " -deblur_richardsonlucy "..sigma_str..","..iterations_str..",1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I used fx_unsharp_richardsonlucy and built my widgets to resemble the gui in Gmic_qt in GIMP. This adds the choice of exponential blur (0) or guassian blur (1) and a cut parameter that seems to preserve luminance (If I understand correctly it restricts the output betweeen 0 and 255 for each iteration). fx_unsharp_richardsonlucy calls deblur_richardsonlucy and maps the arguments.

Copy link
Contributor Author

@Mark-64 Mark-64 Mar 10, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can use that, no pb, but the GMic functions of Gimp plugin are undocumented and I read somewhere that they might change without notice. I thought using -deblur_richardsonlucy was safer.
When coming to preserve luminance, you might have a point. In fact, I have to force cut to 0,255 at the end of the pipeline (see GMic command line). Can't say which is better.
Is -fx_unsharp_richardsonlucy compatible with tiff input files ? I will have to test

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote a postsharpen script that doesn't restrict the file types used. I didn't try RL against all the file types so I'm not sure if there is a problem with them or not. I guess I need to check.

It's here

fx_unsharp_richardsonlucy just calls deblur_richardsonlucy to do all the work.

After thinking about it I would say that using deblur_richardsonlucy is probably a better choice since it is part of the api and not something built on top of it.

new_name = df.filename_increment(new_name)
-- limit to 50 more exports of the original export
if string.match(df.get_basename(new_name), "_%d%d$") == "_50" then break end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is a function df.create_unique_filename() that does this but it goes to 99.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this comes from my other script and when I tried to use df.create_unique_filename() it didn't work for some reason, so I implemented myself.
I will try again

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is a problem with create_unique_filename, let me know and I'll track it down.


sigma_slider = dt.new_widget("slider"){
label = _("sigma"),
tooltip = _("sigma parameter in RL algorithm"),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Controls the width of the blur that's applied

sigma_slider.value = dt.preferences.read(MODULE_NAME, "sigma", "float")
iterations_slider.value = dt.preferences.read(MODULE_NAME, "iterations", "float")
jpg_quality_slider.value = dt.preferences.read(MODULE_NAME, "jpg_quality", "float")

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These statements will run when you first load the script, but not after so they will never update. They need to be moved into the export2RL function if you want to save the values that were used.

@Mark-64
Copy link
Contributor Author

Mark-64 commented Mar 11, 2020

With the last commit, I think I've implemented the requested modifications.
Some comments:

  1. I know and truly appreciate your script for output sharpening, but I wanted something very simple to routinely apply to my edits. For comparison, the super professional Capture One applies output sharpening by default and there is an option to disable, that's all. Not a single slider.
  2. I used the df.create_unique_filename() as you requested, but yes there is an issue. The count doeasn't actually stop at 99. I guess it will be quite rare to go over 99, but anyway I will make a PR for the fix, since I have one.
  3. About your last comment, those statements are there only to load the last used values of the sliders in the previous DT session at statup. I tried to put those within the widget declarations, but for some weird reason it doesn't work reliably that way. I made that more clear in the code comments.

@wpferguson
Copy link
Member

I exported a file just as a jpeg. Then I tried various settings with RL_output_sharpen and loaded the sharpened file and the original export as layers in GIMP. Then I set the blend mode to difference to see what effect the sharpening had. A sigma of .7 with 10 iterations had almost no effect (I couldn't find anything). I bumped the sigma to 2.0 (using my version) and could finally see a difference. You might want to try various settings and comparing the outputs to figure out a good default setting.

@Mark-64
Copy link
Contributor Author

Mark-64 commented Mar 22, 2020

Well, it depends on the image, the size and the usage (archive, web, print).
I tipically use output sharpening when exporting images for web, in that case I resize from 6000x4000 native camera resolution to 3000x2000 and I use sigma=0.7. See the effect below in a 1:1: crop:

Unsharpened
unsharpened

Sharpened
sharpened

Difference
difference

Anyway, in the last commit I increased the range of the sigma slider and put 1.0 as default, which by the way is the default in the Gimp plugin.

@wpferguson
Copy link
Member

Looks good to me

@wpferguson wpferguson merged commit a582f02 into darktable-org:master Mar 22, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants