ラベル MediaPipe の投稿を表示しています。 すべての投稿を表示
ラベル MediaPipe の投稿を表示しています。 すべての投稿を表示

2025年5月29日木曜日

Google MediaPipe Solutionsの手指のランドマーク検出とオブジェクト検出をAPEXアプリで実行する

Google MediaPipeソリューションガイドを参照して、ソリューションに含まれる手指のランドマーク検出オブジェクト検出を、APEXアプリケーションに実装してみます。

参照しているGoogle MediaPipeソリューションガイドのリンクは以下です。

どちらもウェブ版を元にAPEXに実装しています。参照しているのはCodepenのコード例です。

手指のランドマーク検出ガイドのコード例はこちらです。
オブジェクト検出タスクガイドのコード例はこちらです。

CodepenではサンプルとしてHTML、CSSおよびJS(TypeScript)の3種類のコードが提供されています。このうち、CSSとJS(TypeScript)はほぼそのままAPEXアプリの静的アプリケーション・ファイルとして含めています。

CSSの記述に含まれているクラスで、APEXの表示に影響するクラス定義をコメントアウトしています。また、JS(TypeScript)のコードはJavaScriptにしないと静的アプリケーション・ファイルとして保存できないため、型定義を削除しています。追加したコードは、ボタンを押したときにevent.preventDefault()の呼び出して、APEXのボタン・クリックの標準動作であるページの送信を行わないようにしています。

作成した手指のランドマーク検出のAPEXアプリは、以下のように動作します。


このAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/google-mediapipe-hand-landmaker-on-apex.zip

オブジェクト検出のAPEXアプリは以下のように動作します。


このAPEXアプリケーションのエクスポートを以下に置きました。
https://github.com/ujnak/apexapps/blob/master/exports/google-mediapipe-object-detector-on-apex.zip

カメラにアクセスするため、HTTPSおよびホスト名が正しく付けられているサイトでAPEXアプリケーションが動作している必要があります。上記のAPEXアプリはAlways FreeのAutonomous Databaseで実行しています。

両方とも、画面の構成は同じです。そのため、手指のランドマーク検出のAPEXアプリを例に取って実装について紹介します。

JavaScriptとCSSのコードは、静的アプリケーション・ファイルapp.jsおよびapp.cssとして保存しています。


アプリケーションの画面はホーム・ページに実装しています。

ページ・プロパティJavaScriptファイルURLに、HTML内で参照しているJavaScriptのファイルへのリンクと静的アプリケーション・ファイルapp.jsへのリンクを含めています。

CSSファイルURL静的アプリケーション・ファイルapp.cssへのリンクを含めています。


静的な画像を対象とした手指のランドマーク検出と、Webカムの動画より手指のランドマーク検出を行う2種類のデモが含まれています。それぞれdemo_imagesおよびdemo_videoというリージョンに実装しています。

そのリージョンを切り替えて表示するリージョンdemosを作成しています。タイプリージョン表示セレクタです。リージョンの静的IDとしてdemos外観CSSクラスinvisibleを設定しています。これはMediaPipeの初期化が完了するまで、idがdemosのリージョンを非表示にする処理がJavaScriptで実装されているためです。

リージョンdemo_imagesは、画像から手指のランドマーク検出を行うためのリージョンです。画像はリージョンPreviewに表示されます。タイプ静的コンテンツソースHTMLコードに以下を記述しています。
<div class="detectOnClick">
    <img id="preview" src="&P1_URL." title="Click to get detection!"></img>
</div>
CSSクラスとしてdetectOnClickが設定されている要素をクリックしたときに、その子要素のimgとして表示されている画像を対象に、手指のランドマーク検出が行われるようapp.js内にJavaScriptで記述されています。


画像のプレビューの実装については、こちらの記事「画像ビューワーのアプリを改良する」の「ファイルを送信する前にプレビューを表示」のセクションで紹介している方法をそのまま採用しています。

リージョンdemo_videoは、動画から手指のランドマークの検出を行うためのリージョンです。こちらは静的コンテンツとしてCodepenのHTMLの記述をそのままHTMLコードに書き込んでいます。
<p>Hold your hand in front of your webcam to get real-time hand landmarker detection.</br>Click <b>enable webcam</b> below and grant access to the webcam if prompted.</p>

<div id="liveView" class="videoView">
    <button id="webcamButton" class="mdc-button mdc-button--raised">
        <span class="mdc-button__ripple"></span>
        <span class="mdc-button__label">ENABLE WEBCAM</span>
    </button>
    <div style="position: relative;">
        <video id="webcam" style="position: abso" autoplay playsinline></video>
        <canvas class="output_canvas" id="output_canvas" style="position: absolute; left: 0px; top: 0px;"></canvas>
    </div>
</div>
ボタンwebcamBottonをクリックしたときに実行されるコードは、app.jsに記述されています。APEXではボタンのクリックでページの送信が行われます。それを抑止するために、webcamButtonをクリックしたときに呼び出されるファンクションenableCamの先頭でevent.preventDefault()を実行するようにしています。


概ね以上の変更を行うことで、MediaPipe SolutionsのサンプルをAPEXアプリとして実装できました。

