参照している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のアプリケーション作成の参考になれば幸いです。
完