Edit2: I downloaded the provided images of grey scale scans, and played with them, I semi-automatically aligned at rotated the first two image.
img = io.imread("scans/scan078.tif")
img2 = io.imread("scans/scan079.tif")
imgr = transform.rotate(img,angle = -0.78)
imgr2 = transform.rotate(img2,angle = -0.805)
tr1=transform.rescale(imgr[:-10,:-6],0.1)[20:-20,20:-20]
tr2=transform.rescale(imgr2[10:,6:],0.1)[20:-20,20:-20]
This reads rotates each aligns and crops, downsamples 10x and crops to get rid of edges which may have artifacts. This gives a Maximal difference of less than 6% per pixel value. Which is pretty good. However this 6% diff can easily be around any cut-off we choose so even quantizing aggressively doesn't give 0 errors.
bin1 = tr1> 0.5
bin2 = tr2> 0.5
This gave a difference in 103 bits out of 27248 bits or 0.37% These errors appear to be reasonably spread out. This aggressive resizing and quantizing looses a lot of information but we probably still have enough. This is what the image looks like:
The errors are fairly well spread out(and we can always apply a fixed permutation or use larger symbols if needed). So now we can apply any error correction step (e.g Reed solomon) we will just take the decoding step (didn't actually do this) and we should get the same output from either image with high likelyhood and still have ~20K bits.
If we down scale 5x instead of 10x we get 816 differing bits. but get 4x as many bits, at 0.6% difference. Can play with this and find optimum.
We can also probably do better at the quantization step and preserve more information reliably. The aggressive quantization I used will work only for reasonably balanced photos, an over exposed picture will come out all a single value. We could add preprocessing to handle this scenario.