In [1]:
# importa a biblioteca do opencv
import cv2
def read_image(filename):
# carrega a imagem colorida e transforma ela em uma matriz do numpy
image = cv2.imread(filename)
# calcula o pixel com menor intensidade
# inicia a cor com o maior valor possivel
color = 255 * 3
# pega as dimensoes da imagem
(rows, cols, depth) = image.shape
# varre todos os pixels
for row in range(rows):
for col in range(cols):
# acessa um pixel da imagem
pixel = image[row][col]
(r, g, b) = pixel.tolist()
if color > (r + g + b):
color = r + g + b
for row in range(rows):
for col in range(cols):
pixel = image[row][col]
(r, g, b) = pixel.tolist()
c = (r + g + b)
# pinta de branco o que nao for letra
if c != color:
image[row][col] = (255, 255, 255)
# pinta de preto o que for letra
else:
image[row][col] = (0, 0, 0)
return image
In [2]:
def recursive_bounding(image, row, col, letter_color):
min_x = col
min_y = row
max_x = col
max_y = row
(rows, cols, depth) = image.shape
for r in range( max(0, row - 1), min(row + 2, rows)):
for c in range(max(0, col - 1), min(col + 2, cols)):
if r == row and c == col:
continue
(r1, g1, b1) = image[r][c].tolist()
t = (r1 + g1 + b1)
# vizinho nao pertence a letra, ignora ele
if t != letter_color:
continue
# apaga esse pixel
# nao salvamos ele como branco pq precisaremos dele
# no proximo processamento
image[r][c] = (20, 20, 20)
points = recursive_bounding(image, r, c, letter_color)
(min_x1, max_x1, min_y1, max_y1) = points;
min_x = min(min_x, min_x1, c)
max_x = max(max_x, max_x1, c)
min_y = min(min_y, min_y1, r)
max_y = max(max_y, max_y1, r)
return (min_x, max_x, min_y, max_y)
In [3]:
def compute_boxes(image):
boxes = []
letter_color = 0
(rows, cols, depth) = image.shape
for row in range(rows):
for col in range(cols):
pixel = image[row][col]
(r, g, b) = pixel.tolist();
t = (r + g + b)
# nao eh letra, ignora o pixel
if t != letter_color:
continue
# calcula a bounding box dessa letra
box = recursive_bounding(image, row, col, letter_color)
# salva o bounding box numa lista de boxes
boxes.append(box)
boxes.sort()
return boxes
In [4]:
def cut_boxes(image, boxes):
letters = []
for box in boxes:
(col0, col1, row0, row1) = box
letter = image[row0:row1 + 1, col0:col1 + 1]
letters.append(letter)
return letters
In [5]:
def break_captcha(letters, templates):
captcha = ''
unrec = 0
for letter in letters:
(rows, cols, depth) = letter.shape
best_error = rows * cols
best_letter = ''
# copia a imagem, transformando de RGB para tons de cinza
gray = cv2.cvtColor(letter, cv2.COLOR_RGB2GRAY)
# binariza a imagem
(_, gray) = cv2.threshold(gray, 240, 255, cv2.THRESH_BINARY);
for letter in templates.keys():
for template in templates[letter]:
# se a imagem for de tamanho diferente do template
# ignora o template
if template.shape != gray.shape:
continue
xor = template ^ gray
errors = xor.sum()
if errors < best_error:
best_error = errors
best_letter = letter
# match perfeito
if errors == 0:
break;
if best_error == 0:
break;
# nao casou exatamente com nenhuma letra
# provavelmente eh uma nova letra
if best_error != 0:
cv2.imwrite("image_%d.png" % (unrec), gray)
unrec = unrec + 1
captcha = captcha + best_letter
return captcha
In [6]:
import os
import glob
import collections
def load_templates():
# filtra os arquivos .png
files = glob.glob('templates/*.png')
# dicionario com as imagens
# chave = letra
# valor = lista de imagem
templates = collections.defaultdict(list)
for file in files:
f = os.path.basename(file)
# o primeiro caracter do nome do arquivo eh a letra
# correspondente
letter = f[0]
# carrega a imagem
img = cv2.imread(file)
# muda a imagem pra tons de cinza
img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# binariza a imagem
(_, img) = cv2.threshold(img, 245, 255, cv2.THRESH_BINARY)
# uma letra pode ter varios templates
templates[letter].append(img)
return templates
In [7]:
%matplotlib inline
import matplotlib.pyplot as plt
In [8]:
file = 'a.png'
Imagem Original
In [9]:
plt.imshow(cv2.imread(file))
Out[9]:
Imagem Limpa e Binarizada
In [10]:
image = read_image(file)
plt.imshow(image)
Out[10]:
Coordenadas das letras
In [11]:
boxes = compute_boxes(image)
boxes
Out[11]:
Letras recortadas
In [12]:
letters = cut_boxes(image, boxes)
In [13]:
plt.imshow(letters[0], cmap='gray')
Out[13]:
In [14]:
plt.imshow(letters[1], cmap='gray')
Out[14]:
In [15]:
plt.imshow(letters[2], cmap='gray')
Out[15]:
In [16]:
plt.imshow(letters[3], cmap='gray')
Out[16]:
Carrega os templates
In [17]:
templates = load_templates()
Quebra o captcha
In [18]:
break_captcha(letters, templates)
Out[18]:
In [ ]: