LoginSignup
17
17

More than 3 years have passed since last update.

【QRコード入門】作成・読込からリアルタイムカメラ取得QRコードのDCGAN画像変換で遊んでみた♪

Posted at

最近、QRコードを使って決済するのがはやりなので、遅まきながらQRコードで遊んでみました。
考えていたより、簡単にかつ処理も早いのでいろいろ使えそうです。
今回は、QRコードについて作成は参考①、読み込みは参考②を参考に実施しました。また、カメラでの読み込みとして参考③を参考に実施しました。
【参考】
Python, Pillow, qrcodeでQRコード画像を生成、保存@note.nkmk.me
pythonで画像からQRコードを読み込む@python入門ブログ
PYTHONでMACのカメラからQRコードを読んでみた@FROM UMENTU IMPORT STUPID

やったこと

・QRコードを使ってみる生成・読込
・生成QRコードをカメラ読み込み処理をする
・DCGAN生成パラメータのQRコード画像を作成する
・DCGANのQRコード画像をカメラ読み込みしつつ、リアルタイム画像動画を表示する

・QRコードを使ってみる生成・読込

これは参考①、②のとおりだが、簡単に作成したものをまとめておく
まず、今回主に使うqrコード関係のインストールは以下のとおり

>pip install --upgrade pip
>pip install opencv-python
>pip install pillow
>pip install pyzbar
>pip install qrcode

早速、QRコード生成のコードを見てましょう。

import qrcode
from PIL import Image
qr = qrcode.QRCode(box_size=1)
qr.add_data('最近、QRコードを使って決済するのがはやりなので、遅まきながらQRコードで遊んでみました。')
qr.make()
img_qr = qr.make_image()
img_qr.save('./gen_images/qr_lena_1.png')

これでbox_sizeを1,2,5,10と変更すると以下のような出力となる。

box_size size QRコード
1 57x57 qr_lena_1.png
2 114x114 qr_lena_2.png
5 285x285 qr_lena_5.png
10 570x570 qr_lena_10.png

QRコードは以下のパラメータを持つ(詳細はcr.pngを見て下さい)
・バージョン(種類)は、1から40まで設定;21x21ピクセルから177x177ピクセルまで
・ピクセルのサイズをbox_sizeで変更できる
・情報量に応じて最小のバージョンがデフォルトに選ばれるが指定もできる
誤り訂正機構を選べるが、サイズは大きくなる
...
これらの出力制御は以下のような感じらしいです。参考①を参照願います。

qr = qrcode.QRCode(
    version=12,
    error_correction=qrcode.constants.ERROR_CORRECT_H,
    box_size=2,
    border=8
)

一方読み込みの基本も簡単で、以下のとおり

read_qr.py
# -*- coding: UTF-8 -*-
from pyzbar.pyzbar import decode
from PIL import Image

# 画像ファイルの指定
image = './gen_images/qr_lena_1.png'

# QRコードの読取り
data = decode(Image.open(image))
input=data[0][0].decode('utf-8', 'ignore')
print(input)

一番小さいのも無事に入力通りの文章が得られました。

>python read_qr.py
最近、QRコードを使って決済するのがはやりなので、遅まきながらQRコードで遊んでみました。

・生成QRコードをカメラ読み込み処理をする

コードはほぼ参考②のとおりで、以下のとおり
ちょっと、解説いれます。
利用するLibです。

from pyzbar.pyzbar import decode
from pyzbar.pyzbar import ZBarSymbol
import cv2
import numpy as np

以下がQRコードのコントラスト調整用の関数です。

def edit_contrast(image, gamma):
    """コントラスト調整"""
    look_up_table = [np.uint8(255.0 / (1 + np.exp(-gamma * (i - 128.) / 255.)))
        for i in range(256)]
    result_image = np.array([look_up_table[value]
                             for value in image.flat], dtype=np.uint8)
    result_image = result_image.reshape(image.shape)
    return result_image

以下がカメラ入力と読み取りの処理です。
num0=input[1:len(input)-1]は読み込んだ一文字目と最後の文字を削除していますが、これは後で、[-1.0,1.0]のような形式のデータを読むために入れていますが、上記の文章などではいらないのでコメントアウトしています。

if __name__ == "__main__":
    capture = cv2.VideoCapture(1)
    cv2.namedWindow('frame')
    if capture.isOpened() is False:
        raise("IO Error")
    ret, frame = capture.read()
    while True:
        if ret == False:
            continue
        # グレースケール化してコントラストを調整する
        gray_scale = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        image = edit_contrast(gray_scale, 5)
        # 加工した画像からフレームQRコードを取得してデコードする
        codes = decode(image)
        if len(codes) > 0:
            input=codes[0][0].decode('utf-8', 'ignore')
            num0=input  #[1:len(input)-1]
            # コード内容を出力
            print(num0)
            font = cv2.FONT_HERSHEY_SIMPLEX
            cv2.putText(frame,str(input),(10,300), font, 2,(255,255,255),2,cv2.LINE_AA)
        cv2.imshow('frame',frame)
        if cv2.waitKey(1) >= 0:
            break
        ret, frame = capture.read() 

実は上記のコードだと、数値などは出力できますが、日本語は出力できません。
日本語部分は、????みたいな文字化けがでます。
ということで、日本語は以下のようなコードになります。
【参考】
Python + OpenCV でWindowsの日本語フォントを描画する
参考④のコードを使って日本語の場合は以下のようになります。
QR_code/camera_qr_jpn.py
このコードで以下のようなカメラ画像が得られます。
※起動に少し時間がかかります。QRコードを認識しないと画像がでません
res.png

・DCGAN生成パラメータのQRコード画像を作成する

先日のDCGANのパラメータをQRコードにして画像をカメラ画像上に出現させようというアイディアです。ということで、DCGANのパラメータのQRコードを連続作成しました。
以下のようにnoise_listに書かれているのがそのパラメータです。

import qrcode
from PIL import Image

img_bg = Image.open('./gen_images/generator_22000_1.png')
noise_list=['[-1. -1.0]','[-1.  -0.9]','[-1.  -0.8]','[-1.  -0.7]','[-1.  -0.6]','[-1.  -0.5]','[-1.  -0.4]','[-1.  -0.3]','[-1.  -0.2]','[-1.  -0.1]']
img_bg =img_bg.resize(size=(640,640), resample=Image.NEAREST)
for noise in noise_list:  #='[-1. -1.]'
    qr = qrcode.QRCode(box_size=10)
    qr.add_data(noise)
    qr.make()
    img_qr = qr.make_image()
    img_qr =img_qr.resize(size=(img_bg.size[0], img_bg.size[1]), resample=Image.NEAREST)
    pos = (img_bg.size[0] - img_qr.size[0], img_bg.size[1] - img_qr.size[1])
    img_bg.paste(img_qr, pos)
    img_bg.save('./gen_images/qr_img_'+noise+'.png')

上記により生成された連続したQRコードのGifアニメが以下です。
qr_img_.gif

・DCGANのQRコード画像をカメラ読み込みしつつ、リアルタイム画像動画を表示する

全体のコードは以下に置きました。
QR_code/qr_dcgan_generate_one.py

まず、DCGANで画像生成する部分を説明します。
コードは以下の通りとなっています。
ここではモデルを定義してnoiseを使ってgenerated_imagesを生成します。
読み取りが[-1.0 -1.0]のような文字データで、そこから-1.0 -1.0だけ切り出されて取得できます。そこで、最初の4桁と5桁目から9桁目を取得して、noiseに入力しています。

def generate(BATCH_SIZE=1,num0=[1,0]):
    g = generator_model()
    g.compile(loss='binary_crossentropy', optimizer=Adam(lr=0.0002, beta_1=0.5))
    g.load_weights('./gen_images/generator_22000.h5')
    noise = np.random.uniform(size=[BATCH_SIZE, 2], low=-1.0, high=1.0) ##32*32
    x=np.float(num0[0:3])
    y=np.float(num0[5:9])
    print(x,y)
    noise[0]=[x,y]  #[-1,0.5]
    generated_images = g.predict(noise)
    return generated_images

次にnoise_getを説明します。
上記と同じようなコードですが、ここでは必要な機能だけ置いています。
つまり、ほぼQRコードを読み込むだけで、読み込んだ文字列から最初と最後の[]を削除して返すようにしています。

def noise_get(ret,frame):
    while True:
        if ret == False:
            continue
        # グレースケール化してコントラストを調整する
        gray_scale = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        image = edit_contrast(gray_scale, 5)
        # 加工した画像からフレームQRコードを取得してデコードする
        codes = decode(image)
        if len(codes) > 0:
            input=codes[0][0].decode('utf-8', 'ignore')
            num0=input[1:len(input)-1]
            print(num0)
            return num0,frame
        if cv2.waitKey(1) >= 0:
            break
        ret, frame = capture.read()

そして、メインは以下のとおりとしました。
ここで最大の工夫は、取得した画像を一度保存して再度読みだしています。
そのとき表示はせずに単に保存だけしています。こうすることによりImageで扱えるフォーマットにしています。

        plt.imshow(frame)
        plt.savefig('./gen_images/frame.png')
        frame = Image.open('./gen_images/frame.png')

その結果、画像合成を簡単に実施しています。
しかも、mask = Image.new("L", frame.size, 1)のこの1を変更することにより、それぞれの透過度を状況により変更できます。
そして、imgArray = np.asarray(im)で再度numpy配列に変更し、取得したテキストを重畳してcv2.imshowします。

if __name__ == "__main__":
    while True:
        capture = cv2.VideoCapture(1)
        cv2.namedWindow('frame')
        if capture.isOpened() is False:
            raise("IO Error")
        ret, frame = capture.read()
        num0,frame=noise_get(ret,frame)
        generated_images=[]
        generated_images=generate(BATCH_SIZE=1,num0=num0)
        plt.imshow(frame)
        plt.axis("off")
        plt.savefig('./gen_images/frame.png')
        plt.close()
        frame = Image.open('./gen_images/frame.png')
        plt.imshow(generated_images[0])
        plt.axis("off")
        plt.savefig('./gen_images/generated_images.png')
        plt.close()
        img = Image.open('./gen_images/generated_images.png').resize(frame.size)
        mask = Image.new("L", frame.size, 1)
        im = Image.composite(frame, img, mask)
        im.save('./gen_images/qr_'+str(num0)+'.png')
        imgArray = np.asarray(im)

        font = cv2.FONT_HERSHEY_SIMPLEX
        cv2.putText(imgArray,str(num0),(100,200), font, 2,(255,255,255),2,cv2.LINE_AA)
        cv2.imshow('frame',imgArray)
        if cv2.waitKey(1) >= 0:
            break

以下のような出力がでます。
realTime_transform_qr.jpg
上記のQRコードを読み込んで、以下のような画像が得られました。
※ちょっと画像が綺麗じゃないけど、このまま貼っておきます
qr_pic_.gif

まとめ

・QRコードの読み書きで遊んでみた
・カメラでリアルタイムで読み書きできた
・DCGANを利用してカメラ取得のQRコードからリアルタイム画像変換ができた

・いろいろなシーンで利用可能なのでさらなる応用をしたいと思う

17
17
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
17