Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env python
- # -*- encoding: utf-8 -*-
- # Captcha Baker: A captcha breaker hello world
- # Requirements: image magick, PIL, tesseract-ocr
- # Written by kenkeiras
- import os, sys, copy
- # Setea los parámetros
- if (len(sys.argv) < 3):
- print >>sys.stderr, sys.argv[0],"<imágen> <número de letras> [<umbral>]"
- exit(0)
- threshold = 15
- if (len(sys.argv) > 3):
- threshold = int(sys.argv[3])
- oimg = sys.argv[1] # Imágen antigua
- img = oimg[ : oimg.index(".")] + ".bmp" # Imágen convertida
- lcount = int(sys.argv[2]) # Número de letras
- tesseract_out = "tess_out" # Archivo de salida de tesseract
- lprefx = "letra" # Prefijo en el nombre de las letras
- # Convierte la imágen a bmp para manejarla mejor
- if (oimg != img):
- print >>sys.stderr, "Convirtiendo a", img,"..."
- os.system("convert "+oimg+" "+img) # Image magick!!
- #########################################################
- # Misc
- #========================================================
- # Convierte un entero a un string
- def intstr(s,size=4):
- i=0
- t=""
- while i<size:
- aux=(s>>(8*i))&0xFF
- t+=chr(int(aux))
- i+=1
- return t
- # Lee un entero de en archivo (n es el número de bytes)
- def readNum(f,n=4):
- l=f.read(n)
- l=l[::-1] # Reverse, big endian enviroments
- c=0
- for i in l:
- c*=256
- c+=ord(i)
- return c
- #########################################################
- # BMP
- #========================================================
- class bmp:
- def __init__(self,fname):
- self.fname = fname
- f = open(fname,'rb')
- self.header = readNum(f,2) # 0
- self.size = readNum(f,4) # 2
- self.reserved = readNum(f,4) # 6
- self.data_init = readNum(f,4) # A
- self.head_size = readNum(f,4) # E
- self.width = readNum(f,4) # 12
- self.height = readNum(f,4) # 16
- self.planes = readNum(f,2) # 1A
- self.depth = readNum(f,2) # 1C
- self.compression = readNum(f,4)# 1E
- self.img_size = readNum(f,4) # 22
- self.hor_res = readNum(f,4) # 26
- self.ver_res = readNum(f,4) # 2A
- self.palette = readNum(f,4) # 2E
- self.imp_colors = readNum(f,4) # 32
- self.pixNum = self.width * self.height
- self.whitePix = []
- self.blackPix = []
- for i in xrange(self.depth / 8):
- self.whitePix.append("\xff")
- self.blackPix.append("\0")
- offset = 0
- if (self.compression == 3):
- offset = 17
- self.img = []
- f.seek(54 + offset )
- a = f.read()
- for c in a:
- self.img.append(c)
- f.close()
- # Save's current image state
- def dump(self,fname):
- f = open(fname,'wb')
- f.write(intstr(self.header,2))
- f.write(intstr(self.size,4))
- f.write(intstr(self.reserved,4))
- f.write(intstr(self.data_init,4))
- f.write(intstr(self.head_size,4))
- f.write(intstr(self.width,4))
- f.write(intstr(self.height,4))
- f.write(intstr(self.planes,2))
- f.write(intstr(self.depth,2))
- f.write(intstr(self.compression,4))
- f.write(intstr(self.img_size,4))
- f.write(intstr(self.hor_res,4))
- f.write(intstr(self.ver_res,4))
- f.write(intstr(self.palette,4))
- f.write(intstr(self.imp_colors,4))
- f.write(''.join(self.img))
- f.close()
- # Get's a single pixel
- def getPixel(self, num):
- n = self.depth / 8
- p = []
- for i in xrange(num * n,(num * n) + n ):
- p.append(self.img[i])
- return p
- # Set's a single pixel
- def setPixel(self, num, pix):
- n = self.depth / 8
- c = 0
- for i in xrange(num * n,(num * n) + n ):
- self.img[i] = pix[c]
- c += 1
- # Se obtiene una columna
- def getCol(self, x):
- col = []
- for i in range(0, self.height):
- col.append(self.getPixel((i * self.width) + x))
- return col
- # Obtiene la siguiente columna desde x con o sin
- # color negro
- def getNextCol(self, x, with_black):
- while (x < self.width):
- col = self.getCol(x)
- has_black = False
- for pix in col:
- for byt in pix:
- if (byt != "\xff"):
- has_black = True
- break
- if (has_black == with_black):
- return x
- x += 1
- return -1
- # Comprueba la diferencia de color entre dos pixeles
- def inThr(pix1, pix2, thr):
- getNum = abs(ord(pix1[0]) - ord(pix2[0])) + \
- abs(ord(pix1[1]) - ord(pix2[1])) + \
- abs(ord(pix1[2]) - ord(pix2[2]))
- return getNum <= thr
- #########################################################
- # Main
- #========================================================
- bi = bmp(img)
- print >>sys.stderr, bi.depth
- # Se toma como color base la primera fila
- print >>sys.stderr, "Leyendo primera fila"
- baseImg = []
- for i in xrange(bi.width):
- pix = bi.getPixel(i)
- if not pix in baseImg:
- baseImg.append(pix)
- # Los colores que entren en el umbral se convierten en blanco
- # el resto en negro
- print >>sys.stderr, "Aplicando un umbral de", threshold
- for i in xrange(bi.pixNum):
- base = False
- pix = bi.getPixel(i)
- for x in baseImg:
- p = inThr(pix, x, threshold)
- if (p):
- base = True
- break
- if (base):
- bi.setPixel(i, bi.whitePix)
- else:
- bi.setPixel(i, bi.blackPix)
- # Se guarda este archivo
- out = "output.bmp"
- print >>sys.stderr, "Guardando base:", out
- bi.dump(out)
- # Se parte por letras
- # se usa la Python Image Library
- from PIL import Image
- im = Image.open(out)
- bx = 0
- if (lcount != 0):
- print >>sys.stderr, "Partiendo", lcount, "letras"
- else:
- print >>sys.stderr, "Partiendo nosecuantas letras"
- word = ""
- i = 0
- done = False
- while True:
- # Primero se busca una columna con negro
- nx = bi.getNextCol(bx, True)
- if (nx == -1):
- break
- # Antes no estaba claro si se mostraría esta
- print >>sys.stderr, "Letra", str(i + 1) + ":",
- # Y después una sin el
- nx = bi.getNextCol(nx, False)
- if (nx == -1):
- done = True
- nx = bi.width -1
- # Solo queda cortar la imágen
- tmpname = lprefx + str(i) + ".bmp"
- endname = lprefx + str(i) +".tif"
- end = bi.getNextCol(nx, True) - 1
- try:
- im.crop((bx, 0, end, bi.height)).save(tmpname)
- except:
- im.crop((bx, 0, nx, bi.height)).save(tmpname)
- # Se elimina el archivo anterior
- try:
- os.unlink(tesseract_out + "txt")
- except:
- pass
- # Se convierte a tif (lo que maneja el OCR)
- os.system("convert " + tmpname + " " + endname)
- # Se lanza tesseract-ocr contra la imágen
- os.system("tesseract " + endname + " " + tesseract_out + " 2>>/dev/null")
- # Y se lee la letra
- ft = open(tesseract_out + ".txt", "r")
- word += ft.readline(1).strip()
- ft.close()
- try:
- print >>sys.stderr, word[-1]
- except:
- print >>sys.stderr, "¿?"
- bx = nx
- i += 1
- if ((i >= lcount) and (lcount != 0)) or (done):
- break
- print >>sys.stderr, "Resultado: ",
- print word
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement