summaryrefslogtreecommitdiffstats
path: root/module/plugins/captcha
diff options
context:
space:
mode:
authorGravatar mkaay <mkaay@mkaay.de> 2009-12-30 17:33:14 +0100
committerGravatar mkaay <mkaay@mkaay.de> 2009-12-30 17:33:14 +0100
commit7c28259f92c2b3c608583ff128a5ae4134d4c48f (patch)
tree1cc8d9e95c38f51b0efaef927e0036b677355068 /module/plugins/captcha
parentsignal slot stuff (diff)
downloadpyload-7c28259f92c2b3c608583ff128a5ae4134d4c48f.tar.xz
moved captcha stuff, extended serienjunkies, some other stuff
Diffstat (limited to 'module/plugins/captcha')
-rw-r--r--module/plugins/captcha/GigasizeCom.py15
-rw-r--r--module/plugins/captcha/LinksaveIn.py161
-rw-r--r--module/plugins/captcha/MegauploadCom.py13
-rw-r--r--module/plugins/captcha/NetloadIn.py25
-rw-r--r--module/plugins/captcha/ShareonlineBiz.py61
-rw-r--r--module/plugins/captcha/__init__.py0
-rw-r--r--module/plugins/captcha/captcha.py295
7 files changed, 570 insertions, 0 deletions
diff --git a/module/plugins/captcha/GigasizeCom.py b/module/plugins/captcha/GigasizeCom.py
new file mode 100644
index 000000000..136092181
--- /dev/null
+++ b/module/plugins/captcha/GigasizeCom.py
@@ -0,0 +1,15 @@
+from captcha import OCR
+
+class GigasizeCom(OCR):
+ def __init__(self):
+ OCR.__init__(self)
+
+ def get_captcha(self, image):
+ self.load_image(image)
+ self.threshold(2.8)
+ self.run_gocr()
+ return self.result_captcha
+
+if __name__ == '__main__':
+ ocr = GigasizeCom()
+ print ocr.get_captcha('gigasize-com/7.jpg')
diff --git a/module/plugins/captcha/LinksaveIn.py b/module/plugins/captcha/LinksaveIn.py
new file mode 100644
index 000000000..d6f61e362
--- /dev/null
+++ b/module/plugins/captcha/LinksaveIn.py
@@ -0,0 +1,161 @@
+from captcha import OCR
+import Image
+from os import sep
+from os.path import dirname
+from os.path import abspath
+from glob import glob
+import tempfile
+
+
+class LinksaveIn(OCR):
+ def __init__(self):
+ OCR.__init__(self)
+ self.data_dir = dirname(abspath(__file__)) + sep + "LinksaveIn" + sep
+
+ def load_image(self, image):
+ im = Image.open(image)
+ frame_nr = 0
+
+ lut = im.resize((256, 1))
+ lut.putdata(range(256))
+ lut = list(lut.convert("RGB").getdata())
+
+ new = Image.new("RGB", im.size)
+ npix = new.load()
+ while True:
+ try:
+ im.seek(frame_nr)
+ except EOFError:
+ break
+ frame = im.copy()
+ pix = frame.load()
+ for x in range(frame.size[0]):
+ for y in range(frame.size[1]):
+ if lut[pix[x, y]] != (0,0,0):
+ npix[x, y] = lut[pix[x, y]]
+ frame_nr += 1
+ new.save(self.data_dir+"unblacked.png")
+ self.image = new.copy()
+ self.pixels = self.image.load()
+ self.result_captcha = ''
+
+ def get_bg(self):
+ stat = {}
+ cstat = {}
+ img = self.image.convert("P")
+ for bgpath in glob(self.data_dir+"bg/*.gif"):
+ stat[bgpath] = 0
+ bg = Image.open(bgpath)
+
+ bglut = bg.resize((256, 1))
+ bglut.putdata(range(256))
+ bglut = list(bglut.convert("RGB").getdata())
+
+ lut = img.resize((256, 1))
+ lut.putdata(range(256))
+ lut = list(lut.convert("RGB").getdata())
+
+ bgpix = bg.load()
+ pix = img.load()
+ for x in range(bg.size[0]):
+ for y in range(bg.size[1]):
+ rgb_bg = bglut[bgpix[x, y]]
+ rgb_c = lut[pix[x, y]]
+ try:
+ cstat[rgb_c] += 1
+ except:
+ cstat[rgb_c] = 1
+ if rgb_bg == rgb_c:
+ stat[bgpath] += 1
+ max_p = 0
+ bg = ""
+ for bgpath, value in stat.items():
+ if max_p < value:
+ bg = bgpath
+ max_p = value
+ return bg
+
+ def substract_bg(self, bgpath):
+ bg = Image.open(bgpath)
+ img = self.image.convert("P")
+
+ bglut = bg.resize((256, 1))
+ bglut.putdata(range(256))
+ bglut = list(bglut.convert("RGB").getdata())
+
+ lut = img.resize((256, 1))
+ lut.putdata(range(256))
+ lut = list(lut.convert("RGB").getdata())
+
+ bgpix = bg.load()
+ pix = img.load()
+ orgpix = self.image.load()
+ for x in range(bg.size[0]):
+ for y in range(bg.size[1]):
+ rgb_bg = bglut[bgpix[x, y]]
+ rgb_c = lut[pix[x, y]]
+ if rgb_c == rgb_bg:
+ orgpix[x, y] = (255,255,255)
+
+ def eval_black_white(self):
+ new = Image.new("RGB", (140, 75))
+ pix = new.load()
+ orgpix = self.image.load()
+ thresh = 4
+ for x in range(new.size[0]):
+ for y in range(new.size[1]):
+ rgb = orgpix[x, y]
+ r, g, b = rgb
+ pix[x, y] = (255,255,255)
+ if r > max(b, g)+thresh:
+ pix[x, y] = (0,0,0)
+ if g < min(r, b):
+ pix[x, y] = (0,0,0)
+ if g > max(r, b)+thresh:
+ pix[x, y] = (0,0,0)
+ if b > max(r, g)+thresh:
+ pix[x, y] = (0,0,0)
+ self.image = new
+ self.pixels = self.image.load()
+
+ def run_tesser(self):
+ self.logger.debug("create tmp tif")
+ tmp = tempfile.NamedTemporaryFile(suffix=".tif")
+ self.logger.debug("create tmp txt")
+ tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt")
+ self.logger.debug("save tiff")
+ self.image.save(tmp.name, 'TIFF')
+ self.logger.debug("run tesseract")
+ self.run(['tesseract', tmp.name, tmpTxt.name.replace(".txt", ""), "nobatch", self.data_dir+"tesser_conf"])
+ self.logger.debug("read txt")
+
+ with open(tmpTxt.name, 'r') as f:
+ self.result_captcha = f.read().replace("\n", "")
+
+ def get_captcha(self, image):
+ self.load_image(image)
+ bg = self.get_bg()
+ self.substract_bg(bg)
+ self.eval_black_white()
+ self.to_greyscale()
+ self.image.save(self.data_dir+"cleaned_pass1.png")
+ self.clean(4)
+ self.clean(4)
+ self.image.save(self.data_dir+"cleaned_pass2.png")
+ letters = self.split_captcha_letters()
+ final = ""
+ for n, letter in enumerate(letters):
+ self.image = letter
+ self.image.save(ocr.data_dir+"letter%d.png" % n)
+ self.run_tesser()
+ final += self.result_captcha
+
+ return final
+
+if __name__ == '__main__':
+ import urllib
+ ocr = LinksaveIn()
+ testurl = "http://linksave.in/captcha/cap.php?hsh=2229185&code=ZzHdhl3UffV3lXTH5U4b7nShXj%2Bwma1vyoNBcbc6lcc%3D"
+ urllib.urlretrieve(testurl, ocr.data_dir+"captcha.gif")
+
+ print ocr.get_captcha(ocr.data_dir+'captcha.gif')
diff --git a/module/plugins/captcha/MegauploadCom.py b/module/plugins/captcha/MegauploadCom.py
new file mode 100644
index 000000000..374bcd678
--- /dev/null
+++ b/module/plugins/captcha/MegauploadCom.py
@@ -0,0 +1,13 @@
+from captcha import OCR
+
+class MegauploadCom(OCR):
+ def __init__(self):
+ OCR.__init__(self)
+
+ def get_captcha(self, image):
+ self.load_image(image)
+ self.run_tesser()
+ return self.result_captcha
+
+if __name__ == '__main__':
+ ocr = MegauploadCom()
diff --git a/module/plugins/captcha/NetloadIn.py b/module/plugins/captcha/NetloadIn.py
new file mode 100644
index 000000000..9799a6a2b
--- /dev/null
+++ b/module/plugins/captcha/NetloadIn.py
@@ -0,0 +1,25 @@
+from captcha import OCR
+
+class NetloadIn(OCR):
+ def __init__(self):
+ OCR.__init__(self)
+
+ def get_captcha(self, image):
+ self.load_image(image)
+ self.to_greyscale()
+ self.clean(3)
+ self.clean(3)
+ self.run_tesser()
+
+ self.correct({
+ ("$", "g"): "5",
+ })
+
+ return self.result_captcha
+
+if __name__ == '__main__':
+ import urllib
+ ocr = NetloadIn()
+ urllib.urlretrieve("http://netload.in/share/includes/captcha.php", "captcha.png")
+
+ print ocr.get_captcha('captcha.png')
diff --git a/module/plugins/captcha/ShareonlineBiz.py b/module/plugins/captcha/ShareonlineBiz.py
new file mode 100644
index 000000000..91124f181
--- /dev/null
+++ b/module/plugins/captcha/ShareonlineBiz.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+#Copyright (C) 2009 kingzero, RaNaN
+#
+#This program is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3 of the License,
+#or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#See the GNU General Public License for more details.
+#
+#You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+###
+from captcha import OCR
+
+class ShareonlineBiz(OCR):
+ def __init__(self):
+ OCR.__init__(self)
+
+ def get_captcha(self, image):
+ self.load_image(image)
+ self.to_greyscale()
+ self.image = self.image.resize((160, 50))
+ self.pixels = self.image.load()
+ self.threshold(1.85)
+ #self.eval_black_white(240)
+ #self.derotate_by_average()
+
+ letters = self.split_captcha_letters()
+
+ final = ""
+ for letter in letters:
+ self.image = letter
+ self.run_tesser()
+ final += self.result_captcha
+
+ #replace common errors
+ final = self.correct({
+ "A": "4",
+ "‘5": "3",
+ ("‘1", "T"): "7",
+ ("‘L", "B", "'L"): "2",
+ "b": "6",
+ ("I", "X"): "1"
+ }, final)
+
+ return final
+
+ #tesseract at 60%
+
+if __name__ == '__main__':
+ import urllib
+ ocr = ShareonlineBiz()
+ urllib.urlretrieve("http://www.share-online.biz/captcha.php", "captcha.jpeg")
+ print ocr.get_captcha('captcha.jpeg')
diff --git a/module/plugins/captcha/__init__.py b/module/plugins/captcha/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/module/plugins/captcha/__init__.py
diff --git a/module/plugins/captcha/captcha.py b/module/plugins/captcha/captcha.py
new file mode 100644
index 000000000..283b171e0
--- /dev/null
+++ b/module/plugins/captcha/captcha.py
@@ -0,0 +1,295 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+#
+#Copyright (C) 2009 kingzero, RaNaN
+#
+#This program is free software; you can redistribute it and/or modify
+#it under the terms of the GNU General Public License as published by
+#the Free Software Foundation; either version 3 of the License,
+#or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#See the GNU General Public License for more details.
+#
+#You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+###
+from __future__ import with_statement
+import logging
+import subprocess
+import tempfile
+import threading
+
+import Image
+
+class RunThread(threading.Thread):
+ def __init__(self):
+ threading.Thread.__init__(self)
+
+ def e(self, command, inputdata=None):
+ """execute command """
+ self.command = command
+ self.inputdata = inputdata
+ self.result = ""
+ self.start()
+ self.join(10)
+ return self.result
+
+ def run(self):
+ """Run a command and return standard output"""
+ pipe = subprocess.PIPE
+ popen = subprocess.Popen(self.command, stdout=pipe, stderr=pipe)
+ outputdata, errdata = popen.communicate(self.inputdata)
+ assert (popen.returncode == 0), \
+ "Error running: %s\n\n%s" % (self.command, errdata)
+ self.result = outputdata
+
+class OCR(object):
+ def __init__(self):
+ self.logger = logging.getLogger("log")
+
+ def load_image(self, image):
+ self.image = Image.open(image)
+ self.pixels = self.image.load()
+ self.result_captcha = ''
+
+ def unload(self):
+ """delete all tmp images"""
+ pass
+
+ def threshold(self, value):
+ self.image = self.image.point(lambda a: a * value + 10)
+
+ def run(self, command, inputdata=None):
+ """Run a command and return standard output"""
+ # OLD METHOD
+ # pipe = subprocess.PIPE
+ # popen = subprocess.Popen(command, stdout=pipe, stderr=pipe)
+ # outputdata, errdata = popen.communicate(inputdata)
+ # assert (popen.returncode == 0), \
+ # "Error running: %s\n\n%s" % (command, errdata)
+ # return outputdata
+
+ thread = RunThread()
+ result = thread.e(command, inputdata)
+ return result
+
+ def run_gocr(self):
+ tmp = tempfile.NamedTemporaryFile(suffix=".jpg")
+ self.image.save(tmp)
+ self.result_captcha = self.run(['gocr', tmp.name]).replace("\n", "")
+
+ def run_tesser(self):
+ self.logger.debug("create tmp tif")
+ tmp = tempfile.NamedTemporaryFile(suffix=".tif")
+ self.logger.debug("create tmp txt")
+ tmpTxt = tempfile.NamedTemporaryFile(suffix=".txt")
+ self.logger.debug("save tiff")
+ self.image.save(tmp.name, 'TIFF')
+ self.logger.debug("run tesseract")
+ self.run(['tesseract', tmp.name, tmpTxt.name.replace(".txt", "")])
+ self.logger.debug("read txt")
+
+ with open(tmpTxt.name, 'r') as f:
+ self.result_captcha = f.read().replace("\n", "")
+
+ def get_captcha(self):
+ raise NotImplementedError
+
+ def to_greyscale(self):
+ if self.image.mode != 'L':
+ self.image = self.image.convert('L')
+
+ self.pixels = self.image.load()
+
+ def eval_black_white(self, limit):
+ self.pixels = self.image.load()
+ w, h = self.image.size
+ for x in xrange(w):
+ for y in xrange(h):
+ if self.pixels[x, y] > limit:
+ self.pixels[x, y] = 255
+ else:
+ self.pixels[x, y] = 0
+
+ def clean(self, allowed):
+ pixels = self.pixels
+
+ w, h = self.image.size
+
+ for x in xrange(w):
+ for y in xrange(h):
+ if pixels[x, y] == 255: continue
+ # no point in processing white pixels since we only want to remove black pixel
+ count = 0
+
+ try:
+ if pixels[x-1, y-1] != 255: count += 1
+ if pixels[x-1, y] != 255: count += 1
+ if pixels[x-1, y + 1] != 255: count += 1
+ if pixels[x, y + 1] != 255: count += 1
+ if pixels[x + 1, y + 1] != 255: count += 1
+ if pixels[x + 1, y] != 255: count += 1
+ if pixels[x + 1, y-1] != 255: count += 1
+ if pixels[x, y-1] != 255: count += 1
+ except:
+ pass
+
+ # not enough neighbors are dark pixels so mark this pixel
+ # to be changed to white
+ if count < allowed:
+ pixels[x, y] = 1
+
+ # second pass: this time set all 1's to 255 (white)
+ for x in xrange(w):
+ for y in xrange(h):
+ if pixels[x, y] == 1: pixels[x, y] = 255
+
+ self.pixels = pixels
+
+ def derotate_by_average(self):
+ """rotate by checking each angle and guess most suitable"""
+
+ w, h = self.image.size
+ pixels = self.pixels
+
+ for x in xrange(w):
+ for y in xrange(h):
+ if pixels[x, y] == 0:
+ pixels[x, y] = 155
+
+ highest = {}
+ counts = {}
+
+ for angle in range(-45, 45):
+
+ tmpimage = self.image.rotate(angle)
+
+ pixels = tmpimage.load()
+
+ w, h = self.image.size
+
+ for x in xrange(w):
+ for y in xrange(h):
+ if pixels[x, y] == 0:
+ pixels[x, y] = 255
+
+
+ count = {}
+
+ for x in xrange(w):
+ count[x] = 0
+ for y in xrange(h):
+ if pixels[x, y] == 155:
+ count[x] += 1
+
+ sum = 0
+ cnt = 0
+
+ for x in count.values():
+ if x != 0:
+ sum += x
+ cnt += 1
+
+ avg = sum / cnt
+ counts[angle] = cnt
+ highest[angle] = 0
+ for x in count.values():
+ if x > highest[angle]:
+ highest[angle] = x
+
+ highest[angle] = highest[angle] - avg
+
+ hkey = 0
+ hvalue = 0
+
+ for key, value in highest.iteritems():
+ if value > hvalue:
+ hkey = key
+ hvalue = value
+
+ self.image = self.image.rotate(hkey)
+ pixels = self.image.load()
+
+ for x in xrange(w):
+ for y in xrange(h):
+ if pixels[x, y] == 0:
+ pixels[x, y] = 255
+
+ if pixels[x, y] == 155:
+ pixels[x, y] = 0
+
+ self.pixels = pixels
+
+ def split_captcha_letters(self):
+ captcha = self.image
+ started = False
+ letters = []
+ width, height = captcha.size
+ bottomY, topY = 0, height
+ pixels = captcha.load()
+
+ for x in xrange(width):
+ black_pixel_in_col = False
+ for y in xrange(height):
+ if pixels[x, y] != 255:
+ if started == False:
+ started = True
+ firstX = x
+ lastX = x
+
+ if y > bottomY: bottomY = y
+ if y < topY: topY = y
+ if x > lastX: lastX = x
+
+ black_pixel_in_col = True
+
+ if black_pixel_in_col == False and started == True:
+ rect = (firstX, topY, lastX, bottomY)
+ new_captcha = captcha.crop(rect)
+
+ w, h = new_captcha.size
+ if w > 5 and h > 5:
+ letters.append(new_captcha)
+
+ started = False
+ bottomY, topY = 0, height
+
+ return letters
+
+ def correct(self, values, var=None):
+
+ if var:
+ result = var
+ else:
+ result = self.result_captcha
+
+ for key, item in values.iteritems():
+
+ if key.__class__ == str:
+ result = result.replace(key, item)
+ else:
+ for expr in key:
+ result = result.replace(expr, item)
+
+ if var:
+ return result
+ else:
+ self.result_captcha = result
+
+
+if __name__ == '__main__':
+ ocr = OCR()
+ ocr.load_image("B.jpg")
+ ocr.to_greyscale()
+ ocr.eval_black_white(140)
+ ocr.derotate_by_avergage()
+ ocr.run_gocr()
+ print "GOCR", ocr.result_captcha
+ ocr.run_tesser()
+ print "Tesseract", ocr.result_captcha
+ ocr.image.save("derotated.jpg")
+