Sunteți pe pagina 1din 41

UNIVERSIDAD NACIONAL DE INGENIERIA

Facultad de Ingeniera Industrial y de Sistemas

INTELIGENCIA ARTIFICIAL
ST- 414

SEGUNDO ENTREGABLE

Integrantes:
Ordoes Vallenas, Antonio
Velasque Espinoza, Elvis
Miranda Romero, Arturo
Ramos Ramirez, Atenas

Profesor: Samuel Oporto


Fecha: 25/10/2017

2017-II
Contenido
1. RESUMEN ........................................................................................................................... 3
2. INTRODUCCIN ................................................................................................................ 4
3. PROBLEMA ......................................................................................................................... 5
4. MODELO DE SOLUCIN ................................................................................................. 6
4.1 PASOS ......................................................................................................................... 7
4.1.1 Preparacin de CAPTCHAS ............................................................................. 7
4.1.2 Creacin de Dataset ........................................................................................ 23
4.1.3 Aprendizaje del modelo ................................................................................... 25
5 CONCLUSIONES ............................................................................................................. 28
6 RECOMENDACIONES.................................................................................................... 28
7 BIBLIOGRAFIA ................................................................................................................. 28
8 ANEXO: PROGRAMAS FUENTE.................................................................................. 29
ANEXO 1: LIBRERA PARA LEER O BORRAR ARCHIVOS ...................................................... 29
ANEXO 2: PREPARACIN DE LOS CAPTCHAS....................................................................... 31
ANEXO 3: PLANTEAMIENTO, DESARROLLO Y EVALUACION DEL MODELO ....................... 39
1. RESUMEN
En el presente trabajo le mostraremos al lector el mtodo que hemos
desarrollado y utilizado para predecir que letra es la que est dentro de la imagen
cortada de un captcha a partir de un entrenamiento realizado obteniendo una
eficiencia del 81.6%.
El mtodo desarrollado en este trabajo consiste en descargar una cantidad de
aproximadamente 10 000 imgenes de captchas, despus, de forma manual
colocar el nombre de cada imagen con el valor del captcha. Lo que se busca
despus de esto es eliminar la lnea existente que atraviesa a todas las letras de
los captchas, cuando ya se llega a este punto se busca segmentar la imagen del
captcha teniendo como resultado 5 imgenes que contiene cada uno de los
caracteres de su respectivo captcha y como nombre el valor del carcter junto
con el nombre del todo el captcha. De estas imgenes se utilizan la mitad (5 000
captchas) para entrenar al modelo, es decir, que el modelo aprenda a
reconocer cada letra que hay en la imagen y despus con la otra mitad predecir
cul es la letra que est en la imagen.
Se debe tomar en cuenta que en este punto del trabajo solo se predice una letra
por separado y no todo el captcha en su totalidad, las 5 cinco letras en una sola
imagen, esto formar parte de los prximos entregables y trabajos que se van a
ir desarrollando.
2. INTRODUCCIN
En la actualidad la Inteligencia Artificial va tomando forma en los trabajos
realizados o cada vez la idea de tener un programa que aprende por su propia
cuenta tiene ms sentido y se busca implementarlo como mtodo de solucin a
problemas complejos. IBM lanz Watson que es un software de inteligencia
artificial que ha revolucionado la forma como se analiza la informacin y la
relacin que hay con sus usuarios.
A continuacin, en el presente trabajo detallaremos como hemos implementado
nuestros conocimientos de Inteligencia Artificial para crear un modelo que
permita predecir que letra es la que est en una imagen de una letra de un
captcha.
El lector tendr la oportunidad de ver los pasos a seguir, la fuente de donde
sacamos la informacin, ideas planteadas, etc. que hemos desarrollado para la
solucin del problema.
3. PROBLEMA
Disear, construir, verificar y validar un procedimiento para extraer informacin
desde una pgina web que est protegida por un captcha y registrar la
informacin leda en una base de datos, ente caso particular la pgina que se
usara es:

http://apps2.mef.gob.pe/consulta-vfp-webapp/consultaExpediente.jspx

Para ello se tiene como objetivos:


Recolectar una base de datos de alrededor 10000 captchas, asignando
su nombre manualmente.
Preparar los captchas, redimensionando, binarizando, eliminando la lnea
y segmentando para su posterior procesamiento.
Disear un modelo que prediga con el mayor grado de exactitud el
contenido del captcha.
4. MODELO DE SOLUCIN
Con la finalidad de obtener un mtodo que logre predecir las letras existentes
dentro de la imagen de una letra del captcha se ha elaborado un el siguiente
modelo el cual contiene todos los pasos que se han sido desarrollados

FUENTE: MODELO DE SOLUCIN DESARROLLADO


4.1 PASOS
4.1.1 Preparacin de CAPTCHAS
En los siguientes puntos se detallarn cules son los procedimientos que se han
ejecutado para convertir las imgenes descargadas de los captchas a un
dataset. Para desarrollar este mtodo de solucin se ha requerido las siguientes
libreras para el manejo de las imgenes:
from PIL import Image, ImageChops
import os.path
import numpy as np
import cv2
import matplotlib.pyplot as plt
import operator
import os
import time
import leer #libreria nuestra

LIBRERAS DEFINICIN
Aade la capacidad del procesamiento de imgenes con
PIL
Python.
Implementa algunas funciones tiles para el manejo de
Os.path
Rutas y abrir y cerrar archivos
Es la principal librera para la ciencia de la informacin
Numpy
usada con Python.
Opencv Es un procesador de imgenes.
Es un conjunto de funciones que se asemejan a MATLAB
Matplotlib.pyplot
para el manejo de imgenes.
Exporta un grupo de funciones matemticas
Operator
correspondientes de Python.
El mdulo Os permite el acceso de funciones
Os
dependientes del sistema operativo.
Time Proporciona varias funciones relacionadas con el tiempo.
Leer Creada para manejo de archivos.
a. Lectura del captcha
Se cuenta con una base de datos de 10 000 captchas, de los cuales se ha usado
5 000 para el entrenamiento del modelo. Para el comienzo obtener todas las
imgenes se realiza un for y el uso del procedimiento listdir_recurd.

