5

I am trying to automate the cleanup process of a large amount of scanned films. I have all the images in 48-bit RGBI TIFF files (RGB + Infrared), and I can use the infrared channel to create masks for dust removal. I wonder if there is any decent open source implementation of in-painting that I can use to achieve this (all the other software I use for batch processing are open source libraries I access through Ruby interfaces).

My first choice was ImageMagick, but I couldn't find any advanced in-painting option in it (maybe I am wrong, though). I have heard this can be done with MagickWand libraries, but I haven't been able to find a concrete example yet.

I have also had a look at OpenCV, but it seems that OpenCV's in-paint method accept only 8-bit-per-channel images, while I must preserve the 16. Is there any other library, or even an interesting code snippet I am not aware of? Any help is appreciated.

Samples:

Full Picture

Full Picture

IR Channel

IR Channel

Dust and scratch mask

The Mask

What I want to remove automatically

To be removed

What I consider too large to remove with no user intervention

To be removed manually

You can also download the original TIFF file here. It contains two alpha channels. One is the original IR channel, and the other one is the IR channel already prepared for dust removal.

retrography
  • 6,302
  • 3
  • 22
  • 32
  • sorry for the editing noise, was just misreading it. – berak Nov 30 '14 at 21:07
  • Do you have any example images and corresponding infrared channel? What type of inpainting algorithm were you hoping for? Presumably the dust spots only amount to a few pixels each, so would a simple nearest neighbour algorithm suffice? What platform are you on? – Mark Setchell Nov 30 '14 at 22:07
  • I will post some samples right away. But at 4800ppi dust specks can look like icebergs. Also, sometimes IR channels picks up more than dust specks - things like emulsion scratches, development chemistry sediments and even stands of hair, etc... Those come in every shape. – retrography Nov 30 '14 at 22:16
  • Another option may be, if you know of some software that does 8-bit inpainting, to do that in 8-bit then scale just the inpainted pixels back up to 16 bit and replace into original 16-bit image - you do have the IR mask to extract the inpainted pixels after all... – Mark Setchell Nov 30 '14 at 22:50
  • Can you post the corresponding IR image too? – Mark Setchell Nov 30 '14 at 22:53
  • @MarkSetchell Actually, I tried this manually, and it didn't work. The reason is that dust and scratch removal should happen before inverting negatives to positive, gamma correction and color balancing, and since conversion to 8 bits remove some color information, those regions affected by the conversion won't respond to color manipulations in the same way. – retrography Nov 30 '14 at 22:55
  • @MarkSetchell The IR is embedded as Alpha channel within the TIFF. Do you need it as a separate TIFF file? Or do you just want to see it here as a Jpeg sample? – retrography Nov 30 '14 at 22:55
  • I can find it in the TIFF tomorrow - am only on iPad at the moment and hadn't appreciated it was present. – Mark Setchell Nov 30 '14 at 23:04
  • @MarkSetchell I just added some JPEG samples of the IR as well. Just refresh the page and you will see them. :) – retrography Nov 30 '14 at 23:05
  • Your TIFF file is no longer available. Please repost it. – fmw42 Jul 21 '19 at 18:18
  • Imagemagick does not have a inpainting method. But you can do something to mitigate the scratch in Imagemagick. See my answer at https://stackoverflow.com/questions/57126004/how-to-undo-or-remove-the-drawn-rectangle-using-convert/57126561#57126561. – fmw42 Jul 21 '19 at 18:20

3 Answers3

1

I have had an attempt at this, and can go some way to achieving some of your objectives... I can read in your 16-bit image, detect the dust pixels using the IR channel data, and replace them, and write out the result without any alpha channel and all the while preserving your 16-bit data.

The part that is lacking is the replacement algorithm - I have just propagated the next pixel from above. You, or someone cleverer than me on Stack Overflow, may be able to implement a better algorithm but this may be a start.

It is in Perl, but I guess it could be readily converted to another language. Here is the code:

#!/usr/bin/perl
use strict;
use warnings;
use Image::Magick;

# Open the input image
my $image = Image::Magick->new;
$image->ReadImage("pa.tiff");
my $v=0;
# Get its width and height
my ($width,$height)=$image->Get('width','height');

# Create output image of matching size
my $out= $image->Clone();

# Remove alpha channel from output image
$out->Set(alpha=>'off');