余談ですが、Object DetectorのCodepenのサンプルに含まれるJavaScriptのコードは、以下から始まっています。
import {
  ObjectDetector,
  FilesetResolver,
  Detection,
  ObjectDetectionResult
} from "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.2";
APEXに貼り付けて実行すると、以下のエラーが発生しました。
app.js:18 Uncaught SyntaxError: The requested module 'https://cdn.jsdelivr.net/npm/@mediapipe/tasks-vision@0.10.2' does not provide an export named 'Detection' (at app.js:18:3)
Codepenで動作しているコードなのでAPEX側の問題とばかり考えていたため、原因はまったく見当がつきませんでした。

仕方ないのでGoogleのことはGoogleに聞こうと思い、Gemini 2.5 Flashに先のエラー・メッセージを貼り付けて原因を聞いたところ、元のコードがおかしいと回答されました。


Task-based API: MediaPipe Tasks Vision is designed around "tasks" like FaceDetector, ObjectDetector, HandLandmarker, etc. You don't directly interact with a generic "Detection" class. Instead, you use the specific task classes to perform detections.

GeminiからDetectionとObjectDetectionResultをインポート対象から外すように提示され、実際、外したらエラーは解消しました。

改めてAIはすごいな、と感じました。

今回の記事は以上です。

Oracle APEXのアプリケーション作成の参考になれば幸いです。

2025年5月22日木曜日

APEXアプリのページ上でGoogle AI EdgeのMediaPipe LLM Inference APIを呼び出す

GoogleがGoogle AI Edgeのソリューションとして提供しているMediaPipe LLM Inference APIを、Oracle APEXのアプリケーションのページ上で呼び出してみます。

以下のサンプル・アプリケーションに含まれるindex.jsを、Oracle APEXで動くように改変ししました。

MediaPipe LLM Inference task for web
https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/llm_inference/js

実行環境はmacOSのChromeです。作業としては、ウェブ用LLM推論ガイドのクイックスタートを参照しています。

元々は最近発表されたGemma 3nを動かすつもりだったのですが、Gemma 3nは現時点では.taskファイルのみ公開されているようです。ウェブ用LLM推論ガイドモデル変換に.taskの対応プラットフォームとしてAndroid、iOSはありますが、ウェブがありません。そのため、クイックスタートのとおりにgemma2-2b-it-gpu-int8を使用しました。

サンプル・アプリケーションのindex.htmlは、APEXのアプリケーションのページとして作り直しています。

作成したアプリケーションは以下のように動作します。


空のAPEXアプリケーションを作成し、機能はすべてホーム・ページに実装します。

APEX向けに書き直したindex.jsは以下になります。

このファイルを静的アプリケーション・ファイルとしてアップロードします。作成した静的アプリケーション・ファイル参照をメモします。


静的アプリケーション・ファイルindex.jsをページに読み込むために、ホーム・ページのページ・プロパティJavaScriptファイルURLに以下を記述します。moduleを指定します。

[module]#APP_FILES#index#MIN#.js


LLMに送信する文字列は、ページ・アイテムP1_INPUTに入力します。タイプテキスト領域を選択します。セッション・ステートデータ型CLOBストレージリクエストごと(メモリーのみ)を設定します。


ボタンSUBMITを作成します。ボタンをクリックしたときに実行されるイベントハンドラは、index.js内に記述されています。APEXアプリとしては何も処理をしないので、動作アクションとして動的アクションで定義を選択します。また、index.js内でこのボタンをsubmitというIDで見つけているので、詳細静的IDsubmitを設定します。


LLMの出力はページ・アイテムP1_OUTPUTに表示します。LLMの出力フォーマットはMarkdownなので、ページ・アイテムのタイプとしてMarkdownエディタを選択します。セッション・ステートデータ型CLOBストレージリクエストごと(メモリーのみ)を設定します。


Oracle APEXでMediaPipe LLM Inference APIを呼び出すサンプルは以上で完成です。

モデル・ファイルのgemma2-2b-it-gpu-int8.binは、kaggle.comからダウンロードしました。


LLMとしては小さなモデルとはいえ、数GBはあります。Oracle APEXの静的アプリケーション・ファイルとして保存するのも避けたかったので、ORDSから直接ファイルとしてダウンロードできる場所に配置しました。

(CDNではなく)ORDSがOracle APEXのイメージ・ファイルを提供するように構成している場合、以下のようにstandalone.static.pathが設定されています。(global/settings.xml内)

<entry key="standalone.static.path">/opt/oracle/apex/images</entry>

このパスの下はURLから見ると/i/以下にあるファイルとして参照されます。そのため、(上記の例では/opt/oracle/apex/images以下に)ディレクトリmodelsを作成し、その下にgemma2-2b-it-gpu-int8.binを置きました。

index.js内ではモデル・ファイルを以下のように指定しています。
const modelFileName = '/i/models/gemma2-2b-it-gpu-int8.bin'; /* Update the file name */
CORSのエラーが発生しないよう、APEXが動作しているホストと同じホストからモデル・ファイルをダウンロードする必要があるようです。また、ダウンロード元がlocalhost以外の場合、https経由でダウンロードする必要があるとの記載もありました。今回の作業ではAPEXはlocalhostでアクセスしているため、両方の条件が必須かどうかは確認できていません。

今回使用したモデルはWebGPUを使用します。Chromeのchrome://flagsを開いて、WebGPUに関する以下の2つの設定を有効にしています。

#enable-unsafe-webgpu、#enable-webgpu-developer-features


今回の記事は以上になります。

今回作成したAPEXアプリケーションのエクスポートを以下に置きました。https://github.com/ujnak/apexapps/blob/master/exports/sample-google-ai-edge-mediapipe.zip

Oracle APEXのアプリケーション作成の参考になれば幸いです。