歩いたら休め

If the implementation is easy to explain, it may be a good idea.

【Python2】Python2.7 + zbar + PILでプリチケのQRコードを隠すプログラム

こちらのプログラムがひとまず完成しました。

kiito.hatenablog.com

やっている事自体は簡単なので、zbarを使えれば他の言語でも可能です。そのためこんな感じで

nlab.itmedia.co.jp

カメラアプリが作れればいいのですが、その辺の技術はサッパリなのでどうかな…。 とりあえずコマンドラインツール化してgithubにでもアップしておこうかしら。

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import math
import zbar
from PIL import Image, ImageOps

class maskPritikeQRcode:
    def __init__(self):
        self.set_output_path('./output.png')

    def set_output_path(self, path):
        self.output_path = path

    def set_ticket_path(self, path):
        self.ticket_path = path
        
    def read_ticket_data(self, path):
        ticket = Image.open(path)
        # 画像合成用にカラーで読み込む
        self.ticket = ticket.convert('RGBA')
        # qrコード解析用に白黒で読み込んだ上、色を反転する(プリチケのQRコードは白黒逆らしい)
        self.ticket_inverted = ImageOps.invert(ticket.convert('L'))
    
    def read_stamp_data(self, path):
        self.stamp = Image.open(path).convert('RGBA')
        
    def mask_qrcode(self):
        image = self._scan_qrcode(self.ticket_inverted)
        for symbol in image:
            # symbol.locationでQRコードの範囲が取れる
            self._paste_stamp(symbol.location)
        new_image = self.ticket.convert('RGB').convert('P', palette=Image.ADAPTIVE)
        new_image.save(self.output_path, "PNG")
    
    def _scan_qrcode(self, ticket):
        scanner = self._zbar_scanner()
        raw = ticket.tostring()
        (width, height) = ticket.size
        image = zbar.Image(width, height, 'Y800', raw)
        scanner.scan(image)
        return image
    
    def _zbar_scanner(self):
        scanner = zbar.ImageScanner()
        return scanner
    
    def _paste_stamp(self, location):
        xy_coodinate = self._get_qr_location(location)
        shaped_stamp = self._get_shaped_stamp(location)
        self.ticket.paste(shaped_stamp, xy_coodinate, shaped_stamp) # 貼り付け
        
    def _get_qr_location(self, location):
        return tuple(min(x) for x in zip(*location))
    
    def _get_shaped_stamp(self, location):
        angle = self._get_qr_angle(location)
        size = self._get_qr_size(location)
        return self.stamp.resize(size).rotate(angle)
    
    def _get_qr_angle(self, location):
        # TODO:: qrコードが回転している場合をテストする
        left_line = sorted(location, key=lambda x:x[0])[0:2]
        vartical = [x - y for x, y in zip(*left_line)] # zip(*args)で転置を取れる
        return math.atan2(*vartical[::-1]) * 180 / math.pi + 90
    
    def _get_qr_size(self, location):
        return tuple(max(x) - min(x) for x in zip(*location))

if __name__ == '__main__':
     p = maskPritikeQRcode()
     p.read_ticket_data('pritike.jpg')
     p.read_stamp_data('stamp.png')
     p.mask_qrcode()