スクリーンショット 2026-11-13 19.18.46

以前から、インカメラで目の位置を追いかければ、透けて見える壁紙や、写真が立体に見える壁紙が作れるのでは、と考えていました。ただ、計算やキャリブレーションが面倒で手を付けずにいました。今回それを Claude Code で1つのアプリにまとめたのが「透過・3D壁紙」です。

Android 11 以上(arm64)
開発機: OPPO Find N6
処理はすべて端末内

何をするアプリか

よく透明なスマホのようなコンセプト動画がありますが、それを実現しようとしたアプリ。当初は光学迷彩壁紙という名前にしようかと思っていましたが商標上断念しました。
カメラの映像をそのまま全画面に出しても、透けては見えません。カメラの位置と目の位置が違い、画角も違うからです。透けて見せるには、画面を窓枠とみなし、今の目の位置からその窓越しに見える範囲だけを描く必要があります。

図にすると次の通りです。図の距離は縮めています。

see_through_geometry_static

このアプリには、表示する内容が3つあります。

  • 透過:メインカメラの景色を、目の位置に合わせて射影して表示します。画面が透けているように見えます。
  • 写真3D:選んだ1枚の写真から奥行きを推定し、頭を動かすと手前の物と奥の物がずれて見える、疑似的な3D表示にします。
  • 人物+透過:写真に写った人だけを切り抜いて立体にし、透けて見える本物の景色の上に重ねます。窓の向こうに、写真の人が立っているように見えます。

どれもホーム画面のライブ壁紙に設定できます。とはいえカメラを常時使うので実用的ではなく、ネタアプリです。写真3D は、カメラを使わずにジャイロの傾きだけで視差を出す設定もあり、バッテリーへの負担が小さくなります。

目の3次元の位置を測る

インカメラの映像から MediaPipe の Face Landmarker で顔の特徴点を取り、両目の位置を求めます。距離は両目の間隔(瞳孔間距離)から推定し、顔の向きで補正します。虹彩の大きさから推定するより、検出の誤差の影響が小さかったためです。

透けて見える正しい絵は、片方の目の位置でしか成り立ちません。そこで基準にする目を「両目の中間・右目・左目」から選べるようにしました。利き目を選ぶと、両目を開けたままでも自然に見えます。

スクリーンショット 2026-11-13 19.23.18

手ブレはジャイロで打ち消す

手に持つと、端末は細かく回転します。目は空間の中ではほぼ止まっているので、ジャイロで求めた端末の姿勢を使い、目の位置を空間に固定した座標で扱います。端末が回った分だけ、端末から見た目の位置を即座に補正できます。

遅れとの戦い:表示される瞬間の目で描く

実機で測ると、カメラで撮ってから目の位置が出るまでに約 110〜135ms かかっていました。描いてから画面に光るまでにも、さらに数フレームかかります。頭を動かすと、映像が後からついてくる感じが残りました。

そこで、目の位置を「位置と速度」で推定するカルマンフィルタ(等速度モデル)に置き換え、画面に表示される時刻まで速度で進めた位置を描くようにしました。止まっているときに速度の誤差で揺れないよう、ある程度の速さで動いているときだけ先読みを効かせます。検出は 1 秒に 20〜25 回なので、検出のたびに位置を直すと表示がカクつきます。直した分は約 50ms かけて少しずつ反映します。

写真を立体にする

写真3D では、1枚の写真から奥行きを推定し、凹凸のある格子(メッシュ)として描きます。写真の各点は、標準の目の位置(画面の正面 35cm)から見ると元の写真とまったく同じに見えるよう、その目から伸ばした線の上に置きます。正面から見ると元の写真のまま、頭を動かすと奥行きに応じてずれて見えます。

奥行きの推定は端末の中で

奥行きの推定には Depth Anything V2 の Small モデル(int8 量子化、約 27MB)を使い、ONNX Runtime で端末内で動かしています。Depth Anything V2 は Small だけが Apache License 2.0 で、商用でも使えます。

推定した奥行きは、人の輪郭のような境目でなだらかにぼやけます。この中間の値の部分は、視点を動かすと引き伸ばされてギザギザになります。そこで写真の色と、MediaPipe の人物切り抜きモデルで求めた人の範囲を手がかりに、近くの画素の重み付き中央値で境目をくっきりさせています。

