美文网首页
码中码之图片之二维码

码中码之图片之二维码

作者: 小温侯 | 来源:发表于2018-07-21 00:10 被阅读64次

    对图片我们能做些什么?

    这次熟悉了两个很重要的关于图片处理的库:PIL,三个关于二维码的库:qrcodeqrcode-terminallilithqrtoolspyqrcode

    PIL全称Python Imaging Library,可以为Python解释器添加图片处理能力。它和它包含的模块一起几乎可以实现所有你想要对图片的操作。

    这里举个例子,例子的来源为:https://zhuanlan.zhihu.com/p/34658133。作用是将一张图片处理成九等份,方便发朋友圈LOL。

    image = Image.open('pencil.jpg')
    
    # (1)将图片补充为正方形,变成以长边为准
    width, height = image.size
    edge = max(width, height)
    
    # 因为图片之后会被分为9份,这里保证边长是3的倍数
    if edge % 3 != 0:
        edge = edge + 3 - edge%3
    
    new_image = Image.new(image.mode, (edge, edge), color='white')
    
    if width < height:
        new_image.paste(image, ((edge-width)//2, 0))
    else:
        new_image.paste(image, (0, (edge-height)//2))
    
    # (2)将图片切割成3x3份
    n = edge / 3
    boxes = []
    
    # 分割,数学问题
    for i in range(3):
        for j in range(3):
            boxes.append((i*n, j*n, (i+1)*n, (j+1)*n,))
    
    subimages = [image.crop(box) for box in boxes]
    
    # (3)保存分割后的图片
    idxs = [1,4,7,2,5,8,3,6,9]
    
    for subimage, idx in zip(subimages, idxs):
        subimage.save("{0:s}-{1:d}.{2:s}".format(image.filename.split('.')[0], idx, image.format))
    

    二维码

    做爬虫不可避免的会遇到二维码,二维码的原理这里就不说了。个库分别对应三种不同的功能,几乎可以满足关于二维码的所有要求。

    • qrcodepyqrcode,包含几乎关于二维码的常用操作,多用于创建。
    • qrcode-terminallilith,可以将一个字符串转换为二维码并在终端上打印出来,这个库用到了qrcode的部分功能。pyqrcode也支持二维码打印到终端,但是对象是Linux的终端。
    • qrtools,解析一个二维码图片的内容

    qrcode

    生成一个内容为ipaimg二维码对象,并保存为qrcode.jpg。这个img也可以作为qrcode-terminal库的参数,解析之后可以在终端上打印一个二维码。

    import qrcode
    ipa="https://journal.ethanshub.com/"
    qr = qrcode.QRCode(
        version = 2,  
        error_correction = qrcode.constants.ERROR_CORRECT_L,  
        box_size = 10,  
        border = 1,  
    )  
    qr.add_data(ipa)  
    qr.make(fit=True)
    img = qr.make_image( fill_color="black", back_color="white")
    img.save('qrcode.jpg')
    

    qrcode2terminal - windows

    但是做爬虫,接触最多的其实是扫描二维码这个操作,之前模拟淘宝登陆的时候,我是将二维码保存到本地再手动扫描,这里我准备把二维码图片解析并打印到终端上,这样就可以直接扫描了。

    另外,目前看的几个在终端打印二维码的都是针对Linux终端的,我这个例子可以在windows cmd里使用,亲测有效。

    qrcode-terminal中,关于打印部分是这样的:

    def qr_terminal_str(str,version=1):
        qr = qrcode.QRCode(version)
        qr.add_data(str)
        qr.make()
        output = white_block*(qr.modules_count+2) + new_line
        for mn in qr.modules:
            output += white_block
            for m in mn:
                if m:
                    output += black_block
                else:
                    output += white_block
            output += white_block + new_line
        output += white_block*(qr.modules_count+2) + new_line
        return output
    

    因为它所使用的qr图示由qrcode库生成的,因此它可以直接访问modules_count获取每一行有多少个方块(包括黑色的和白色的),但是现在我面临的情况是从图片中读取二维码,如果采用PIL打开一张图片,那么可以使用getpixel方法获取图片的某个点的像素值,因为是二维码,所以这个值只能是(0,0,0)或(255,255,255),非黑即白。

    如果采取遍历所有像素点的方法,遇到白的打印一个white_block,黑的打印一个black_block,这样是可行的,但是打印出来的二维码会非常大,一般屏幕是显示不出来的。解决这个问题的核心要素是如何获取每行的方块数

    qrcode-scan.jpg

    如图,现在有一张二维码图片,我用一条直线从左往右逐个像素扫描。每右移一个像素,就会从上往下获取每个像素的值,因为是黑白的,所以这个值只能是1或者0,将这些值累加起来,这样每扫一行就会得到一个类似于10101010101010100110010000的字符串。继续往右扫,每次都会得到一个字符串,将这个字符串和上一个字符串比较,如果相同,说明还没有到移动满一个方块;如果不同,那么横向的位移就是方块的像素大小,用图片的宽度除以方块的大小就可以获得方块的数量了。代码如下:

    # 打开图片
    img = Image.open('qrcode.jpg')
    text = ''
    sample = ''
    cnt = 0
    # 开始扫描
    for w in range(img.width):
        tmp = ''
        for h in range(img.height):
            res = img.getpixel((w, h))
            if res:
                tmp += '1'
            else:
                tmp += '0'
    
        if sample == '':
            sample = tmp
    
        if sample == tmp:
            cnt += 1
        else:
            break
    
    # 得到方块大小和每一行的方块数量
    cell_size = cnt
    cell_num  = img.width//cnt
    
    # 打印到终端
    # 注意这里会给原先的二维码包裹一个边框,看起来舒服点
    # 取像素点的时候取的是每个方块的中心
    white_block = '▇'
    black_block = ' '
    new_line = '\n'
    text +=  white_block*(cell_num+2) + new_line
    for w in range(cell_num):
        text += white_block
        for h in range(cell_num):
            res = img.getpixel((w*cell_size+cell_size/2, h*cell_size+cell_size/2,))
            text += white_block if res == 0 else black_block
        text += white_block + new_line
    text +=  white_block*(cell_num+2) + new_line
    print (text)
    

    打出来的效果是这样的,我试了下用iphone的相机可以识别:

    qrcode-res.jpg

    qrtools

    qrtools依赖于一个叫zbar的外部库,这个库不能直接用pip安装,官方据说只支持到Python 2.7。windows上我没成功,好在解析二维码这个功能其实需求不大,所以就暂且放一边了。

    from qrtools.qrtools import QR
    qr = qrtools.QR()
    qr.decode("qrcode.jpg")
    print(qr.data)
    

    相关文章

      网友评论

          本文标题:码中码之图片之二维码

          本文链接:https://www.haomeiwen.com/subject/orycmftx.html