iPhone の「カメラ入力」でおもしろビデオカメラを作ろう

5 min読了の目安(約5100字TECH技術記事

この記事は Processing Advent Calendar 2020 の8日目の記事です。

今日は、先月リリースしたばかりの RubySketch というアプリに、カメラ入力機能を追加したのでその紹介をしたいと思います。

はじめに

まずは簡単にアプリの紹介をさせてください。

一言でいうと、スマホで手軽に Ruby + Processing しようというコンセプトのアプリです。

ストア画像

アプリには簡易的なテキストエディタと Ruby の実行環境を組み込んであり、Ruby から呼べる Processing 互換の関数[1]も実装してありますので、Processing IDEp5.js Web Editorと同じ感覚でクリエイティブコーディングをすることが出来ます。

Rects.rb
作例1 Rects.rb

Clock.rb
作例2 Clock.rb

Pong.rb
作例3 Pong.rb

PerlinNoise
作例4 PerlinNoise.rb

まだ機能として公開はしてませんが、物理演算ライブラリの Box2D も組み込んであったりします。

現在はリリースしたばかりということで Processing の基本的な関数を優先して実装しておりまだまだ未実装の機能も多いのですが、createGraphics() なんかも使えたりと割と本気で Processing 完全互換を目指している[2]ので、Processing や p5.js が使える方[3]ならわりとすんなりと使えるアプリになっていると思います。

実装済みの Processing 互換関数の一覧

width, height, colorMode, angleMode, rectMode, ellipseMode, imageMode, fill, stroke, strokeWeight, strokeCap, strokeJoin, noFill, noStroke, textFont, textSize, textWidth, textAscent, textDescent, textAlign, background, point, line, rect, ellipse, circle, arc, square, triangle, quad, curve, bezier, text, image, copy, translate, scale, rotate, pushMatrix, popMatrix, resetMatrix, pushStyle, popStyle, push, pop, setup, draw, key, mousePressed, mouseReleased, mouseMoved, mouseDragged, touchStarted, touchEnded, touchMoved, windowWidth, windowHeight, frameCount, frameRate, displayDensity, mouseX, mouseY, pmouseX, pmouseY, touches, loop, noLoop, redraw, abs, ceil, floor, round, pow, sq, mag, dist, norm, lerp, map, min, max, constrain, radians, degrees, sin, cos, tan, asin, acos, atan, atan2, noise, random, createVector, createGraphics, loadImage

カメラ入力の Capture クラス

で、アプリの最初のリリースから約一ヶ月が経ち、先週無事に新バージョンの v1.1 を出すことができました。

その v1.1 で追加したのがスマホのカメラから画像を取得する Capture クラスです。
Capture クラスを使ったスクリプトの実行例はこんな感じになります。

これくらいのものがこんな感じで 20行程度で書けるというのはさすが Processing です。

DelayCamera.rb
# スクリーンの幅と高さを取得
w, h = width, height

# カメラ画像を60フレーム分保存する用の画像60枚
images = 60.times.map {createGraphics w, h}

# カメラから画像の取得開始
cam = Capture.new w, h
cam.start

# 毎フレーム呼ばれる描画処理
draw do
  # 一番最後の画像を先頭に移動
  images.unshift images.pop

  # 先頭の画像にカメラ画像を保存
  images.first.tap do |g|
    g.beginDraw
    g.image cam, 0, 0
    g.endDraw
  end

  # 画面全体をクリア
  background 0

  # 60枚の画像を新しい方から順に、上から1/60の高さずつ描画する
  segment_h = h / images.size
  images.each.with_index do |g, i|
    y = i * segment_h
    copy g, 0, y, w, segment_h, 0, y, w, segment_h
  end
end

ということでさらにいくつかバリエーションを作ってみました。

時間差カメラ

60枚のカメラ画像を保存しておいて少しずつ遅らせた映像を描画するのは同じですが、カメラ全体を4枚表示しています。これはこれでまた違った感じでになりました。
約1秒の映像をずらして表示していますが、もっと長い時間差で表示させても面白そうです。

DelayCamera2.rb
w, h = width, height
images = 60.times.map {Graphics.new w, h}
cam = Capture.new w, h
cam.start

draw do
  images.unshift images.pop
  images.first.tap do |g|
    g.beginDraw {g.image cam, 0, 0}
  end
  background 0
  ww, hh = w / 2, h / 2

  # 左上に最新の映像を描画
  copy images[0], 0, 0, w, h, 0, 0, ww, hh

  # 右上に約 0.333 秒前の映像を描画
  copy images[19], 0, 0, w, h, ww, 0, ww, hh

  # 左下に約0.666秒前の映像を描画
  copy images[39], 0, 0, w, h, 0, hh, ww, hh

  # 右下に 1秒前の映像を描画
  copy images[59], 0, 0, w, h, ww, hh, ww, hh
end

鏡カメラ

シンプルですが鏡効果です。[4]
カメラの左半分を反転して右側にも描画するだけと実装も 10行程度と単純な割に、特にフロントカメラで実装すると子供にも受けが良いのでコスパの良いスクリプトですw

MirrorCamera.rb
w, h = width, height
cam = Capture.new w, h
cam.start

draw do
  background 0
  ww = w / 2

  # 左側にカメラの左半分を描画
  copy cam, 0, 0, ww, h, 0, 0, ww, h

  # 右側にカメラの左半分を反転して描画
  copy cam, 0, 0, ww, h, w, 0, -ww, h
end

まとめ

今後は Shader クラスも追加予定[5]で、カメラから取得した映像にリアルタイムでエフェクトを掛けたりもできるようにする予定です。

こんな感じでカメラ機能に限らず、いつでもどこでもスキマ時間に iPhone で手軽にクリエイティブコーディングできるというのは結構楽しいので、面倒な環境整備も不要な RubySketch アプリ是非使ってみてください!無料です!

明日は?

アドベントカレンダーの明日 9日目は nagayama さんです。
YouTube Live で何かされるそうなのでどうぞお楽しみに!

脚注
  1. ちなみに Processing との互換性を優先した結果、関数名なども Ruby の文化で標準的な snake_case() ではなく、Processing / p5.js に合わせて lowerCamelCase() にしてます ↩︎

  2. 中身の実装としては OpenGL で作った独自実装なので、JRuby から Java の Processing 関数を呼ぶ系とはちょっと違います ↩︎

  3. Processing の学習やプログラミング自体の学習にも使っていただけるかもしれません ↩︎

  4. 昔ドリフ?がやっていた、鏡を使って人が浮くように見せるコントを思い出しますw ↩︎

  5. Shadertoy 的な GLSL フラグメントシェーダーだけを書くモードも入れたいですね ↩︎