Scanned image scratch removal with “ICE”

The image is available here as VS_FN_0003.tif.

To ensure that not some other operation introduces the colour shift I compared the original with the result of the G’MIC script directly (without converting in PhotoShop with ColorPerfect). I also compared the original with the orignal as exported by GIMP without applying the script (i.e. no changes at all!). I have removed the alpha-channel from all images with imageJ and then subtracted the GIMP-results from the original. The result is very strange:

On the left is the difference (original - script). It shows the defects as it should, but also some colour differences in all channels, which it shouldn’t. On the right is (original - GIMP only) and here only the R-channel differs, G and B are identical after the export from GIMP! Here all channels should be identical to zero, i.e. no colour difference, since no changes were made in GIMP. How can that be???

Just realized that in the TIF exported from GIMP after applying your script for scratch removal the alpha-channel is still there. All pixels are set to 65535. Since it does not contain any information it could be discarded.


I think that is a limitation of the G’MIC plugin. I think you cannot remove channels from the image layers in Gimp, therefore you would have to remove the channel in Gimp before saving. But that information may be outdated.

Regarding the other topic, I am totally lost. I am not sure which processing chains with which software leads to which results. It may be beneficial if you could make a simple list with the different chains and results and where you observe something unusual. Furthermore, it may be beneficial for sure if you could a test file that is a bit more moderate in file size, either a crop from the file you uploaded, or, even better, a small scan that includes some pure film material at one of the edges such that we have a neutral colour reference.

But, it was a long day already, maybe @garagecoder is a bit more fresh and has a better view on the issue. Since G’MIC is not colour managed and the script does only change the image in areas that are not masked (you can check the mask by changing the “Show preview after …” drop down), I would not expect any colour change by the script.

Your TIF is very large. The alpha has noise info.


Thanks for your comments.

The colour change is very strange and probably is a GIMP problem. I come to this conclusion since a very straight forward test provides the results above: Load image into GIMP and export it without any changes as a TIF. This is what I showed above. The side aspect, that I deleted the alpha-channel in imageJ, is only for demonstration purposes, since with the alpha-channel the display looks odd. All this assumes that imagej is working correctly :slight_smile: .

Yes, the scans are quite large, indeed. The “noise info” are the scratches and defects!


Here are the channel stats. I wonder how GIMP handles the alpha range in comparison to G’MIC. Also, I wonder if the colour change has to do with the alpha being grey scale. That would mean that there is interpolation happening on all the pixels in some manner.

min : 2069
max : 65535
mean: 38505.334375885774
std : 8831.2067611971379
rang: 63466

min : 752
max : 29167
mean: 13174.70579523862
std : 4620.8236825924314
rang: 28415

min : 304
max : 10904
mean: 5691.407874438356
std : 1372.6782105490483
rang: 10600

min : 6224
max : 56832
mean: 50701.402429768204
std : 1893.3387769891613
rang: 50608

I do not understand what you mean by “the alpha being grey scale”. The alpha-channel is the same as the other channels, it is 16bit “greyscale”.

I have repeated your measurements for the version which was load and exported as TIF in GIMP. This clearly also shows the problem:

No mean std min max median
1 38505 8831 2069 65535 37629
2 13175 4621 752 29167 11767
3 5691 1373 304 10904 5760
4 50701 1893 6224 56832 50960
5 38096 8081 2069 56160 37628
6 13175 4621 752 29167 11767
7 5691 1373 304 10904 5760
8 50701 1893 6224 56832 50960

Measurements 5 … 8 refer to the output from GIMP. The R-channel changed but shouldn’t, the others are the same as in the input image, which is correct.

I just installed the new GIMP version to see, if the problem remains. But there is an error message right at start, so I have to wait until this is solved. Re-installation of GIMP does not solve this issue.


Basically, when the alpha is 0, nothing happens. When alpha is 1 or max, there is inpainting. If it is grey scale and not 0, this means that all pixels receive inpainting to some extent. Would that then not mean that the colours would change and therefore be different?

On the other hand, the changing R channel does seem to be a bug. Have you tried reporting it or pinging anyone who is affiliated with GIMP?

PS My comment about range is important as well. G’MIC’s alpha range is 0-1 and the file’s is 0-65535, and I don’t know how GIMP reconciles with that. That might be a part of the problem.

The G’MIC script first computes a mask from the alpha channel. That’s its main purpose.

This script crashes gmic-qt with a segfault on this file (saved from vuescan as 64 bit RGBI)

I may have also accidentally wound up hijacking the filebin link from the OP, which seems like a slight security risk on the part of filebin :confused:

Hm, tested with your file and it works here:

It’s not the most recent gimp or G’MIC on my side (2.9.9/2.1.5), but maybe something important changed. Since I will not be able to test with a more recent version for a couple of days, it would be good if somebody else could do the test. However, can you give any additional information (command line/log outputs, software versions, …)?

When exactly does it crash? Could you please try the following: Before loading the image, open G’MIC and set the “Show preview after” drop-down to the first point (“Threshold”). Cancel the G’MIC window and load your file. Open G’MIC and check if it already crashes. If not, go to the second preview step and so on, and tell when it exactly crashes.

Hi, thanks for the fast response and apologies for disappearing for a couple of days!

Versions are as follows:
Gimp - 2.10.6
G’Mic - 2.3.4
Both using ubuntu 18.04 and this ppa

