Scanned image scratch removal with “ICE”

It requires only the 1:1 view. E.g., if it shows the mask (only black and white values), it seems that the magnitude scaling (black/white point) when the threshold is computed depends on the area shown. It works correct with different areas on the command line.

I uploaded the test file again if you want to have a look: https://filebin.net/gqc36e26a63vmuin/raw0009.tif (150 MB).

Great news. I read about it here already, but did not know about standalone capabilities.

@chris
The problem is the combination of view area and “-lt $1%”. Using a percentage means base it on min/max values in the area supplied to the filter.

You could either base it on a fixed min/max or you could make the preview full image, but neither are likely to be perfect anyway. Perhaps there’s some other way I haven’t thought of though.

Hm, but on the command line the “-lt x%” seems independent of the actual input data range but in GIMP it seems not. What’s the difference and how can I achieve identical behaviour, such that I can reuse the parameters found in GIMP on the command line?

@garagecoder is right, you have this problem here :slight_smile:

  • The -lt. $1% is intended to depend on the min/max values of the whole image, which means that in the preview you’ll compute the threshold uniquely based on the min/max values of a cropped region. Not good or an accurate preview, if you zoom only on very dark or bright regions for instance. I suggest you use an absolute value instead of a percentage (the RGB input image has always values constrained to be in [0,255], so -lt. {$1*255%} should be great here.

Thanks for the suggestions, @garagecoder and @David_Tschumperle, it works well in GIMP G’MIC. Here’s the updated code for Version 1.8.0:

#@gui ICE : ice, ice(0)
#@gui : note = note("Scratch removal for scanned film images")
#@gui : sep = separator()
#@gui : Threshold = float(72,0,100)
#@gui : Erosion = int(2,0,5)
#@gui : Dilation = int(4,0,7)
#@gui : Show preview after = choice("threshold","erosion","dilation","final image")
ice :
-sh 0,2
-sh.. 3
-lt. {$1*255%}

-if {$4>=1}
  -erode. $2
-endif

-if {$4>=2}
  -dilate. $3
-endif

-if {$4<3}
  -k...
  -channels 3
  -* 255
-else
  -inpaint_patchmatch.. [-1]
  -k...
  -channels 0,2
-endif

Feel free to include this into G’MIC if you think it could be useful for other people. Maybe better change the name then, ICE may be trademarked in the context of scratch removal. Since in Germany ICE is a type of high speed train and G’MIC is a french product, I would suggest “TGV scratch removal” ;-).

Edit: If you decide to do so, I of course would contribute documentation on the whole process.

Hello Chris,

I’ve worked a bit on your code, to make it more clean :

  • I’ve added a Split preview option.
  • I’ve separated the preview process and the final process, so that you always get the final result when you actually apply the filter (even when the Preview as option is different).
  • I’ve added a loop to make your filter work with multiple input layers (and do not crash when input image is not in RGBA).
  • I’ve added a credit note at the end of the filter.

That’s how the code looks now, feel free to suggest any modification you would like to see:

#@gui Remove scratches : fx_remove_scratches, fx_remove_scratches_preview(0)
#@gui : note = note("<small><b>Note:</b> Scratch removal for scanned film images</small>")
#@gui : sep = separator()
#@gui : Threshold = float(72,0,100)
#@gui : Erosion = int(2,0,5)
#@gui : Dilation = int(4,0,7)
#@gui : Show preview after = choice(3,"Threshold","Erosion","Dilation","Final image")
#@gui : sep = separator(), Preview type = choice("Full","Forward horizontal","Forward vertical","Backward horizontal","Backward vertical","Duplicate top","Duplicate left","Duplicate bottom","Duplicate right")
#@gui : sep = separator(), note = note("<small>Author: <i>Chris/Pixls.us</i>.      Latest update: <i>01/04/2017</i>.</small>")
_fx_remove_scratches :
  -repeat $! -l[$>] -to_rgba
    -sh 0,2
    -sh.. 3
    -lt. {$1*255%}
    -if {$4>=1} -erode. $2 -endif
    -if {$4>=2} -dilate. $3 -endif
    -if {$4<3} -k... -channels 3 -* 255
    -else -inpaint_patchmatch.. [-1] -k... -channels 0,2
    -endif
  -endl -done

fx_remove_scratches :
  -_fx_remove_scratches ${1-3},3

fx_remove_scratches_preview :
  -gui_split_preview "-_fx_remove_scratches $*",$-1

I’ve put this filter in Testing / Chris - pixls.us. It should be really available after a filter refresh, with G’MIC plug-in 1.8.0.

2 Likes

That looks great, I already checked in GIMP. Nevertheless, it seems odd for me to claim authorship, it is mainly garagecoder’s and your work. However, I am going to take care of the filter and will start over with writing a proper tutorial the next days (or maybe some weeks, depending on other workload).

Not odd at all, you had the motivation/idea and wrote it to your needs. All we did was a little nudge :wink:

And the best part is others can use it now too.

1 Like

I’ve looked for some documentation on the “Remove scratches” filter, but this thread also didn’t really tell me how to use it.

So I’ve got 2 layers in GIMP: the actual image & the infrared mask. How do I apply the “Remove scratches” filter now?

in g’mic, look in Testing / Chris - pixls.us the g’mic filter mentioned a few posts above should be there.

Oh I know where it is, I just don’t know how to use it. There’s no way to say what layer it should use for the scratches information.

I may be wrong about this, but seem to remember the infrared layer needs to be merged into the alpha/opacity layer of the image. In other words combine the RGB + infra into a single RGBA.

@garagecoder is correct about this topic, IR information is expected in the alpha channel. That’s e.g. the format vuescan saves this information.

Btw, could you tell where (which software etc.) you got this format from? If this is a standard output of another software, maybe it should be considered as another input option in the filter.

Furthermore, I would like to ask if it was useful for you or if there was anything missing (besides documentation, it’s still on my task list, but real life …).

If you require further assistance, please let me know. It’s good to see there are people with similar problems around :slight_smile:.

Hello,

since I am interested to look into this problem also for Kodachrome slides in detail, I installed the latest version of Gimp and the G’MIC plugin. However, when I ran the scratch removal, I get an error message:

Any ideas what went wrong?

Is there any more detailed documentation than the reference manual to understand what the various versions of inpaint do? I would very much appreciate more information on that.

Hermann-Josef

@Jossie I just encountered the same bug today. Closing and restarting Gimp cured the problem for me.

@sguyader
Unfortunately that did not help.

Hermann-Josef

@Jossie same problem for me… maybe coincidence but the preview command was updated recently. Perhaps one for @David_Tschumperle

He’s no doubt the best to answer questions about the inpaint methods as well. They range from simple to sophisticated, I think the newest is based on “patchmatch” algorithm which you can find easily.

I’m sorry guys, I’ve indeed broke the split preview command today with a small update.
I’ve fixed it, and after updating your filters (push the filter update button), it should be working again.
Sorry for the inconvenience.

2 Likes

@David_Tschumperle

Good morning David,

thanks a lot for the quick repair!

I am new to G’MIC. The scratch removal it provides is something I was long thinking about working on. Now the issue seems to be solved at least for negatives and E6-emulsion. However, for Kodachrome there is the problem that the IR-channel contains a strong signal from the scene (due to the high Ag-content).

For the VueScan scratch removal approach on Kodachrome this is a disaster (applying corrections all over dark areas and thus reducing contrast there considerably) and it should not be used in my opinion. The G’MIC script and also SilverFast have problems with satisfactory consistent corrections both in dark and bright areas of the image. The correction either affects also dark areas, where there are no artefacts, or by lowering the threshold, artefacts in brighter regions are not corrected satisfactorily. Here I would like to find a solution with G’MIC.

Is there a more detailed description (more detailed than in the reference manual) on what the various inpaint commands actually do?

I guess, I will find instructions on how to write my own script in the documentation, which I have not yet studied carefully.

Many thanks for great software!

Hermann-Josef