Advertisement
Guest User

Captcha baker

a guest
Jan 7th, 2011
245
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.37 KB | None | 0 0
  1. #!/usr/bin/env python
  2. # -*- encoding: utf-8 -*-
  3. # Captcha Baker: A captcha breaker hello world
  4. # Requirements: image magick, PIL, tesseract-ocr
  5. # Written by kenkeiras
  6.  
  7. import os, sys, copy
  8. # Setea los parámetros
  9. if (len(sys.argv) < 3):
  10.     print >>sys.stderr, sys.argv[0],"<imágen> <número de letras> [<umbral>]"
  11.     exit(0)
  12.  
  13. threshold = 15
  14. if (len(sys.argv) > 3):
  15.     threshold = int(sys.argv[3])
  16.  
  17. oimg = sys.argv[1] # Imágen antigua
  18. img = oimg[ : oimg.index(".")] + ".bmp" # Imágen convertida
  19. lcount = int(sys.argv[2]) # Número de letras
  20.  
  21. tesseract_out = "tess_out" # Archivo de salida de tesseract
  22.  
  23. lprefx = "letra" # Prefijo en el nombre de las letras
  24.  
  25. # Convierte la imágen a bmp para manejarla mejor
  26. if (oimg != img):
  27.     print >>sys.stderr, "Convirtiendo a", img,"..."
  28.     os.system("convert "+oimg+" "+img) # Image magick!!
  29.  
  30. #########################################################
  31. # Misc
  32. #========================================================
  33. # Convierte un entero a un string
  34. def intstr(s,size=4):
  35.     i=0
  36.     t=""
  37.     while i<size:
  38.         aux=(s>>(8*i))&0xFF
  39.         t+=chr(int(aux))
  40.         i+=1
  41.     return t
  42.  
  43. # Lee un entero de en archivo (n es el número de bytes)
  44. def readNum(f,n=4):
  45.     l=f.read(n)
  46.     l=l[::-1] # Reverse, big endian enviroments
  47.     c=0
  48.     for i in l:
  49.         c*=256
  50.         c+=ord(i)
  51.     return c
  52.  
  53. #########################################################
  54. # BMP
  55. #========================================================
  56. class bmp:
  57.     def __init__(self,fname):
  58.         self.fname = fname
  59.         f = open(fname,'rb')
  60.         self.header = readNum(f,2)     # 0
  61.         self.size = readNum(f,4)       # 2
  62.         self.reserved = readNum(f,4)   # 6
  63.         self.data_init = readNum(f,4)  # A
  64.         self.head_size = readNum(f,4)  # E
  65.         self.width = readNum(f,4)      # 12
  66.         self.height = readNum(f,4)     # 16
  67.         self.planes = readNum(f,2)     # 1A
  68.         self.depth = readNum(f,2)      # 1C
  69.         self.compression = readNum(f,4)# 1E
  70.         self.img_size = readNum(f,4)   # 22
  71.         self.hor_res = readNum(f,4)    # 26
  72.         self.ver_res = readNum(f,4)    # 2A
  73.         self.palette = readNum(f,4)    # 2E
  74.         self.imp_colors = readNum(f,4) # 32
  75.  
  76.         self.pixNum = self.width * self.height
  77.         self.whitePix = []
  78.         self.blackPix = []
  79.         for i in xrange(self.depth / 8):
  80.             self.whitePix.append("\xff")
  81.             self.blackPix.append("\0")
  82.  
  83.         offset = 0
  84.         if (self.compression == 3):
  85.             offset = 17
  86.  
  87.         self.img = []
  88.         f.seek(54 + offset )
  89.         a = f.read()
  90.         for c in a:
  91.             self.img.append(c)
  92.        
  93.         f.close()
  94.        
  95.     # Save's current image state
  96.     def dump(self,fname):
  97.         f = open(fname,'wb')
  98.         f.write(intstr(self.header,2))
  99.         f.write(intstr(self.size,4))
  100.         f.write(intstr(self.reserved,4))
  101.         f.write(intstr(self.data_init,4))
  102.         f.write(intstr(self.head_size,4))
  103.         f.write(intstr(self.width,4))
  104.         f.write(intstr(self.height,4))
  105.         f.write(intstr(self.planes,2))
  106.         f.write(intstr(self.depth,2))
  107.         f.write(intstr(self.compression,4))
  108.         f.write(intstr(self.img_size,4))
  109.         f.write(intstr(self.hor_res,4))
  110.         f.write(intstr(self.ver_res,4))
  111.         f.write(intstr(self.palette,4))
  112.         f.write(intstr(self.imp_colors,4))
  113.         f.write(''.join(self.img))
  114.         f.close()
  115.  
  116.     # Get's a single pixel
  117.     def getPixel(self, num):
  118.         n = self.depth / 8
  119.         p = []
  120.         for i in xrange(num * n,(num * n) + n ):
  121.             p.append(self.img[i])
  122.         return p
  123.  
  124.     # Set's a single pixel
  125.     def setPixel(self, num, pix):
  126.         n = self.depth / 8
  127.         c = 0
  128.         for i in xrange(num * n,(num * n) + n ):
  129.             self.img[i] = pix[c]
  130.             c += 1
  131.  
  132.     # Se obtiene una columna
  133.     def getCol(self, x):
  134.         col = []
  135.         for i in range(0, self.height):
  136.             col.append(self.getPixel((i * self.width) + x))
  137.         return col
  138.    
  139.     # Obtiene la siguiente columna desde x con o sin
  140.     # color negro
  141.     def getNextCol(self, x, with_black):
  142.         while (x < self.width):
  143.             col = self.getCol(x)
  144.             has_black = False
  145.             for pix in col:
  146.                 for byt in pix:
  147.                     if (byt != "\xff"):
  148.                         has_black = True
  149.                         break
  150.  
  151.             if (has_black == with_black):
  152.                 return x
  153.  
  154.             x += 1
  155.         return -1
  156.  
  157. # Comprueba la diferencia de color entre dos pixeles
  158. def inThr(pix1, pix2, thr):
  159.     getNum = abs(ord(pix1[0]) - ord(pix2[0])) + \
  160.              abs(ord(pix1[1]) - ord(pix2[1])) + \
  161.              abs(ord(pix1[2]) - ord(pix2[2]))
  162.     return getNum  <= thr
  163.  
  164. #########################################################
  165. # Main
  166. #========================================================
  167. bi = bmp(img)
  168.  
  169. print >>sys.stderr, bi.depth
  170.  
  171. # Se toma como color base la primera fila
  172. print >>sys.stderr, "Leyendo primera fila"
  173. baseImg = []
  174. for i in xrange(bi.width):
  175.     pix = bi.getPixel(i)
  176.     if not pix in baseImg:
  177.         baseImg.append(pix)
  178.  
  179. # Los colores que entren en el umbral se convierten en blanco
  180. # el resto en negro
  181. print >>sys.stderr, "Aplicando un umbral de", threshold
  182. for i in xrange(bi.pixNum):
  183.     base = False
  184.  
  185.     pix = bi.getPixel(i)
  186.  
  187.     for x in baseImg:
  188.         p = inThr(pix, x, threshold)
  189.         if (p):
  190.             base = True
  191.             break
  192.  
  193.     if (base):
  194.         bi.setPixel(i, bi.whitePix)
  195.     else:    
  196.         bi.setPixel(i, bi.blackPix)
  197.  
  198. # Se guarda este archivo
  199. out = "output.bmp"
  200. print >>sys.stderr, "Guardando base:", out
  201. bi.dump(out)
  202.  
  203. # Se parte por letras
  204. # se usa la Python Image Library
  205. from PIL import Image
  206.  
  207. im = Image.open(out)
  208.  
  209. bx = 0
  210. if (lcount != 0):
  211.     print >>sys.stderr, "Partiendo", lcount, "letras"
  212. else:
  213.     print >>sys.stderr, "Partiendo nosecuantas letras"
  214.  
  215. word = ""
  216. i = 0
  217. done = False
  218.  
  219. while True:
  220.     # Primero se busca una columna con negro
  221.     nx = bi.getNextCol(bx, True)
  222.  
  223.     if (nx == -1):
  224.         break
  225.  
  226.     # Antes no estaba claro si se mostraría esta
  227.     print >>sys.stderr, "Letra", str(i + 1) + ":",
  228.  
  229.     # Y después una sin el
  230.     nx = bi.getNextCol(nx, False)
  231.     if (nx == -1):
  232.         done = True
  233.         nx = bi.width -1
  234.  
  235.     # Solo queda cortar la imágen
  236.    
  237.     tmpname = lprefx + str(i) + ".bmp"
  238.     endname = lprefx + str(i) +".tif"
  239.  
  240.     end = bi.getNextCol(nx, True) - 1
  241.  
  242.     try:
  243.         im.crop((bx, 0, end, bi.height)).save(tmpname)
  244.     except:
  245.         im.crop((bx, 0, nx, bi.height)).save(tmpname)
  246.  
  247.     # Se elimina el archivo anterior
  248.     try:
  249.         os.unlink(tesseract_out + "txt")
  250.     except:
  251.         pass
  252.  
  253.     # Se convierte a tif (lo que maneja el OCR)
  254.     os.system("convert " + tmpname + " " + endname)
  255.  
  256.     # Se lanza tesseract-ocr contra la imágen
  257.     os.system("tesseract " + endname + " " + tesseract_out + " 2>>/dev/null")
  258.  
  259.     # Y se lee la letra
  260.     ft = open(tesseract_out + ".txt", "r")
  261.     word += ft.readline(1).strip()
  262.     ft.close()
  263.  
  264.     try:
  265.         print >>sys.stderr, word[-1]
  266.     except:
  267.         print >>sys.stderr, "¿?"
  268.  
  269.     bx = nx
  270.     i += 1
  271.     if ((i >= lcount) and (lcount != 0)) or (done):
  272.         break
  273.  
  274. print >>sys.stderr, "Resultado: ",
  275. print word
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement