QRコードをQR分解する
概要
QRコードをQR分解します。
QRコードをQR分解する
QRコードを良く目にすると思います。例えばこんなのです。
これを見ると、まるで疎行列のように見えてきますね。なので、これを行列だと思ってQR分解したくなりますね。
QR分解とは、正方行列
と分解することです。なぜQR分解が必要かはその辺にいるガチ勢に聞いてください。ではさっそくQRコードをQR分解してみましょう。以下、Google Colabで実行することを想定していますが、何を使ってもかまいません。
まずはQRコードを作るのに必要なqrcode
をインストールしておきましょう。
!pip install qrcode
必要なライブラリをimportしましょう。
import qrcode
import numpy as np
import scipy.linalg as linalg
import matplotlib.pyplot as plt
from PIL import Image, ImageDraw
まずはQRコードを作ります。
BOX_SIZE = 10
qr = qrcode.QRCode(box_size=BOX_SIZE,border=0)
qr.add_data('Hello QR Code')
qr.make()
img = qr.make_image()
img
いきなりqrcode.make("Hello QR Code")
としてQRコードを作ることもできますが、そうするとまわりに「枠」ができてしまうので、それを消すためにQRCode
クラスのコンストラクタでboder=0
を指定しています。
ここから行列BOX_SIZE
倍縮小するだけです。
LX, LY = img.size
data = np.array(img.getdata()).reshape(LX, LY)
X, Y = LX//BOX_SIZE, LY//BOX_SIZE
A = np.zeros((X, Y))
for ix in range(X):
for iy in range(Y):
A[ix][iy] = 255-data[ix*BOX_SIZE][iy*BOX_SIZE]
あとで使うので、行列を可視化する関数を作っておきましょう。
def get_image(M):
M = np.abs(M)
M = M/np.max(M)
im = Image.new("L",(LX,LY), "white")
draw = ImageDraw.Draw(im)
for ix in range(X):
for iy in range(Y):
c = 255-int(M[iy][ix]*255)
sx = ix*BOX_SIZE
sy = iy*BOX_SIZE
draw.rectangle((sx, sy, sx+BOX_SIZE, sy+BOX_SIZE), fill=c)
return im
これで先ほどの行列
get_image(A)
できてるっぽいですね。
次に、linalg.qr
を呼ぶだけです。
Q, R = linalg.qr(A)
それぞれ可視化してみましょう。
get_image(Q)
これは直交行列のはず。パッと見ではわかりませんが、直交行列は、自身の転置と行列積を取ると対角行列になるという性質があります。確認してみましょう。
get_image(Q @ Q.transpose())
ちゃんと対角行列になっていますね。
次はR
を見てみましょう。
get_image(R)
こちらは上三角行列だということがわかりやすいですね。
さて、
get_image(Q @ R)
ちゃんと元に戻りました。
まとめ
QRコードを行列だと思ってQR分解してみました。本稿がQRコードをQR分解したい人の参考になれば幸いです。
Discussion