2014-12-03 20 views
2

我感興趣的是3D驗證碼的,我把它與單個字體的工作,如下圖所示:創建具有不同的字體3D驗證碼

import string 
from matplotlib.font_manager import findSystemFonts 
import random 
from PIL import ImageFont, Image, ImageDraw 

def rand_font(fonts=[], fontpaths=None, fontext='ttf', font_encoding='', min_size=24, max_size=36): 
    if fonts == []: 
     fonts = findSystemFonts(fontpaths, fontext) 
    requested_font = fonts[random.randint(0, len(fonts)-1)] 
    font_size = random.randint(min_size, max_size) 
    return ImageFont.truetype(requested_font, font_size, encoding=font_encoding) 

def create_captcha(text): 
    def _rand_color(): 
     colors = ['red', 'orange', 'white', 'purple', 'green', 'yellow'] 
     return colors[random.randint(0, len(colors)-1)] 

    width = random.randint(400, 700) 
    height = random.randint(150, 200) 
    angle = angle if angle else uniform(-20, 20) 


    font = rand_font() 

    text_width, text_height = font.getsize(text) 

    img = Image.new("L", (text_width * 3, text_height * 3), "white") 
    draw = ImageDraw.Draw(img) 
    draw.text((text_width, text_height), text, font=font) 

    fig = pylab.figure(figsize=(width/100.0, height/100.0), dpi=4000) 
    axes = Axes3D(fig) 
    X, Y = numpy.meshgrid(range(img.size[0]), range(img.size[1])) 
    Z = 1 - numpy.asarray(img)/255 


    func = Axes3D.plot_surface if random.randint(0,1) == 0 else Axes3D.plot_wireframe 

    func(axes, X, -Y, Z, rstride=1, cstride=1, color=_rand_color()) 

    axes.set_zlim((-3, 3)) 
    axes.set_xlim((text_width * 1.1, text_width * 1.9)) 
    axes.set_ylim((-text_height * 1.9, -text_height* 1.1)) 
    axes.set_axis_off() 
    axes.view_init(elev=60, azim=-90) 

這就是好的,首先,它可以讓我創建之類的東西這樣的:
http://puu.sh/dfxcW/d9fc3f5c4e.jpg
http://puu.sh/dft1a/1d35f5c99a.png

我想,雖然做的是創建一個使用不同的字體和大小的每個字符驗證碼,並通過一個小的每個字符抵消y

由於地塊關閉它基於numpy陣列我試圖通過每個字符在文本中像這樣的循環:

prev_x = 0 
x = [] 
y = [] 
z = [] 
for character in text: 
    X, Y = numpy.meshgrid(range(prev_x, prev_x + img.size[0]), range(img.size[1])) 
    for v in X.tolist(): 
     x.append(v) 
    for v in Y.tolist(): 
     y.append(v) 
    # same for z 
prev_x += 40 # trying to offset the characters by an x value so they dont overlap 
x = numpy.array(x) 
# same for y and z to convert back to numpy array 
Axes3D.plot_wireframe(x, -y, z, rstride=1, cstride=1) 

這導致shape mismatch: two or more arrays have incompatible dimensions on axis 1.這混淆了我,因爲我覺得尺寸是準確的因爲我正在每個人上進行相同的呼叫。我是新來的numpy和3D的東西,所以如果有人有任何建議,請讓我知道!

+0

爲什麼不仔細檢查尺寸?您在此跳過一些代碼,因此無法準確調試。 – Ajean 2014-12-03 22:59:40

+0

我檢查了尺寸,它們不匹配。我沒有跳過代碼,我提供了一切。第二部分可以很容易地複製到第一部分 – ZWiki 2014-12-04 15:27:01

+0

你肯定已經跳過代碼 - 爲了得到這個工作,我不得不添加大量的導入,並替換你說的「#same for z」的行,並且諸如此類的東西。另外你的'Axes3D.plot_wireframe()'調用應該是'axes.plot_wireframe()',所以除非你真的沒有複製並粘貼真正的代碼到問題中,否則其他的東西就完全搞砸了。鑑於您的問題標題與您的問題內容不符,我不確定您要查找的是什麼。 – Ajean 2014-12-04 22:24:09

回答

2

在開始這件事的過程中,肯定有很多很酷的因素,它主要是在那裏;這裏是我爲了獲得隨機字體和可能的顏色每個字符的基礎上做出的mods。我確實改變了一些尺寸以適合我的屏幕。

from matplotlib.font_manager import findSystemFonts 
import random 
from PIL import ImageFont, Image, ImageDraw 
import numpy 
from mpl_toolkits.mplot3d.axes3d import Axes3D 
import matplotlib.pyplot as plt 

def rand_font(fonts=[], fontpaths=None, fontext='ttf', font_encoding='', min_size=24, max_size=36): 
    if fonts == []: 
     fonts = findSystemFonts(fontpaths, fontext) 
    requested_font = fonts[random.randint(0, len(fonts)-1)] 
    font_size = random.randint(min_size, max_size) 
    return ImageFont.truetype(requested_font, font_size, encoding=font_encoding) 

def create_captcha(text): 
    def _rand_color(): 
     colors = ['red', 'orange', 'purple', 'green', 'yellow'] 
     return colors[random.randint(0, len(colors)-1)] 

    # First font just gets the general offsets 
    font = rand_font() 
    text_width, text_height = font.getsize(text) 

    # Dont draw text here first 
    img = Image.new("L", (text_width * 3, text_height * 3), "white") 
    draw = ImageDraw.Draw(img) 

    fig = plt.figure(figsize=(12, 8)) 
    axes = Axes3D(fig) 

    # Do this way if you want random fonts AND colors 
    #================= 
    prev_x = 0 
    for character in text: 
     cfont = rand_font() 
     char_wid, char_height = cfont.getsize(character) 
     draw.text((prev_x+text_width, text_height), character, font=cfont) 

     X, Y = numpy.meshgrid(range(prev_x+text_width, prev_x+text_width+char_wid), 
           range(text_height, text_height+char_height)) 
     Z = 1 - numpy.asarray(img.crop((prev_x+text_width, text_height, 
             prev_x+text_width+char_wid, 
             text_height+char_height)))/255 
     axes.plot_wireframe(X, -Y, Z, rstride=1, cstride=1, color=_rand_color()) 

     prev_x += char_wid # trying to offset the characters by an x value so they dont overlap 
    #================= 

    # Do this way if you want just random fonts on each letter all one color 
    #================= 
    prev_x = 0 
    for character in text: 
     cfont = rand_font() 
     char_wid, char_height = cfont.getsize(character) 
     draw.text((prev_x+text_width, text_height), character, font=cfont) 

     prev_x += char_wid # trying to offset the characters by an x value so they dont overlap 

    X, Y = numpy.meshgrid(range(img.size[0]), range(img.size[1])) 
    Z = 1 - numpy.asarray(img)/255 
    axes.plot_wireframe(X, -Y, Z, rstride=1, cstride=1, color=_rand_color()) 
    #================= 

    axes.set_zlim((-3, 3)) 
    axes.set_xlim((text_width * 1.1, text_width * 1.9)) 
    axes.set_ylim((-text_height * 1.9, -text_height* 1.1)) 
    axes.set_axis_off() 
    axes.view_init(elev=60, azim=-90) 
    plt.show() 

create_captcha('TEST') 

的多字體的單色版本看起來是這樣的: test image all one color

和多字體多色版本是這樣的: test image multiple colors

這大概可以到製作看起來更好,如果你使它成爲一個表面,並改變視角/高度來避免背景...也許是這樣的: test image multiple colors with raised surface

至少應該是一個起點!