Gimp: Remove watermark lines from images

Every year a photographer visits our kindergarten and takes photos of every child, siblings and all the groups. You can then buy the photos of your own children.

The photos can be pre-viewed online, but they are water-marked with diagonal white lines to prevent you from simply downloading and printing the images:

Image with white watermark lines

Every year, we make a video of our children's group to document the progress they made, and how they changed during the year. At the beginning of the video we usually introduce the children with a photo and their name, so that we can still recognize them im 20 years.

The parents bought the portfolios of their children, and I could have went to each of them, scan the portrait image and use the scanned image in the video.

Alternatively, I could use the photos from the photographer's website if it was not for the white watermark lines that made them unusable. I simply had to fix them.

GIMP

GIMP is my preferred image manipulation program, and it has a plugin that is able to "heal" errors on images quite convincingly: gimp-resynthesizer. You can install it on Debian/Ubuntu via

$ apt-get install gimp-resynthesizer

The plugin provides a menu entry Filters -> Enhance -> Heal selection that fixes the selected area by filling it with a mixture of surrounding pixels.

To test it, I rotated the image by 45° to make the white lines horizontal so that they are easily selectable. Then I selected a part of the upper white line and applied the "Heal selection" with the following settings:

Context sample width
10
Sample from
All around
Filling order
Random

Test image before
Before healing
Test image after healing a part of the line
After healing a part of the line

Automation

Now that I knew that healing would work, the task was to automate it - because I did not want to manually select 19 lines in an image, and repeat that 15 times.

GIMP supports plugins and has a scripting console, Script-Fu. I do not know the scheme language, so I opted to use the Python-Fu console.

You can open it with Tools > Python-Fu > Console.

Image

At first you have to get the image you'll be working with. I simply used the first image the GIMP has open:

image = gimp.image_list()[0];

Diagonal selection

When clicking the "Browse" in the console window, the "Python Procedure Browser" window appears. You can then search for "select" and find gimp-image-select-rectangle and others like gimp-image-select-polygon.

Making a rectangular selection is easy, but I failed to find out how to rotate the selection by 45 degrees. Instead I used the polygon selection method:

pdb.gimp_image_select_polygon(
    image,
    2, #replace previous selection
    8, #8 coordinates in the following array
    [
        100, 0,
        105, 0,
        5, 100,
        0, 100
   ]
)

This code makes a selection equivalent to a rectangle rotated by 45 degrees, from the top right to the bottom left.

Healing

Now the hard part is over; we only have to let the plugin heal the selection.

python-fu-heal-selection takes the image as first, and a Drawable as second parameter. In this case we can use the first layer (image.layers[0]) or the active drawable:

pdb.python_fu_heal_selection(image, image.active_drawable, 10, 0, 0)

Use Python's dir function to inspect objects:

>>> dir(image)
['ID', '__class__', '__cmp__', '__delattr__', '__doc__', '__format__', ...

Repeat

I didn't want to do this manually for all the 19 lines on an image, so I counted the space between the lines - always 90 pixels. A range call made it easy:

>>> for i in range(0,19): print i
0
1
2
...

Final script

This is the final code to heal a diagonal line. Apart from initx (horizontal coordinate of first line on the top), nothing needs to be changed:

initx = 85
selwidth = 5
selheight = 1000
image = gimp.image_list()[0]
for i in range(19):
    posx=initx + i * 90
    pdb.gimp_image_select_polygon(
        image, 2, 8,
        [
            posx, 0,
            posx + selwidth, 0,
            posx + selwidth - selheight, selheight,
            posx - selheight, selheight
        ]
    )
    pdb.python_fu_heal_selection(image, image.layers[0], 10, 0, 0)
    pdb.gimp_selection_none(image)

I combined this all into one line so that I could repeat it by pressing up and enter on the keyboard:

initx=85
for i in range(19): selwidth=5; selheight=1000; image = gimp.image_list()[0];posx=initx+i*90; pdb.gimp_image_select_polygon(image, 2, 8, [posx, 0, posx+selwidth, 0, posx+selwidth-selheight, selheight, posx-selheight, selheight]); pdb.python_fu_heal_selection(image, image.layers[0], 10, 0, 0); pdb.gimp_selection_none(image)

Result

Image with no watermark lines anymore

Written by Christian Weiske.

Comments? Please send an e-mail.