Você pode usar um algoritmo de pintura padrão. Esses algoritmos substituem os pixels marcados em uma imagem pelos valores de pixel que cercam esses pixels marcados. O desafio aqui é detectar a grade (meus testes parecem mostrar que não é uma grade completamente regular). Então, eu vim com esta solução:
from PIL import Image
import requests
from io import BytesIO
import cv2
url = "http://i.stack.imgur.com/Ahrnl.jpg"
response = requests.get(url)
img = Image.open(BytesIO(response.content))
plt.imshow(img)
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
plt.subplot(221)
plt.imshow(sX)
plt.subplot(222)
plt.imshow(sY)
plt.subplot(223)
# 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
plt.plot(eX)
plt.subplot(224)
eY = (sY**.2).sum(axis=1)
eY = np.roll(eY, -1)
plt.plot(eY)
mask = np.zeros(A2.shape[:2], dtype=np.uint8)
mask[eY>480,:] = 1
mask[:, eX>390] = 1
A2[mask.astype(bool),:] = 255
plt.figure()
plt.subplot(221)
plt.imshow(A)
plt.subplot(222)
plt.imshow((A2))
restored = cv2.inpaint(A, mask, 1, cv2.INPAINT_NS)
plt.subplot(223)
plt.imshow(restored)
A saída do programa é a seguinte:
Para detectar a grade, fiz uma solução rápida e suja. Pode ser melhorado bastante, mas mostra a ideia inicial. O fluxo geral é:
- detectar a grade
- crie uma máscara que descreva quais pixels estão corrompidos pela grade
- pintar os pixels corrompidos.
Para a pintura, usei a operação de pintura OpenCV . Para detectar a grade, realizei a detecção de arestas nas direções X e Y usando um filtro Sobel. Em seguida, adiciono todos os valores das arestas nas direções X e Y para encontrar picos, onde estão as linhas de grade. Depois, escolho os picos mais altos como as coordenadas nas quais as linhas da grade são estimadas. Não está funcionando perfeitamente (por exemplo, bordas fortes na imagem são falsamente detectadas como linhas de grade), mas mostra a ideia. Pode ser melhorada, por exemplo, na transformação de Hough para encontrar linhas, expulsar arestas muito fortes, etc.
Como alternativa, se a grade é realmente a mesma para todas as imagens, você pode executar a detecção da grade em conjunto para todas as imagens, o que produziria uma precisão muito melhor (basta fazer a técnica acima, mas antes de escolher os picos, resuma os resultados de todas as imagens). Mais detalhadamente, você calcularia o eX para todas as imagens e adicionaria todos esses eX em um único vetor. Esse vetor terá uma estrutura de pico muito mais clara e o limiar pode ser feito mais facilmente.