境目は2層で描く

手前の物と奥の物の境目では、視点を動かすとメッシュが大きく引き伸ばされます。そこで、写真を「前景」と、手前の物を取り除いたと仮定した「背景層」の2層で描きます。前景の引き伸ばされた部分は、シェーダーで奥行きの等高線に沿って切り抜きます。三角形ごとに捨てると格子の形のギザギザになるので、三角形の中を通る線で切って、なめらかにつなげています。

「透ける」と「壁」の問題

背景層づくりは何度もやり直しました。最初は隙間を「周りでいちばん奥の面」で埋めていました。すると、顔と髪の間の隙間から奥の花畑が見え、人が透けているように見えました。

次に「すぐ後ろの面」で埋めるようにすると、透け感は消えました。ただし今度は、輪郭から一定の幅のところに段差ができ、視点を大きく動かすと手前の物に厚みのある側面の壁があるように見えました。

最終的には、手前の物の内側も「隙間が開きうる幅」まで後ろの面に下げる形に落ち着きました。幅は、手前と奥の奥行きの差に比例させています。隠れていた部分の色は、すぐ後ろが遠くの背景なら描き足しモデルの MI-GAN で模様を続けます。手の後ろの体のように別の手前の物なら、奥行きが近い画素の色だけで埋めます。

スクリーンショット 2026-11-13 19.20.15

ぼかしのピントは目に合わせる

奥行きに応じたぼかしも付けられます。写真に人の目があれば、顔の特徴点から目の位置を探し、その奥行きにピントを合わせます。ポートレートらしい見え方になります。

写真の人を、本物の景色の中に立たせる

透過と写真3D がそろうと、「写真の人だけを、今いる場所の景色に重ねたら」という組み合わせが自然に浮かびます。部品はほとんどそろっていました。メインカメラの景色を窓として描き、その上に、写真の人だけを残した立体のメッシュを重ねます。

残す範囲は、写真に写った人と、設定した奥行きより手前の物です。人の範囲は、写真3D で境目を整えるのに使っていた人物の切り抜きモデルの結果を、そのまま保存して使い回しています。

やってみると、写真3D のための工夫が、ここではことごとく裏目に出ました。

  • 体に穴が空く:写真3D では、奥行きの境目で引き伸ばされた部分を捨て、後ろの背景層を見せています。後ろが本物の景色になると、捨てた所がそのまま穴になり、コートの内側から景色が見えました。人物+透過では、この処理を止めました。
  • 輪郭が階段状になる:切り抜いた外側の奥行きが元の写真の遠い背景のままだと、輪郭をまたぐ格子が引き伸ばされ、格子の大きさの段差が出ます。外側は描かないので、奥行きはどうでもよいはずの場所です。そこで、外側を近くの人の奥行きで埋めました。推定した奥行きは輪郭の少し内側から下がり始めるので、人の範囲を数画素縮めてから埋めます。
  • 輪郭そのものが粗い:人の範囲は奥行きと同じ粗い格子で求めているので、拡大すると輪郭がギザギザでした。読み込むときに、写真の色を手がかりにする guided filter で、長い辺 1024px まで細かくしています。範囲の境目が写真の色の境目に吸い付き、コートの縁がなめらかになりました。
  • 髪と服の境目が段になる:人の中の奥行きの段差も、捨てずに引き伸ばすので階段に見えます。切り抜き用の奥行きを少しぼかし、格子数個分のなだらかな坂にしました。

色や明るさを景色に合わせる補正と、足元の影はまだありません。そのため、少し浮いて見えます。とはいえ、頭を動かすと、写真の人と後ろの本物の景色が別々にずれていき、窓の向こうに人がいるような感覚はちゃんと出ます。

スクリーンショット 2026-11-13 19.18.46

フローティングウィンドウで画面の一部を透過に

ホーム画面の壁紙だけでなく、別のアプリに窓を開けることもやってみました。アプリをフローティングウィンドウで表示すると、ウィンドウの位置と大きさに合わせて景色を描き、アプリに窓が開いたように見せます。(フローティングウィンドウ対応機のみ)

スクリーンショット 2026-11-13 19.19.14