# Load Red, Green, Blue and Alpha channels of input image into arrays, values normalised to 1.0
my (@R,@G,@B,@A);
for my $y (0..($height-1)){
   my $j=0;
   my @RGBA=$image->GetPixels(map=>'RGBA',height=>1,width=>$width,x=>0,y=>$y,normalize=>1);
   for my $x (0..($width-1)){
      $R[$x][$y]=$RGBA[$j++];
      $G[$x][$y]=$RGBA[$j++];
      $B[$x][$y]=$RGBA[$j++];
      $A[$x][$y]=$RGBA[$j++];
   }
}

# Now process image
my ($d,$r,$s,@colours);
for my $y (0..($height-1)){
   for my $x (0..($width-1)){
      # See if IR channel says this is dust, and if so, replace with pixel above
      if($A[$x][$y]<0.01){
         $colours[0]=$R[$x][$y-1];
         $colours[1]=$G[$x][$y-1];
         $colours[2]=$B[$x][$y-1];
         $R[$x][$y]=$R[$x][$y-1];
         $G[$x][$y]=$G[$x][$y-1];
         $B[$x][$y]=$B[$x][$y-1];
         $out->SetPixel(x=>$x,y=>$y,color=>\@colours);
      }
   }
}

$out->write(filename=>'out.tif',compression=>'lzw');

The result looks like this, but I had to make it a JPEG just to fit on SO:

enter image description here

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • This is interesting. Maybe I will try to have a look at OpenCV's documentation and see if I can bring a bit more sophisticated algorithm into this... That should be more than enough for my needs. – retrography Dec 02 '14 at 22:35
  • 1
    If you change the line that sets `$colours[0]` and just do `$colours[0]=1;` you can immediately see, in Red, which pixels have been selected for de-dusting. – Mark Setchell Dec 02 '14 at 22:48
  • Mark or retrography, did you go any further with this? I am interested in pursuing this myself. Thanks! – Sol Arnu Mar 17 '15 at 10:57
  • I guess I was somewhat discouraged from goin any further and disappointed that it wasn't accepted as the answer as I felt it went quite a long way towards answering the question. I think a bicubic, or some other, interpolation would be the way to go for replacing dusty pixels. Please write it up if you further it and leave a note. – Mark Setchell Mar 17 '15 at 11:06
  • @MarkSetchell Sorry mark. A very busy last year PhD candidate here. Missed your comments. – retrography Aug 23 '15 at 20:05
1

I cannot comment, so I write an answer.

I suggest using G'Mic with the filter "inpaint".

You should load the image, take the IR image and convert it to b/w, then tell the filter inpaint to fill the areas marked in the IR image.

FarO
  • 161
  • 11
  • I tried to do so without much success. I think I had an issue compiling gmic on OS X, or something in that order. But I will go back to that soon to give it a second shot. Thanks for the suggestions! – retrography Jul 27 '15 at 18:11
  • I am actually trying to do it as well. When I use a mask obtained manually from the infrared image, then I apply -inpaint, the result is good (even if I haven't optimised its parameters). Right now I'm trying to make the process of defining a threshold automatic. How did you get the dust and scratch mask above, starting from the IR image you posted? What threshold have you used? – FarO Jul 27 '15 at 20:37
  • Sorry, I was out of town for a while. I don't really remember how I did it at the time. I have been trying in so many arbitrary ways to get this straight. My last conclusion, I remember was that the process will be scanner-dependent. I have a Photoshop action [here](https://github.com/retrography/scanning) That may help you go further. The repository also includes some trials and errors I have done with updating negfix8, and a scanning script I have developed (scaneg). Let me know if you make progress on the issue. – retrography Aug 23 '15 at 20:10
  • Proper answers should show code and an example. Your answer should have been just a comment. – fmw42 Jul 21 '19 at 18:15
0

OpenCV has a good algorithm for image inpaiting, which is basically what you were searching for. https://docs.opencv.org/3.3.1/df/d3d/tutorial_py_inpainting.html

If that will not help then only Neural Networks algorithms

neat nib
  • 48
  • 3
Andrey Nikishaev
  • 3,759
  • 5
  • 40
  • 55
  • Op says “it seems that OpenCV's in-paint method accept only 8-bit-per-channel images, while I must preserve the 16.” Also, suggesting that it’s either OpenCV or NN is rather short-sighted, there are millions of tools and millions of methods out there for inpainting. – Cris Luengo Jul 21 '19 at 13:42
  • Proper answers should show code and an example. Your answer should have been just a comment. – fmw42 Jul 21 '19 at 18:14