You can use a standard inpainting algorithm. These algorithms replace marked pixels in an image with the pixel values that surround these marked pixels. The challenge here is to detect the grid (my tests seem to show that it is not a completely regular grid). So, I came up with this solution:
from PIL import Image
from io import BytesIO
url = "http://i.stack.imgur.com/Ahrnl.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))
A = np.array(img)
A2 = A.copy()
A_gray = cv2.cvtColor(A, cv2.COLOR_RGB2GRAY)
# Do some rough edge detection to find the grid
sX = cv2.Sobel(A_gray, cv2.CV_64F, 1, 0, ksize=3)
sY = cv2.Sobel(A_gray, cv2.CV_64F, 0, 1, ksize=3)
sX[sX<0] = 0
sY[sY<0] = 0
# the sum operation projects the edges to the X or Y-axis.
# The 0.2 damps the high peaks a little
eX = (sX**.2).sum(axis=0)
eX = np.roll(eX, -1) # correct for the 1-pixel offset due to Sobel filtering
eY = (sY**.2).sum(axis=1)
eY = np.roll(eY, -1)
mask = np.zeros(A2.shape[:2], dtype=np.uint8)
mask[eY>480,:] = 1
mask[:, eX>390] = 1
A2[mask.astype(bool),:] = 255
restored = cv2.inpaint(A, mask, 1, cv2.INPAINT_NS)
The program output is as follows:
To detect the grid I did a quick-and-dirty solution. It can be improved a lot, but it shows the initial idea. The general flow is:
- detect the grid
- create a mask that describes which pixels are corrupted by the grid
- inpaint the corrupted pixels.
For inpainting I used OpenCV inpaint operation. For detecting the grid, I performed edge detection in X and Y direction using a Sobel filter. Then I add all edge values in the X-direction and Y-direction to find peaks, where the grid lines are. Then, I choose the highest peaks as the coordinates where the grid lines are estimated. It's not working perfect (e.g. strong edges in the image are falsely detected as grid lines), but it shows the idea. It can be improved by e.g. Hough transformation to find lines, kicking out very strong edges etc.
Alternatively, if the grid is really the same for all images, then you can perform the grid detection jointly for all images, which would yield a much better accuracy (just do the technique above, but before choosing the peaks, sum up the results from all pictures). In more detail, you would calculate eX for all images and add all these eX together into a single vector. This vector will have a much clearer peak structure and the thresholding can be done easier.