キャリブレーション・設定を簡単に

一番難しいと思ったのが端末に合わせたキャリブレーションですが、初回にガイド付きの調整で済ませられます。
OPPO Find N6のような折りたたみスマホでは、両方の画面で個別に設定できます。

Screenshot_2026-11-13-18-58-26-30_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-18-58-40-76_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-18-59-02-44_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-18-59-42-35_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-18-59-51-44_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-19-01-56-03_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-19-02-16-90_5c45f128d7093a809b34df984ced8bd0

設定画面は「表示」「立体感」「視点」の3つに分け、よく使う項目だけを並べました。細かい項目は「詳細」の中にあり、ガイド付き調整もそこからやり直せます。

Screenshot_2026-11-13-19-02-31-49_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-19-02-45-41_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-19-04-54-09_5c45f128d7093a809b34df984ced8bd0
Screenshot_2026-11-13-19-04-57-61_5c45f128d7093a809b34df984ced8bd0

作りながらつまずいたこと

起きたこと原因と対策
奥行き推定の途中でアプリが強制終了するONNX Runtime 1.23.2 が、SME はあるが SME2 はない CPU で SME2 の命令を実行していた(SIGILL)。1.27.0 に上げて解決
壁紙からカメラを開けないAndroid は画面に出ていないアプリのカメラを拒否する。カメラ種別のフォアグラウンドサービスを、アプリが前面にある間に起動しておく
Android 15 で互換性の警告が出るネイティブライブラリが 16KB ページサイズに未対応だった。MediaPipe 0.10.35 などに上げ、全ライブラリのアラインメントを確認
写真の輪郭がギザギザ・透ける・壁に見える境目の整え方、前景の切り抜き方、背景層の作り方を段階的に変更(前述の通り)
人物+透過で、体に穴が空き、輪郭が階段状になる写真3D 用の「引き伸ばされた部分を捨てる」処理を止め、切り抜いた外側の奥行きを人の奥行きで埋め、人の範囲を写真の色で細かくした(前述の通り)

アプリ

OPPO Find N6でしか動作確認していないので、他機種で動くかは分かりませんが、作成したアプリを載せておきます。インストールは自己責任でお願いします。

SHA-256: 0d5e8a74e6a5a268ca7ad4c779a44d74988ef1d0276afe0b1766bd40774d7f42 touka-3d-wallpaper-0.2.apk

  • インストールには「提供元不明のアプリ」の許可が必要です
  • 初回はカメラの許可を求められ、ガイド付き調整が始まります

動画撮影用に、目の代わりに撮影するカメラの位置を QR コードで測る機能もあります(設定の『視点の決め方』→『QR』)。印刷用の QR コードは下記です。

プライバシー

  • カメラの映像は端末の中だけで処理し、保存も送信もしません。
  • 選んだ写真は、縮小した複製と推定結果(奥行き・人の範囲など)を、アプリ専用の領域に1枚分だけ保存します。端末の外へは送らず、Android のバックアップの対象からも外しています。
  • 奥行きの推定、人の切り抜き、背景の描き足しは、すべて端末内のモデルで行います。
  • QR マーカーの検出に使う ML Kit(Google Play 開発者サービス版)は、モデルのダウンロードや利用状況の統計で Google と通信することがあります。

動く環境と制約

  • Android 11 以上の arm64 端末が対象です。カメラの透過表示には、インカメラとメインカメラを同時に使える機種が必要です。
  • カメラの透過表示は、背景を1枚の平面と仮定しています。距離の違う物は一部しか合いません。
  • 正しく見えるのは片目(または両目の中間)の視点だけです。
  • 写真3D で視点を大きく動かすと、描き足した部分がのっぺりした色に見えることがあります。
  • 人物+透過は、明るさや色を景色に合わせておらず、影もないので、少し浮いて見えます。髪の毛先の隙間には、写真の元の背景の色が少し残ります。メインカメラを使うので、電池の消費は透過と同じです。

使っているライブラリとモデル:MediaPipe(Apache 2.0)、ONNX Runtime(MIT)、Depth Anything V2 Small(Apache 2.0)、MI-GAN(MIT)、ML Kit。アプリ内の「ライセンス」から全文を確認できます。