Cdigo:
for k in leer.listdir_recurd([],' /img', /img', []):
print(k)
leer.borraraux()
I = Image.open("img/"+k)

FUENTE: CAPTCHAS DESCARGADOS PARA LEER


b. Conversin a gris
Con la finalidad de manejar solo una escala de colores se busca color a todas
las imgenes en escala de grises y se guardan estas en una nueva carpeta
llamada gris.

FUENTE: CONVERSIN DE IMAGEN A IMAGEN EN GRIS

Funcin:
I.convert("L")

Cdigo:
G = I.convert("L")
G.save("gris/"+k)

FUENTE: IMGENES CONVERTIDAS A ESCALA DE GRISES

c. Obtener lnea
Existe una lnea que atraviesa todas o casi todas las letras de un captcha por
ende con la finalidad de eliminarla se busca identifica los pixeles que conforman
esta lnea y se guarda como otra imagen en la carpeta llamada lnea. Para
identificar cules son los pixeles que conforman la lnea se estableci que estos
pixeles eran los nicos que se tenan un valor menor a 40 en la escala de gris.
Por lo tanto, se realiz una binarizacin con umbral 40.

FUENTE: PROCEDIMIENTO DE OBTENCIN DE LNEA

Funcin:
quitar_linea(A,LN)

Cdigo:
LN=binarizacion(G, 40)
LN.save("linea/"+k)
FUENTE: LNEAS OBTENIDASDE LOS CAPTCHAS

d. Binarizacin de la imagen
La Binarizacin consiste en que con un cierto nivel de umbral se llega a quitar el
fondo en las imgenes y ciertas manchas, despus de esto se guardar las
imgenes creadas en la carpeta binarizada. Para cada columna de pixeles se
hall un promedio de escala de gris, usando este promedio como umbral en
dicha columna para realizar la binarizacin.

FUENTE: PROCEDIMIENTO DE BINARIZACIN DE LAS IMGENES


Cdigo binarizar imagen para quitar el color de fondo de la imagen:
w, h = G.size
pix = G.load()
output = Image.new("L", (w, h))
out_pix = output.load()
for i in range(w):
sum=0
for a in range(h):
sum=sum+pix[i,a]
p=sum/h
p=int(p)
for j in range(h):
if pix[i, j] >= p: out_pix[i, j] = 255
else: out_pix[i, j] = 0
output.save("binarizada/"+k)

FUENTE: IMGENES BINARIZADAS CON MANCHAS

Como se ha podido notar en el proceso de Binarizacin se crean dos manchas


en las esquinas superiores de las imgenes de los captchas, se ejecuta el
siguiente cdigo con la finalidad de borrar esas manchas y guardarlo en la
carpeta sinmancha.
Cdigo quitar mancha

A=quitar_mancha(output)
A.save("sinmancha/"+k)

FUENTE: CAPTCHAS SIN MANCHAS

e. Quitar lnea
Ya que se requiere obtener las imgenes de cada una de las letras de los
captchas se debe eliminar la lnea que atraviesa a todas las letras, esto se da a
partir de la imagen binarizada sin mancha junto con la imagen de la lnea.
Cuando se elimina la lnea de los captchas se guardan estas imgenes en la
carpeta sinLnea.

FUENTE: PROCEDIMIENTO DE ELIMINAR LA LNEA DEL CAPTCHA

Cdigo quitar lnea:


C=quitar_linea(A,LN)
C.save("sinlinea/"+k)

FUENTE: IMGENES SIN LNEA

f. Invertir imagen
Con esta ltima imagen se invierten las imgenes ya que de preferencia se
obtiene un mejor resultado cuando se trabaja con las letras en color blanco y un
fondo negro.

Cdigo invertir colores de la imagen


out = ImageChops.invert(C)
out.save("invertida/"+k)

FUENTE: IMGENES INVERTIDAS Y SIN LNE


g. Cortar imagen
Antes de proceder a la segmentacin de la imagen se cortan mrgenes de los
captchas para dejar nicamente donde haya letras.

Funcin:
def corte(imagen,m,n):
w1, h1 = imagen.size #se obtiene el largo y ancho de la imagen
c1=pixels_total_horizontal(imagen) #total pixeles horizontal
for i1 in range(w1):
if c1[i1]>m:
T=imagen.crop((i1-1,0,w1,h1))
break
w2, h2 = T.size
c2=pixels_total_horizontal(T)
for i2 in range(w2):
if c2[w2-i2-1]>m:
P=T.crop((0,0,w2-i2,h2))
break
w3, h3 = P.size
c3=pixels_total_vertical(P)
for i3 in range(h3):
if c3[i3]>n:
Q=P.crop((0,i3-1,w3,h3))
break
w4, h4 = Q.size
c4=pixels_total_vertical(Q)
for i4 in range(h4):
if c4[h4-i4-1]>n:
R=Q.crop((0,0,w4,h4-i4))
break
return R

Cdigo:
Ct=corte(out,2,2)
Ct.save("cortada/"+k)

h. Segmentacin de la imagen

Para la segmentacin de captchas el objetivo principal es encontrar los 4 puntos


de corte a travs de los cuales se segmentar la imagen. Para el computador,
no existe una manera 100% efectiva para reconocer exactamente los puntos por
los que los captchas deben ser segmentados, el algoritmo se utilizara se basara
en 3 parmetros para buscar puntos de segmentacin en una imagen, los cuales
se calcularan directamente del vector de total de pixeles horizontales. Este vector
contiene el total de pixeles blancos existentes en una columna de pixeles.

Imagen binarizada Vector de total de pixeles


Calculo de total de pixeles horizontales:
horizontal
[0, 2, 12, 20, 23 , 23, 2, 1,,]
Cdigo:

def pixels_total_vertical(imagen):
w, h = imagen.size
pix = imagen.load()
histog=h*[0]
for j in range(h):
c=0
for i in range(w):
if pix[i,j]==255:
c=c+1
histog[j]=c
return histog

A partir del vector de total de pixeles horizontales se buscan puntos de corte


basndose en 3 parmetros: mnimo de pixeles en la columna, mnimo de ancho
del segmento y mnimo de pixeles en el segmento. El primer parmetro
determina cuantos pixeles como mximo puede tener la columna por donde se
va a realizar el corte, esto nos permite identificar posibles espacios entre letras.
El segundo determina cual es el mnimo nmero de pixeles de ancho que pueden
tener los segmentos resultantes tras el corte, esto nos evita obtener segmentos
demasiado angostos en donde no entre una letra. El ltimo parmetro indica cual
es el total de pixeles que debe tener como mnimo un segmento, esto nos evita
realizar cortes en segmentos que sean casi totalmente negros, donde no hayan
pixeles blancos suficientes para que exista alguna letra. Adems, la funcin
recibe un parmetro adicional que limita el nmero de veces que puede dividir
una imagen para evitar dividir el Captcha en ms de 5 segmentos. Una vez
encontrados los puntos de corte se realiza el corte y se obtienen de 2 a 5 posibles
segmentos resultantes. Todas las imgenes resultantes se almacenan en la
carpeta segmentada con el siguiente formato: n.captcha

1.2n6d7
Imagen binarizada

Vector de pixeles : Segmentacin


[0, 2, 12, 20, 23 , 23, 2, 1,,] inicial: 2.2n6d7

Mnimo pixeles: 0
Mnimo Longitud: 25
Mnimo pixeles segmento: 90 Total de segmentos: 2
Numero de segmentos=5
Cdigo:

def segmentacion(imagen,separador,nsegmentos,lseg,mintotpix):
his=pixels_total_horizontal(imagen)
print(his)
w, h = imagen.size
letter=False
foundletter=False
u=0
t=0
p=0
for i in range(w):
if letter==True:
if his[i]<=separador or i==w-1:
if i== w-1: print (t)
if t>lseg:
n2=i
foundletter=True
print("e")
else:
t=t+1
else:
t=t+1
else:
if his[i]>separador or i==0:
letter=True
n1=i
t=1

if foundletter==True:
im = imagen.crop((n1, 0, n2, h))
print(conteo_pixels_blanco(im))
if conteo_pixels_blanco(im)>mintotpix:
u=u+1
print(u)
if u==nsegmentos:
im = imagen.crop((n1, 0, w, h))
im.save(str(nsegmentos)+".jpg")
im.close()
break
elif u<nsegmentos:
leer.borrarauxexp(str(u)+"jpg")
im.save(str(u)+".jpg")
im.close()
p=n1
foundletter=False
letter=False

if u<nsegmentos:
im1 = imagen.crop((p, 0, w, h))
im1.save(str(u)+".jpg")
im1.close()

return u
Como se observa, en el ejemplo anterior, un Captcha al pasar por el cdigo de
segmentacin no se sabe cuntas veces se va a segmentar, y no se puede
garantizar que este se halla segmentado en 5 partes. Para seguir encontrando
puntos de corte y segmentar los captchas se aplica el mismo algoritmo en los
segmentos resultantes buscando encontrar los 4 puntos de corte y as obtener
los 5 captchas. Para esto se utiliza lee el total de segmentos en la carpeta, se
valida que no sean 5 segmentos, se buscan puntos de corte en los segmentos
existentes reduciendo la exigencia de los parmetros. Una vez encontrado los
puntos de corte se renombran los captchas posteriores al Captcha que se ha
segmentado aumentando el nmero en su nombre para luego eliminar la imagen
segmentada y reemplazarla por lo los captchas resultantes. Durante cada intento
de segmentacin se actualiza el nmero de segmentos c que se tienen.

Imgenes binarizada
1.2n6d7

1.2n6d7
2.2n6d7

2.2n6d7
Segmentacin: 3.2n6d7
Nuevos parmetro:
Mnimo pixeles: 2
Mnimo Longitud: 20 4.2n6d7
Mnimo pixeles segmento:85 Total de segmentos: 4
Numero de segmentos=6-c

Cdigo:

def segmentar(minpix,nseg,Lminseg,k,mintotpix):
s=segmentada/
leer.borraraux()
c=leer.total_arch(s,k)
print(c)
if c<5:
for i in range(c):
im1=Image.open(s+str(i+1)+"."+str(k))
m=segmentacion(im1,minpix,nseg,Lminseg,mintotpix)
im1.close()
print(m,n,c)
if m>1 :
for r in range(c,i+1,-1):
print(r)
os.rename(s+str(r)+"."+str(k),s+str(r+m-1)+"."+str(k))

os.remove(s+str(i+1)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg",s+str(i+1+s)+"."+str(k))
break
leer.borraraux()
Para obtener 5 segmentos en la mayora de captchas es necesario llamar varias
veces la misma funcin reduciendo la exigencia de los parmetros a utilizar en
la bsqueda de los puntos de corte. Mientras la segmentacin se realiza con
parmetros ms exigentes menor riesgo de cortar en un punto indebido se
tendr, pero ser ms complicado que identifique un punto de corte.

segmentar(0,6-n,23,k,80)
segmentar(1,6-c,23,k,85)
segmentar(0,6-n,20,k,85)
segmentar(1,6-c,22,k,85)
segmentar(2,6-c,25,k,85)
segmentar(2,6-c,20,k,70)
segmentar(3,6-c,20,k,80)
segmentar(3,6-c,20,k,70)
segmentar(5,6-c,20,k,70)
segmentar(6,6-c,20,k,70)
segmentarforzado(k)

Si bien la mayora de captchas resultan segmentados bajo esta funcin, existen


casos excepcionales los cuales se dificulta la segmentacin lo cuales
normalmente estn relacionados a imgenes en los cuales las letras estn muy
juntas o muy inclinadas.
Por este motivo, al final del cdigo se llama a la funcin segmentarforzado(k).
Dicha funcin cumple el rol de segmentar en 2 partes el Captcha ms ancho de
los que ya se tienen. El punto de corte es por defecto el mnimo de pixeles que
se puedan encontrar en el tercio central de la imagen. El mnimo de longitud es
un tercio del ancho del segmento y no se considera un mnimo de pixeles. De
esta forma buscamos obtener los puntos de corte faltantes, aunque se puede
cometer el error de segmentar en un punto errneo.

1.2n6d7
1.2n6d7

2.2n6d7
2.2n6d7
3.2n6d7
3.2n6d7 segmentarforzad
o:
4.2n6d7
4.2n6d7

Total de segmentos: 4 5.2n6d7

Total de segmentos: 5
Cdigo:
def segmentarforzado(k):
s="segmentada/"
c=leer.total_arch("C:/Users/Antonio/Desktop/ia.trabajo/segmentada",k)
print(c)
Lmax=0
p=0

if c<5:
for i in range(c):
im1=Image.open("segmentada/"+str(i+1)+"."+str(k))
ancho, alt=im1.size
im1.close()
if ancho>Lmax:
Lmax=ancho
p=i+1
im1=Image.open("segmentada/"+str(p)+"."+str(k))
his=pixels_total_horizontal(im1)
minpix=100
for i in range(int(round(Lmax/3.0,0))+1,int(2.0*round(Lmax/3.0,0))):
if his[i]<minpix:
minpix=his[i]
print(minpix,Lmax,p,"sd")
im1.close()
im1=Image.open("segmentada/"+str(p)+"."+str(k))
m=segmentacion(im1,minpix,2,round(Lmax/3),0)
im1.close()
if m==2 :
for r in range(c,p,-1):
print(r)
os.rename(s+str(r)+"."+str(k), "segmentada/"+str(r+1)+"."+str(k))
os.remove("segmentada/"+str(p)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg", "segmentada/"+str(p+s)+"."+str(k))
leer.borraraux()

Finalmente se mueven los captchas de la carpeta segmentada a la carpeta


correspondiente en alfabeto centrado y se modifica su nombre agregando a la
imagen al inicio un identificador que carcter se supone que es la imagen.
El formato con el que se guarda el el segmento de captcha es:
l.n.captcha.jpg
Donde:
l: Letra que debera
n: Posicion de la letra en el captcha
captcha: Nombre del captcha del que proviene el segmento.
Ubicacin/nombre: Ubicacin/nombre:
segmentada/1.2n6d7.jpg alfabeto/2/2.0.2n6d7.jpg
segmentada/2.2n6d7.jpg Reubicar y alfabeto/n/n.1.2n6d7.jpg
segmentada/3.2n6d7.jpg renombrar alfabeto/6/6.2.2n6d7.jpg
segmentada/4.2n6d7.jpg alfabeto/d/d.3.2n6d7.jpg
segmentada/5.2n6d7.jpg alfabeto/7/7.4.2n6d7.jpg

Cdigo:
for i in range(5):
letra=k[i]
if os.path.exists("alfabeto/"+str(letra)+"/"+str(letra)+"."+str(i)+"."+str(k))==0:
os.rename("segmentada/"+str(i+1)+"."+str(k), "alfabeto/"+str(letra)+"/"+str(letra)+"."+str(i)+"."+str(k))
os.remove("img/"+str(k))

e. Centrar captchas

El objetivo de este procedimiento es uniformizar el tamao de todos los


segmentos de captchas que se obtuvieron en paso anterior y procurar que el
Captcha quede centrado en la nueva imagen. El tamao de cada captcha
(52x52 px) se determin en base al tamao de los segmentos resultantes ms
anchos que se encontraron.

Captchas no uniformes Captchas de los mismos


ni centrados Uniformar tamao y tamaos y centrados
centrar
Cdigo:
maxancho=0
for letra in os.listdir("alfabeto/"):
for f in os.listdir("alfabeto/"+letra+"/"):
print(f)
im1=Image.open("alfabeto/"+letra+"/"+f)
if ancho<53:
im2=Image.new("L",(52,52))
im2_pix = im2.load()
for i in range(26-mitad_ancho,26+mitad_ancho):
for j in range(26-mitad_alto,26+mitad_alto):
if pix[i+mitad_ancho-26,j+mitad_alto-26]>180:
im2_pix[i,j]=255
im2.save("alfabetocentrado/"+letra+"/"+f)
im2.close()
else:
os.remove("alfabeto/"+letra+"/"+f)

4.1.2 Creacin de Dataset

La creacin del Dataset en este modelo es la creacin de dos archivos txt, uno
que se llama classifications en la cual estn almacenadas el cdigo ACSII del
carcter que debe ser cada imagen. Este carcter es el primer carcter del
nombre de la imagen.
El otro archivo txt es el flattened_images en donde se encuentran
almacenadas el contenido de cada una de las imgenes. Para el
almacenamiento de cada imagen se lee el mapa de bits de cada imagen,
obtenindose una matriz de [52,52,3] y se aplana dicha matriz a una matriz
[1,(52*52*3))] haciendo que cada una de las imgenes se almacene en una
columna del vector que se almacenara en flattened_images.txt.
Las imgenes que estn siendo guardadas son las 5 000 imgenes que han sido
usadas para el entrenamiento del modelo.

Imgenes ubicadas en flattened_images.txt


carpeta entrenamiento
classifications.txt

Preparacin
del dataset
Cdigo
npaFlattenedImages = [np.empty((8112))]
intClassifications = []
for k in leer.listdir_recurd([],"entrenamiento/"," entrenamiento/",[]):
intClassifications.append(ord(k[0]))
I = Image.open("entrenamiento/"+str(k))
I.save("r.jpg")
imgTrainingNumbers = cv2.imread("r.jpg")
print(imgTrainingNumbers.shape)
npaFlattenedImage = imgTrainingNumbers.reshape(1,np.prod(imgTrainingNumbers.shape))
npaFlattenedImages = np.append(npaFlattenedImages, npaFlattenedImage,0)
print(k)

npaFlattenedImages =np.delete(npaFlattenedImages,0,0)
fltClassifications = np.array(intClassifications, np.float32)
# flatten numpy array of floats to 1d so we can write to file later
npaClassifications = fltClassifications.reshape((fltClassifications.size, 1))
print ("\n\ntraining data complete !!\n")

np.savetxt("classifications.txt", npaClassifications) # write flattened images to file


np.savetxt("flattened_images.txt", npaFlattenedImages)

Cuando finalice esto el modelo que hemos planteado habr guardado en los
archivos txt las imgenes como los caracteres que deben representar.

FUENTE: BLOC DE NOTAS CLASSIFICATIONS

Flattened_images.txt
FUENTE: BLOC DE NOTAS FLATTENED_IMAGES

4.1.3 Aprendizaje del modelo

El modelo KNN realiza las predicciones de qu tipo de objeto, en nuestro caso


carcter, es el que se introduce al modelo realizando una evaluacin de cules son los
K vecinos ms cercanos al objeto introducido
En nuestro caso los bits de la imagen, y el algoritmo calcula que tipo de objeto
es ms comn entre los vecinos del objeto a predecir y cul es la distancia del
objeto a predecir a cada uno de estos. Finalmente las valores que devuelve son
predicciones de qu tipo de objeto es basndose en que vecinos posee y la
distancia a estos.
El entrenamiento producir dos estructuras de datos paralelos:
- un grupo de nmeros indicando a que grupo o clasificacin pertenece la
imagen
- un grupo de imgenes

Aprendizaje hecho
La base de datos de entrenamiento est conformada por letras y nmeros:

Al modelo se le introduce tanto como dataset el archivo "flattened_images.txt" y


sus respectivos labels que se encuentran en el archivo classifications.txt.

flattened_images.txt
classifications.txt Entrenamiento Modelo entrenado
del modelo
kNearest
Cdigo:
try:
npaClassifications = np.loadtxt("classifications.txt", np.float32)
except:
print ("error, unable to open classifications.txt, exiting program\n")
os.system("pause")
# end try

try:
npaFlattenedImages = np.loadtxt("flattened_images.txt", np.float32)
except:
print ("error, unable to open flattened_images.txt, exiting program\n")
os.system("pause")

El cdigo de aprendizaje es el siguiente:


Cdigo:
kNearest = cv2.ml.KNearest_create() # instantiate KNN object
kNearest.train(npaFlattenedImages, cv2.ml.ROW_SAMPLE, npaClassifications)

Evaluacin del modelo:


La evaluacin del se realiz utilizando 3518 segmentos de captchas que haban
sido previamente seleccionados para la evaluacin del modelo y almacenados
en la carpeta test. Para verificar el rendimiento del modelo se realiz la
prediccin de todos los captchas en la carpeta test y se compar los resultados
con la primera letra de sus nombres que indica que letra debera ser el captcha.

Segmentos en carpeta
test Evaluacin del Rendimiento del
modelo modelo
Modelo kNearest entrenado

Se tuvo una tasa de xito del 81.6%, lo que indica que el modelo tiene una
buena eficiencia, podra mejorarse con un dataset ms grande.
5 CONCLUSIONES

El procedimiento para predecir el carcter que est en la imagen si cuenta con


una alta efectividad a tener ms de un 80% sin embargo presenta problemas ya
que al ejecutarse por un largo perodo se para debido a errores que no han sido
considerados
El cdigo de segmentacin trabaja a un 85% de xito, ya que en algunos casos
llega a fallar por el contenido de los captchas, pero esto no le resta efectividad,
ya que estos casos pueden ser eliminados manualmente

6 RECOMENDACIONES

Si se busca obtener un programa efectivo para la prediccin del carcter que


se encuentra en la imagen se deben probar el programa evaluando cualquier
casustica que se logre presentar, llevndolo a una mejora en el procedimiento
y posible mejora en efectividad de prediccin
Se necesita una base de datos ms grande para que el modelo aprenda
nuevos tipos de casustica y pueda predecir con mayor efectividad.
Usar un cdigo de segmentacin ms efectivo, que considere todos los casos y
haga recortes en las zonas correspondientes

7 BIBLIOGRAFIA

https://www.analyticsvidhya.com/blog/2014/10/introduction-k-neighbours-algorithm-
clustering/

https://docs.scipy.org/doc/numpy-dev/user/quickstart.html

http://www.oldemarrodriguez.com/yahoo_site_admin/assets/docs/Presentaci%C3%B3n_-
_KNN.20085205.pdf
8 ANEXO: PROGRAMAS FUENTE

ANEXO 1: LIBRERA PARA LEER O BORRAR ARCHIVOS


import os
import sys
from os import listdir
from os.path import isfile, isdir, join

def listdir_recurd(files_list, root, folder, checked_folders):


if (folder != root):
checked_folders.append(folder)
for f in listdir(folder):
d = join(folder, f)
if isdir(d) and d not in checked_folders:
listdir_recurd(files_list, root, d, checked_folders)
else:
if isfile(d):
files_list.append(join(f))
return files_list

def total_arch(folder,k):
n=0
for f in listdir(folder):
if f[2:11]==k:
n=n+1
return n

def borraraux():
if(os.path.exists("a.jpg")):
try:
os.remove("a.jpg")
except ValueError:
pass
if(os.path.exists("0.jpg")):
try:
os.remove("0.jpg")
except ValueError:
pass
if(os.path.exists("1.jpg")):
try:
os.remove("1.jpg")
except ValueError:
pass
if(os.path.exists("2.jpg")):
try:
os.remove("2.jpg")
except ValueError:
pass
if(os.path.exists("3.jpg")):
try:
os.remove("3.jpg")
except ValueError:
pass
if(os.path.exists("3.jpg")):
try:
os.remove("3.jpg")
except ValueError:
pass
if(os.path.exists("4.jpg")):
try:
os.remove("4.jpg")
except ValueError:
pass
if(os.path.exists("5.jpg")):
try:
os.remove("5.jpg")
except ValueError:
pass

def borraraux2():
if(os.path.exists("0.jpg")):
try:
os.remove("0.jpg")
except ValueError:
pass
if(os.path.exists("1.jpg")):
try:
os.remove("1.jpg")
except ValueError:
pass
if(os.path.exists("2.jpg")):
try:
os.remove("2.jpg")
except ValueError:
pass
if(os.path.exists("3.jpg")):
try:
os.remove("3.jpg")
except ValueError:
pass
if(os.path.exists("3.jpg")):
try:
os.remove("3.jpg")
except ValueError:
pass
if(os.path.exists("4.jpg")):
try:
os.remove("4.jpg")
except ValueError:
pass
if(os.path.exists("5.jpg")):
try:
os.remove("5.jpg")
except ValueError:
pass

def borrarauxexp(path):
if(os.path.exists(path)):
print(path)
try:
os.remove(path)
except ValueError:
pass

ANEXO 2: PREPARACIN DE LOS CAPTCHAS


from PIL import Image, ImageChops
import os.path
import numpy as np
import cv2
import matplotlib.pyplot as plt
import operator
import os
import time
import leer

def binarizacion(imagen, umbral):


ancho, alto = imagen.size
pix = imagen.load()
output = Image.new("L", (ancho, alto))
out_pix = output.load()
for i in range(ancho):
for j in range(alto):
if pix[i, j] >umbral: out_pix[i, j] = 255
else: out_pix[i, j] = 0
return output

def dilation(n):
imagen = cv2.imread("a.jpg",0)
#Crear un kernel de '1' de nxn
kernel = np.ones((n,n),np.uint8)
#Se aplica la transformacion: Erode
transformacion = cv2.dilate(imagen,kernel,iterations = 1)
cv2.imwrite("a.jpg" ,transformacion)

def pixels_total_horizontal(imagen):
w, h = imagen.size
pix = imagen.load()
histog=w*[0]
for i in range(w):
c=0
for j in range(h):
if pix[i,j]==255:
c=c+1
histog[i]=c
return histog

def pixels_total_vertical(imagen):
w, h = imagen.size
pix = imagen.load()
histog=h*[0]
for j in range(h):
c=0
for i in range(w):
if pix[i,j]==255:
c=c+1
histog[j]=c
return histog

def corte(imagen,m,n):
w1, h1 = imagen.size
c1=pixels_total_horizontal(imagen)
for i1 in range(w1):
if c1[i1]>m:
T=imagen.crop((i1-1,0,w1,h1))
break
w2, h2 = T.size
c2=pixels_total_horizontal(T)
for i2 in range(w2):
if c2[w2-i2-1]>m:
P=T.crop((0,0,w2-i2,h2))
break
w3, h3 = P.size
c3=pixels_total_vertical(P)
for i3 in range(h3):
if c3[i3]>n:
Q=P.crop((0,i3-1,w3,h3))
break
w4, h4 = Q.size
c4=pixels_total_vertical(Q)
for i4 in range(h4):
if c4[h4-i4-1]>n:
R=Q.crop((0,0,w4,h4-i4))
break
return R

def conteo_pixels_blanco(imagen):
cantidad=0
ancho, alto = imagen.size
pix = imagen.load()
for i in range(ancho):
for j in range(alto):
if pix[i,j]==255:
cantidad=cantidad+1
return cantidad

def seg_minimo_pixel(imagen):
r=minimo_pixel(imagen)
c=pixels_total_horizontal(imagen)
smenor=200
for i in range(len(c)):
if(c[i]<smenor and c[i]!=0 and c[i]!=r):
smenor=c[i]
return smenor

def thinning():
imagen = cv2.imread("a.jpg",0)
size = np.size(imagen)
skel = np.zeros(imagen.shape,np.uint8)
ret,imagen = cv2.threshold(imagen,127,255,0)
element = cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
done = False
while( not done):
eroded = cv2.erode(imagen,element)
temp = cv2.dilate(eroded,element)
temp = cv2.subtract(imagen,temp)
skel = cv2.bitwise_or(skel,temp)
imagen = eroded.copy()
zeros = size - cv2.countNonZero(imagen)
if zeros==size:
done = True
cv2.imwrite("a.jpg" ,skel)

def segmentacion(imagen,separador,nsegmentos,lseg,mintotpix):
his=pixels_total_horizontal(imagen)
print(his)
w, h = imagen.size
letter=False
foundletter=False
u=0
t=0
p=0
for i in range(w):
if letter==True:
if his[i]<=separador or i==w-1:
if i== w-1: print (t)
if t>lseg:
n2=i
foundletter=True
print("e")
else:
t=t+1
else:
t=t+1
else:
if his[i]>separador or i==0:
letter=True
n1=i
t=1
if foundletter==True:
im = imagen.crop((n1, 0, n2, h))
print(conteo_pixels_blanco(im))
if conteo_pixels_blanco(im)>mintotpix:
u=u+1
print(u)
if u==nsegmentos:
im = imagen.crop((n1, 0, w, h))
im.save(str(nsegmentos)+".jpg")
im.close()
break
elif u<nsegmentos:
leer.borrarauxexp(str(u)+"jpg")
im.save(str(u)+".jpg")
im.close()
p=n1
foundletter=False
letter=False
if u<nsegmentos:
im1 = imagen.crop((p, 0, w, h))
im1.save(str(u)+".jpg")
im1.close()
return u

def
segmentacion_thin(imagen1,imagen2,separador,nsegmentos,lseg):
leer.borraraux2()
his=pixels_total_horizontal(imagen2)
print(his)
w, h = imagen2.size
letter=False
foundletter=False
u=0
t=0
p=0
for i in range(w):
if letter==True:
if his[i]<=separador or i==w-1:
if t>lseg:
n2=i
foundletter=True
else:
t=t+1
else:
t=t+1
else:
if his[i]>separador or i==0:
letter=True
n1=i
t=1
if foundletter==True:
im = imagen1.crop((n1, 0, n2, h))
if conteo_pixels_blanco(im)>9:
u=u+1
if u==nsegmentos:
im1 = imagen1.crop((n1, 0, w, h))
im1.save(str(u)+".jpg")
im1.close()
break
elif u<nsegmentos:
im.save(str(u)+".jpg")
p=n1
im.close()
foundletter=False
letter=False
if u<nsegmentos:
im1 = imagen1.crop((p, 0, w, h))
im1.save(str(u)+".jpg")
im1.close()
print(u)
return u
def quitar_mancha(imagen):
ancho, alto = imagen.size
pix = imagen.load()
output = Image.new("L", (ancho, alto))
out_pix = output.load()
for i in range(ancho):
fin=1
for j in range(alto):
if pix[i,j]==0 and fin:
out_pix[i,j]=255
else:
fin=0
out_pix[i,j]=pix[i,j]
return output

def quitar_linea(imagen,L):
anchu, altu = imagen.size
out = imagen.load()
outps = Image.new("L", (anchu, altu))
out_ps = outps.load()
pix = L.load()
for n in range(anchu):
for m in range(altu):
if(out[n, m]==0):
if (pix[n, m] == 0):
out_ps[n, m]=255
if m != altu-1:
out_ps[n,m+1]=255
if m != 0:
out_ps[n,m-1]=255
else:
if out_ps[n, m]!=255:
out_ps[n, m]=out[n, m]
else:
if out_ps[n, m]!=255:
out_ps[n, m]=out[n, m]
return outps

def segmentar(minpix,nseg,Lminseg,k,mintotpix):
leer.borraraux()

c=leer.total_arch("C:/Users/Antonio/Desktop/ia.trabajo/segmentad
a",k)
print(c)
if c<5:
for i in range(c):
im1=Image.open("segmentada/"+str(i+1)+"."+str(k))
m=segmentacion(im1,minpix,nseg,Lminseg,mintotpix)
im1.close()
print(m,n,c)
if m>1 :
for r in range(c,i+1,-1):
print(r)
os.rename("segmentada/"+str(r)+"."+str(k),"segmentada/"+str(r+m-
1)+"."+str(k))
os.remove("segmentada/"+str(i+1)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg",
"segmentada/"+str(i+1+s)+"."+str(k))
break
leer.borraraux()

def segmentarforzado(k):

c=leer.total_arch("C:/Users/Antonio/Desktop/ia.trabajo/segmentad
a",k)
print(c)
Lmax=0
p=0
if c<5:
for i in range(c):
im1=Image.open("segmentada/"+str(i+1)+"."+str(k))
ancho, alt=im1.size
im1.close()
if ancho>Lmax:
Lmax=ancho
p=i+1
im1=Image.open("segmentada/"+str(p)+"."+str(k))
his=pixels_total_horizontal(im1)
minpix=100
for i in
range(int(round(Lmax/3.0,0))+1,int(2.0*round(Lmax/3.0,0))):
if his[i]<minpix:
minpix=his[i]
print(minpix,Lmax,p,"sd")
im1.close()
im1=Image.open("segmentada/"+str(p)+"."+str(k))
m=segmentacion(im1,minpix,2,round(Lmax/3),0)
im1.close()
print(m,n,c)
if m==2 :
for r in range(c,p,-1):
print(r)
os.rename("segmentada/"+str(r)+"."+str(k),
"segmentada/"+str(r+1)+"."+str(k))
os.remove("segmentada/"+str(p)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg",
"segmentada/"+str(p+s)+"."+str(k))
leer.borraraux()

def segmentarthin(minpix,nseg,Lminseg,k):
c=leer.total_arch("segmentada/",k)
print(c)
if c<5:
for i in range(c):
leer.borraraux()
im1=Image.open("segmentada/"+str(i+1)+"."+str(k))
im1.save("a.jpg")
dilation(2)
M=Image.open("a.jpg")
N=binarizacion(M, 90)
M.close()
leer.borrarauxexp("a.jpg")
N.save("a.jpg")
thinning()
dilation(2)
N.close()
P=Image.open("a.jpg")
Q=binarizacion(P, 90)
m=segmentacion_thin(im1,Q,minpix,nseg,Lminseg)
P.close()
Q.close()
im1.close()
if m>1:
for r in range(c,i+1,-1):
print(r)
os.rename("segmentada/"+str(r)+"."+str(k),
"segmentada/"+str(r+m-1)+"."+str(k))

os.remove("segmentada/"+str(i+1)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg",
"segmentada/"+str(i+1+s)+"."+str(k))
break
leer.borraraux2()

#########################CODIGO
PRINCIPAL###########################

for k in
leer.listdir_recurd([],'C:/Users/Antonio/Desktop/ia.trabajo/img'
,'C:/Users/Antonio/Desktop/ia.trabajo/img', []):
print(k)
leer.borraraux()
I = Image.open("img/"+k)
#convertir a gris
G = I.convert("L")
G.save("gris/"+k)
#binarizar imagen para que se vea solo la linea
LN=binarizacion(G, 40)
LN.save("linea/"+k)
#binarizar imagen para quitar el color de fondo de la imagen
w, h = G.size
pix = G.load()
output = Image.new("L", (w, h))
out_pix = output.load()
for i in range(w):
sum=0
for a in range(h):
sum=sum+pix[i,a]
p=sum/h
p=int(p)
for j in range(h):
if pix[i, j] >= p: out_pix[i, j] = 255
else: out_pix[i, j] = 0
output.save("binarizada/"+k)
#quitar mancha
A=quitar_mancha(output)
A.save("sinmancha/"+k)
#quitar linea
C=quitar_linea(A,LN)
C.save("sinlinea/"+k)
#invertir colores de la imagen
out = ImageChops.invert(C)
out.save("invertida/"+k)
#corte
Ct=corte(out,2,2)
Ct.save("cortada/"+k)
Ct.save("a.jpg")
dilation(2)
M=Image.open("a.jpg")
N=binarizacion(M, 90)
N.save("a.jpg")
thinning()
dilation(2)
N.close()
M.close()
P=Image.open("a.jpg")
Q=binarizacion(P, 90)
n=segmentacion_thin(Ct,Q,0,5,30)
P.close()
print(n)
for i in range(n):
if os.path.exists(str(i+1)+".jpg"):
L=Image.open(str(i+1)+".jpg")
L.save("segmentada/"+str(i+1)+"."+str(k))
L.close()
n=0
m=0
for i in range(5):
if os.path.exists("segmentada/"+str(i+1)+"."+str(k)):
R=Image.open("segmentada/"+str(i+1)+"."+str(k))
w, h = R.size
R.close()
if w>m:
m=w
c=i+1
n=n+1
else:
break
if n<5 and n>0:
print(m,n,c)
for i in range(n):
leer.borraraux()
im1=Image.open("segmentada/"+str(i+1)+"."+str(k))
m=segmentacion(im1,0,6-n,27,90)
im1.close()
print(m,n,c)
if m>1:
for r in range(c,i+1,-1):
print(r)

os.rename("segmentada/"+str(r)+"."+str(k),"segmentada/"+str(r+m-
1)+"."+str(k))
os.remove("segmentada/"+str(i+1)+"."+str(k))
for s in range(m):
os.rename(str(s+1)+".jpg",
"segmentada/"+str(i+1+s)+"."+str(k))
segmentar(0,6-n,23,k,80)
segmentar(1,6-c,23,k,85)
segmentar(0,6-n,20,k,85)
segmentar(1,6-c,22,k,85)
segmentar(2,6-c,25,k,85)
segmentar(2,6-c,20,k,70)
segmentar(3,6-c,20,k,80)
segmentar(3,6-c,20,k,70)
segmentar(5,6-c,20,k,70)
segmentar(6,6-c,20,k,70)
segmentarforzado(k)

for i in range(5):
letra=k[i]
if
os.path.exists("alfabeto/"+str(letra)+"/"+str(letra)+"."+str(i)+
"."+str(k))==0:
os.rename("segmentada/"+str(i+1)+"."+str(k),
"alfabeto/"+str(letra)+"/"+str(letra)+"."+str(i)+"."+str(k))
os.remove("img/"+str(k))

for letra in os.listdir("alfabeto/"):


for f in os.listdir("alfabeto/"+letra+"/"):
print(f)
im1=Image.open("alfabeto/"+letra+"/"+f)
if ancho<53:
im2=Image.new("L",(52,52))
im2_pix = im2.load()
for i in range(26-mitad_ancho,26+mitad_ancho):
for j in range(26-
mitad_alto,26+mitad_alto):
if pix[i+mitad_ancho-26,j+mitad_alto-
26]>180:
im2_pix[i,j]=255
im2.save("alfabetocentrado/"+letra+"/"+f)
im2.close()
else:
os.remove("alfabeto/"+letra+"/"+f)

ANEXO 3: PLANTEAMIENTO, DESARROLLO Y EVALUACION DEL MODELO


import sys
import numpy as np
import cv2
import os
import leer
from PIL import Image, ImageChops

npaFlattenedImages = [np.empty((8112))]
intClassifications = []

for k in
leer.listdir_recurd([],"C:/Users/USUARIO/Desktop/ia.trabajo/entrenamiento/","C:/Users/
USUARIO/Desktop/ia.trabajo/entrenamiento/",[]):
if k!="Thumbs.db":
intClassifications.append(ord(k[0]))
I = Image.open("entrenamiento/"+str(k))
I.save("r.jpg")
imgTrainingNumbers = cv2.imread("r.jpg")
npaFlattenedImage=
imgTrainingNumbers.reshape(1,np.prod(imgTrainingNumbers.shape))
npaFlattenedImages = np.append(npaFlattenedImages, npaFlattenedImage,0)
print(k)
npaFlattenedImages =np.delete(npaFlattenedImages,0,0)
fltClassifications = np.array(intClassifications, np.float32)
npaClassifications = fltClassifications.reshape((fltClassifications.size, 1))
print ("\n\ntraining data complete !!\n")
np.savetxt("classifications.txt", npaClassifications)
np.savetxt("flattened_images.txt", npaFlattenedImages)

try:
npaClassifications = np.loadtxt("classifications.txt", np.float32)
except:
print ("error, unable to open classifications.txt, exiting program\n")
os.system("pause")
# end try
try:
npaFlattenedImages = np.loadtxt("flattened_images.txt", np.float32)
except:
print ("error, unable to open flattened_images.txt, exiting program\n")
os.system("pause")

kNearest = cv2.ml.KNearest_create() # instantiate KNN object


kNearest.train(npaFlattenedImages, cv2.ml.ROW_SAMPLE, npaClassifications)
print("modelo entrenado")

#test
cont=0
for n in
leer.listdir_recurd([],"C:/Users/USUARIO/Desktop/ia.trabajo/test/","C:/Users/USUARIO/
Desktop/ia.trabajo/test/",[]):
print(n)
if n !="Thumbs.db":
test=Image.open("test/"+str(n))
test.save("test.jpg")
imgTestNumbers = cv2.imread("test.jpg")
testflt= imgTestNumbers.reshape(1,np.prod(8112))
testflt = np.float32(testflt)
retval, npaResults, neigh_resp, dists = kNearest.findNearest(testflt, k = 1)
predicchar = str(chr(int(npaResults[0][0])))
print(predicchar+" "+n[0])
if (n[0]==predicchar):
cont=cont+1
print(cont)

S-ar putea să vă placă și