I ran gimp from the command line to try and source some kind of detailed output but sadly the segfault just looks like this:

*WARNING* missing babl fast path(s): "Y u16" to "Y' u8"
/usr/lib/gimp/2.0/plug-ins/gmic-gimp-qt/gmic-gimp-qt: fatal error: Segmentation fault
/usr/lib/gimp/2.0/plug-ins/gmic-gimp-qt/gmic-gimp-qt: fatal error: Segmentation fault
/usr/lib/gimp/2.0/plug-ins/gmic-gimp-qt/gmic-gimp-qt: fatal error: Segmentation fault
free(): corrupted unsorted chunks

(It crashes when creating the preview)

EDIT: Misinterpreted your testing instructions originally. So:

no preview = All is well initially, crash on hitting apply or ok
threshold = The entire preview box is white, no crash
erosion/dilation = same as threshold
final image = crash

Wow, well that was silly of me.

So, after wiggling the sliders around it properly created the mask and didn’t crash, so it seems the issue was as follows:

  1. Scanner creates noisy IR layer (Nikon LS-30 in this case)
  2. The filter’s default settings assume the entire image is one big scratch
  3. The full preview is generated and the infill (presumably) crashes because infilling an entire image is a bit silly
  4. Because the dialog box crashed I never managed to move the sliders!

So, problem solved! Might be worth changing the default preview mode if possible.

Hm, the initial threshold value is at 72%, and the initial preview is showing the final image, maybe it should default to showing the mask and using 0% as threshold. However, I wonder if it should be considered a bug in G’MIC that the inpaint with a malformed mask (e.g. 100% image coverage by mask) crashes instead of dropping an error message and skipping the computation, @David_Tschumperle?

@chris, @MPratley, I confirm the crash with your file.
This is clearly a bug, it shouldn’t crash of course, so thanks a lot for noticing this and allowing me to reproduce this bug easily.
I’ll try to fix it ASAP. Cheers :beers: !


Found the bug, and fixed it with commit :

I’ll post new pre-release packages tomorrow (v. 2.4.0_pre) with this fix included.
Thanks again for your detailed report !


So, after having a relatively successful run with the filter, I’ve been having trouble with a few scratched negs. The issue seems to stem from the fact that my scanner has a LOT of overlap between the IR and cyan in a negative image.

After playing around with numbers in the filter and not having much luck, I found this previous post on the forum that I assume is referring to the technique described in this paper linked from this stack exchange post. Whew, that was a lot of hyperlinks. To paraphrase the SE post:

The idea is to remove the shadow of the color information from the infrared image by using the red/cyan channel (the one with the wavelength closest to IR, depending on whether the image is inverted)

Any thoughts on perhaps using a similar technique in this filter?

Filebin | 94ru9yhnxrxow3of <-an example of a sad, scratched image with a naff IR layer.

1 Like

Are you sure that it is a leaking of the other channel? I see variations in the extend to which the scene is visible in the IR-channel, depending on the emulsion used. Most evident this is in Kodachrome, which is almost like B&W-negatives, i.e. you clearly see the scene in the IR. So I would conclude that it ist the emulsion composition, which produces the effect that you see the scene in the IR, and not any leakage. Leakage would be the same for all type of emulsions.

Having said that, I would use the fact that the defects are on a much smaller scale than the scene and remove the scene to isolate the scratches.


That’s exactly how I observed it and what I concluded as well. The histogram of the alpha channel shows a huge but narrow spike, such as (from the example crop above)
This spike contains image information, which I would guess is not a leakage effect but simply the IR light affected by the dye of the film. The scratches are almost black, to the left of the spike. This can be shown by adapting the dynamic range:

Therefore, setting the threshold to the left of the spike in the histogram works well for me.

Simple thresholding does not always work. It depends on the emulsion type. For Kodachrome one has to use a more elaborate procedure since the scene is very prominent:
At left is the RGB image with defects marked, to the right the IR-channel of a Kodachrome slide.
Some color negative films do also show the scene in the IR-channel, albeit not as strong as with Kodachrome.

At least for my scanner (DigitDia6000) leakage cannot happen. The IR-scan is taken in a separate exposure by the G-CCD with an IR-LED which has no emission at wavelength shorter than about 820nm and the RGB-LED is dead beyond 800nm.


Hi, I worked on this issue (scratches) in the past, then I gave up due to lack of time.

The “leakage” is implicitly meant as “effect of the emulsion on the IR channel”, as you also figured out. It’s not a “leakage” in the sense of the electronics involved as you seem to have undestood :slight_smile:

When “leak” (so to say) recognition is performed, the resulting image is PERFECT, I remember doing some tests. However, it required image per image tuning.

What I never got to find out is:

  • which colour channel(s) is/are best for the identification and substraction of the scene from the IR image, so that the process can be automated
  • how to properly perform the substraction once the best channel(s) is/are found. As I pointed out in the other thread Difference between two regression techniques different apparently correct approaches bring different correlation parameters, except for a simple test image, only for which they match as they should!

Regarding thresholding: mentioned by @chris : it cannot work, because besides scratches and dust (relatively sharp), there is something else in the IR channel… drop-shaped or smeared-shaped residues of developing/fixing solution! They cause the histogram to be much broader and with a much less certain threshold values. It won’t work automatically at all, and trust me that even manually you’ll have a hard time choosing the value.