Over on genealogy.SE, I proposed a method of manipulating images to make "bleed through" less visible and the handwriting on the correct side of the page more legible.

Here are the original images:

enter image description here

enter image description here

The idea is to make a mirror image of the other page, and then remove things that are dark on the flipped page and lighter on the target page, and similarly keep things that are darker on the target page than the flipped page. Here's the flipped page:

page17cropflip = ImageReflect[page17crop, Left]

enter image description here

Here was the set of commands that worked tolerably well in this case (it looks better at full size):

With[{brightness = -0.3`, contrast = 0, final = 0.903`, 
  highbleed = 0.159`, lowbleed = 0.221`, method = "Cluster"}, 
    ImageAdd[Blur[page18crop, 3], 
     ImageClip[page17cropflip, {lowbleed, lowbleed + highbleed}]], {0,
      final}], {contrast, brightness}], Method -> method]]

enter image description here

But I needed to crop the images by hand (I used ImageDifference to help line it up) so that the bleeding through text lined up with the actual text on the image of the facing page. Is there a way to automate this?

  • $\begingroup$ I'm also interested in improvements to my method. I think it could be better. $\endgroup$
    – Verbeia
    Jul 29, 2014 at 10:35
  • 1
    $\begingroup$ Interesting question. I've done this specific operation by hand before (for full color images rather than text) and I think subtle distortions in the scans will require compensation in the alignment, especially with details as fine as text. I mean that a simple translation will not suffice, and you will need to "warp" the background image to produce a perfect alignment. Many of the image processing tools in v10 are new to me so I'm not sure where to start. Is there a function that is suitable for localized warping? $\endgroup$
    – Mr.Wizard
    Jul 30, 2014 at 1:38
  • $\begingroup$ @Mr.Wizard: ImageTransformation can wrap. If you have per-pixel offsets (as you would have with many optical flow or non-parametric registration algorithms), this question might be useful: mathematica.stackexchange.com/questions/31274/… $\endgroup$ Jul 30, 2014 at 5:33
  • $\begingroup$ If this weren't a Mathematica-specific site I would suggest a simple manual technique using two minutes of Photoshop: i.sstatic.net/5Lm3z.jpg $\endgroup$
    – user484
    Jul 30, 2014 at 8:03
  • $\begingroup$ @Mr.Wizard, I made an attempt at doing what you describe by doing correlations on smaller sub-images to get a local translation which varies across the image, then interpolating that data and using ImageForwardTransformation to apply the warp. It didn't work very well though. $\endgroup$ Jul 30, 2014 at 8:04

1 Answer 1


Here's a first (very simple!) attempt:

{p1, p2} = 
     "Grayscale"] & /@ {"https://i.sstatic.net/2hf7N.jpg", 

A simple CorrelationDistance gives a surprisingly good estimate for the shift:

corr = ImageCorrelate[p1, ImageReflect[p2, Left -> Right], 

enter image description here

shift = PixelValuePositions[corr, Min[ImageData[corr]]][[1]] - 
shiftedImgs = {p1, 
   ImageTransformation[ImageReflect[p2, Left -> Right], # - shift &, 
    PlotRange -> Full, DataRange -> Full]};

enter image description here

Now, I remember vaguely that PCA was a very cheap way to do blind source separation:

{u, s, v} = 
 SingularValueDecomposition[# - Mean[#] & /@ 
    Flatten /@ ImageData /@ shiftedImgs, 2];
Image[Rescale[Partition[v[[All, 2]], 1000]]]

enter image description here

It seems that the "positive" pixels are one page, the "negative" pixels are the other one. (But I'm probably doing it wrong. I really have to look up how this works again.)

  Function[{sign, mirror},
    Image[1 - 
      Rescale[Clip[sign*Partition[v[[All, 2]], 1000], {0, \[Infinity]}]], 
     ImageSize -> All], mirror]],
   {1, -1},
   {Left -> Left, Left -> Right}

Here's a before/after comparison: enter image description here

Like I said, not perfect. But I think blind source separation techniques really are the way to go here. Both for separating the signal, as well as for choosing a good "correlation measure" to determine the shift between the images. That's why I posted this answer.

  • $\begingroup$ Thanks nikie, this is excellent, but the real challenge is stripping the bleedthrough of page 17 on page 18. I'm away from my Mathematica machine at the moment, so is there any chance you could show the unflipped version of the second-last image? $\endgroup$
    – Verbeia
    Jul 29, 2014 at 22:45

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.