processing

ProcessingでQRコードを使う

はじめに

この記事はProcessing Advent Calendar 2017 24日目の記事です。
そういえば24日ってクリスマスイブですね。
何も考えずに参加したので、クリスマス感は薄い記事になると思います。

ProcessingでQRコードを使う

ProcessingでQRコードを使う為のライブラリは有名なところだと、
Daniel Shiffmanのqrcode-processingがあります。
ですが今回はZXingP5という、Java製のQRコードライブラリZXingのProcessingラッパーを使います。

このライブラリの特徴はQRコードの左上、右上、左下にある四角形の座標が取得できることです。
なのでこのようにQRコードの位置と大きさ、角度や文字情報などを取得することができます。
実はこのライブラリは自分が作ったので、コメントやIssueをいただけたら、
修正や改良をしたいと思います。

sample

ではでは使い方を書いていきます。

インストール

ここからZipをダウンロードして、解凍したディレクトリをZXingP5にリネームして、PROCESSING_PATH/libraryに配置、
もしくはターミナルで以下のコマンドを実行します。

cd PROCESSING_PATH/library
git clone https://github.com/enkatsu/ZXingP5.git

使い方

サンプルは3つ入っていて内容はこのようになっています。

  • WriterSample...文字列からQRコードのPImageを生成するサンプル
  • ReaderSample...QRコードの映ったPImageから文字列を読み取るサンプル
  • ReaderAdvancedSample...QRコードの映ったPImageから文字列と座標、大きさを読み取るサンプル

一つずつ説明しようと思ったんですが、
見直してみたら説明するほどコード量が多くないので、
ReaderAdvancedSampleをいじってクリスマスっぽくしようと思います。

元のReaderAdvancedSampleはこんな感じです。

import processing.video.*;
import com.github.endoh0509.zxingp5.*;

Capture cam;
QRReader reader;

void setup() {
  size(320, 240);

  cam = new Capture(this, 320, 240);
  cam.start();
  reader = new QRReader(this);
}

void draw() {
  if (cam.available() == true) {
    cam.read();
    image(cam, 0, 0);
    tint(255, 200);
    String txt = reader.decode(cam);
    if (txt != null) {
      PVector[] points = reader.getPoints();
      PVector lowerLeft = points[0];
      PVector upperLeft = points[1];
      PVector upperRight = points[2];

      // Get QR Code position
      PVector vec = PVector.sub(lowerLeft, upperRight);
      PVector center = PVector.mult(vec, 0.5).add(upperRight);

      // Get QR Code angle
      PVector qrVertical = PVector.sub(upperLeft, lowerLeft);
      PVector camVertical = new PVector(0, 1);
      float angle = atan2(qrVertical.y - camVertical.y, qrVertical.x - camVertical.x);
      if (angle < 0) { 
        angle += TWO_PI;
      }

      // Get QR Code scale
      float scale = PVector.dist(upperLeft, upperRight);

      noStroke();
      fill(255, 200);
      rectMode(CENTER);
      pushMatrix();
      translate(center.x, center.y);
      rotate(angle);
      rect(0, 0, scale, scale);
      popMatrix();

      textAlign(CENTER, CENTER);
      textSize(scale);
      fill(#193EA2);
      text(txt, center.x, center.y);
    }
  }
}

QRコードが読み取れた時だけ、
最初に載せた写真のように、
QRコードの位置と大きさ、角度を使って四角形を描画して、
その上に文字情報を表示しています。

これに画像をURLからロードしてくる感じにするとこんな風になります。

import processing.video.*;
import com.github.endoh0509.zxingp5.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

Capture cam;
QRReader reader;
PImage img;

void setup() {
  size(320, 240);
  imageMode(CENTER);
  cam = new Capture(this, 320, 240);
  cam.start();
  reader = new QRReader(this);
  img = null;
}

void draw() {
  if (cam.available() == true) {
    cam.read();
    image(cam, width / 2, height / 2);
    String url = reader.decode(cam);
    if (url != null) {
      if (img == null && isImageURL(url)) {
        img = loadImage(url);
      } else if (img != null) {
        PVector[] points = reader.getPoints();
        PVector lowerLeft = points[0];
        PVector upperLeft = points[1];
        PVector upperRight = points[2];

        // Get QR Code position
        PVector vec = PVector.sub(lowerLeft, upperRight);
        PVector center = PVector.mult(vec, 0.5).add(upperRight);

        // Get QR Code angle
        PVector qrVertical = PVector.sub(upperRight, upperLeft);
        PVector camVertical = new PVector(0, 1);
        float angle = atan2(qrVertical.y - camVertical.y, qrVertical.x - camVertical.x);
        if (angle < 0) { 
          angle += TWO_PI;
        }

        // Get QR Code scale
        float scale = PVector.dist(upperLeft, upperRight);

        pushMatrix();
        translate(center.x, center.y);
        rotate(angle);
        image(img, 0, 0, scale, scale);
        popMatrix();
      }
    }
  }
}

boolean isImageURL(String urlStr) {
  String pattern = "(http(s?):/)(/[^/]+)+" + "\\.(?:jpg|gif|png)";
  Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
  Matcher m = p.matcher(urlStr);
  return m.find();
}

スクリーンショット 2017-12-21 22.33.11.png

使ったQRコードはこちらです。
(実際に使ったのとQRのバージョンが違うから少し違いますが)
だいぶクリスマスっぽくなりましたね。

QR_Code1513877100.png

ではではメリークリスマス。
そして良いお年を。