# 画面設計書 9-TFLiteカメラプレビューフラグメント

## 概要

本ドキュメントは、TFLite DemoアプリにおけるCamera2BasicFragment（TFLiteカメラプレビューフラグメント）の画面設計書である。Camera2 APIでカメラプレビューを表示し、TFLiteモデルで画像分類を実行するFragmentについて記述する。

### 本画面の処理概要

**業務上の目的・背景**：TensorFlow Liteの画像分類モデル（MobileNet v1の量子化版・浮動小数点版）のオンデバイス推論をデモンストレーションするために本Fragmentが必要である。Camera2 APIでカメラプレビューを表示しながら、バックグラウンドスレッドで定期的に画像分類を実行し、結果をTextViewに表示する。GPU、NNAPI、CPU（マルチスレッド）のデバイス選択機能も提供する。

**画面へのアクセス方法**：CameraActivity（TFLite Demo）のonCreate()で自動的に生成・配置される。直接起動されることはない。

**主要な操作・処理内容**：
1. Camera2 APIによるカメラプレビューの表示
2. モデル選択（MobileNet v1 Quantized / MobileNet v1 Float）のListViewによる切り替え
3. デバイス選択（CPU / GPU / NNAPI）のListViewによる切り替え
4. スレッド数のNumberPickerによる調整（1-10）
5. periodicClassifyによるバックグラウンドでの定期的な画像分類実行
6. TextureViewからBitmapを取得しclassifier.classifyFrame()で分類
7. 分類結果のTextViewへの表示

**画面遷移**：CameraActivityから生成・配置される。他の画面への遷移機能は持たない。

**権限による表示制御**：カメラ権限が未付与の場合、FragmentCompat.requestPermissions()で権限リクエストを行う。

## 関連機能

| 機能No | 機能名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| 80 | TFLiteモデル変換 | 主機能 | TFLite形式のMobileNetモデル（量子化版・浮動小数点版）を読み込んで画像分類を実行 |
| 81 | TFLite推論エンジン | 主機能 | ImageClassifierを通じてTFLite推論エンジンで画像分類推論をperiodic実行し結果をTextViewに表示 |
| 82 | TFLiteデリゲート | 補助機能 | GPU・NNAPIデリゲートの選択切替によるハードウェアアクセラレーション対応 |
| 52 | 画像変換操作（Image Operations） | 補助機能 | Camera2 APIでカメラプレビューを取得しBitmapへ変換して分類モデルへ入力 |

## 画面種別

リアルタイム処理Fragment（カメラプレビュー＋画像分類＋設定UI）

## URL/ルーティング

Fragmentのため、URLベースのルーティングは存在しない。パッケージ: `com.example.android.tflitecamerademo`、クラス: `Camera2BasicFragment`。

## 入出力項目

| 項目名 | 入力/出力 | データ型 | 説明 |
|--------|----------|---------|------|
| カメラプレビューフレーム | 入力 | TextureView → Bitmap | TextureViewから取得される分類用Bitmap |
| モデル選択 | 入力 | ListView選択位置 | MobileNet v1 Quantized / Float |
| デバイス選択 | 入力 | ListView選択位置 | CPU / GPU / NNAPI |
| スレッド数 | 入力 | NumberPicker値 | 1-10の範囲で設定 |
| 分類結果 | 出力 | SpannableStringBuilder | 分類ラベルと信頼度のフォーマット済みテキスト |

## 表示項目

| 項目名 | データ型 | 説明 |
|--------|---------|------|
| カメラプレビュー | AutoFitTextureView (texture) | Camera2 APIによるリアルタイムカメラプレビュー |
| 分類結果テキスト | TextView (text) | 分類結果の表示 |
| デバイス選択リスト | ListView (device) | CPU/GPU/NNAPIの選択 |
| モデル選択リスト | ListView (model) | 量子化/浮動小数点モデルの選択 |
| スレッド数選択 | NumberPicker (np) | 推論スレッド数の設定 |

## イベント仕様

### 1-モデル/デバイス/スレッド数変更イベント

ListView（model/device）のitemClick、またはNumberPickerのvalueChangeでupdateActiveModel()がトリガーされる。

処理フロー:
1. 現在のモデルインデックス、デバイスインデックス、スレッド数を取得
2. バックグラウンドスレッドで実行
3. 前回と同じ設定の場合はスキップ
4. 既存のclassifierをclose()
5. モデル選択に応じてImageClassifierQuantizedMobileNetまたはImageClassifierFloatMobileNetを生成
6. classifier.setNumThreads()でスレッド数設定
7. デバイス選択に応じてuseGpu()またはuseNNAPI()を呼び出し

### 2-定期分類イベント（periodicClassify）

バックグラウンドスレッドで定期的に実行されるRunnable。

処理フロー:
1. lockオブジェクトで同期、runClassifier==trueの場合のみ実行
2. classifyFrame()を呼び出し
3. backgroundHandler.post(periodicClassify)で自身を再スケジュール

### 3-classifyFrame処理

処理フロー:
1. classifier==null、getActivity()==null、cameraDevice==nullのチェック
2. textureView.getBitmap(classifier.getImageSizeX(), classifier.getImageSizeY())で分類サイズのBitmapを取得
3. classifier.classifyFrame(bitmap, textToShow)で分類実行
4. bitmap.recycle()でリソース解放
5. showToast(textToShow)でTextViewに結果表示

### 4-カメラオープンイベント

onResume時またはSurfaceTexture利用可能時にopenCamera()が呼び出される。

処理フロー:
1. 権限チェック（未付与ならリクエスト）
2. setUpCameraOutputs()でカメラ出力設定
3. configureTransform()でテクスチャ変換設定
4. CameraManager.openCamera()でカメラオープン

## データベース更新仕様

### 操作別データベース影響一覧

本画面はデータベースを使用しない。

| 操作（イベント） | 対象テーブル | 操作種別 | 概要 |
|----------------|-------------|---------|------|
| なし | なし | なし | データベース操作なし |

## メッセージ仕様

| メッセージID | メッセージ内容 | 種別 | 表示条件 |
|-------------|--------------|------|---------|
| MSG-01 | "Failed to load model" | エラー | モデル読み込みに失敗した場合（showToast） |
| MSG-02 | "Failed" | エラー | CameraCaptureSession設定失敗時 |
| MSG-03 | camera_error文字列リソース | エラー | Camera2 API非対応エラー時 |

## 例外処理

| 例外状態 | 処理内容 |
|---------|---------|
| モデル読み込み失敗（IOException） | Log.d()でログ出力、classifier=null設定 |
| カメラオープンタイムアウト | 2500msでSemaphore取得失敗時にRuntimeExceptionスロー |
| CameraAccessException | Log.e()でエラーログ出力 |
| NullPointerException（Camera2非対応） | ErrorDialogを表示 |

## 備考

- パッケージ: `com.example.android.tflitecamerademo`
- MAX_PREVIEW_WIDTH: 1920、MAX_PREVIEW_HEIGHT: 1080
- HANDLE_THREAD_NAME: "CameraBackground"
- モデル: ImageClassifierQuantizedMobileNet（量子化版）、ImageClassifierFloatMobileNet（浮動小数点版）
- デバイス: CPU（デフォルト）、GPU（useGpu()）、NNAPI（useNNAPI()）
- スレッド数: 1-10（NumberPicker）
- periodicClassifyによる継続的な分類実行（Handler.post()による自己再スケジュール）
- レイアウト: `fragment_camera2_basic.xml`
- onDestroy()でclassifier.close()によるリソース解放

---

## コードリーディングガイド

本画面を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | ImageClassifier.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/ImageClassifier.java` | classifyFrame(), getImageSizeX/Y(), setNumThreads(), useGpu(), useNNAPI(), close()の各メソッド |

**読解のコツ**: ImageClassifierは抽象クラスで、ImageClassifierQuantizedMobileNetとImageClassifierFloatMobileNetが具体的実装。TFLite Interpreterを内部で使用する。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | Camera2BasicFragment.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/Camera2BasicFragment.java` | onViewCreated()（381-445行目）: UI初期化、モデル/デバイスリスト構築、リスナー設定 |
| 2-2 | Camera2BasicFragment.java | 同上 | startBackgroundThread()（676-686行目）: periodicClassify開始、updateActiveModel()呼び出し |

**主要処理フロー**:
1. **383-387行目**: 文字列リソースからGPU/CPU/NNAPI/モデル名を取得
2. **390-393行目**: TextureView、TextView、ListView、NumberPicker取得
3. **396-430行目**: モデルリスト・デバイスリストのAdapter設定とonItemClickListener登録
4. **432-442行目**: NumberPicker設定（min=1, max=10）
5. **676-686行目**: バックグラウンドスレッド開始時にperiodicClassifyをpost

#### Step 3: 分類処理を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | Camera2BasicFragment.java | 同上 | classifyFrame()（808-820行目）: TextureView→Bitmap→classifyFrame→showToast |
| 3-2 | Camera2BasicFragment.java | 同上 | updateActiveModel()（323-378行目）: モデル/デバイス切り替えロジック |
| 3-3 | Camera2BasicFragment.java | 同上 | periodicClassify（704-715行目）: 自己再スケジュール型の定期分類 |

### プログラム呼び出し階層図

```
Camera2BasicFragment (extends Fragment)
    |
    +-- onViewCreated()
    |       +-- UI要素の初期化
    |       +-- ListView/NumberPicker設定
    |
    +-- startBackgroundThread()
    |       +-- updateActiveModel()
    |       |       +-- ImageClassifierQuantizedMobileNet() / ImageClassifierFloatMobileNet()
    |       |       +-- classifier.setNumThreads()
    |       |       +-- classifier.useGpu() / classifier.useNNAPI()
    |       +-- backgroundHandler.post(periodicClassify)
    |
    +-- periodicClassify [定期実行]
    |       +-- classifyFrame()
    |       |       +-- textureView.getBitmap()
    |       |       +-- classifier.classifyFrame(bitmap, textToShow)
    |       |       +-- showToast(textToShow)
    |       +-- backgroundHandler.post(periodicClassify) [自己再スケジュール]
    |
    +-- openCamera()
    |       +-- setUpCameraOutputs()
    |       +-- createCameraPreviewSession()
    |
    +-- onDestroy()
            +-- classifier.close()
```

### データフロー図

```
[入力]                        [処理]                              [出力]

Camera2 API ------> TextureView -------> getBitmap() --------> ImageClassifier
(CaptureSession)   (プレビュー表示)     (リサイズBitmap)      (classifyFrame)
                                                                    |
モデル選択 ------> updateActiveModel                                 |
デバイス選択 --->  (QuantizedMobileNet /                             |
スレッド数 ---->   FloatMobileNet)                                   v
                  (CPU/GPU/NNAPI)                           SpannableStringBuilder
                                                                    |
                                                              TextView表示
                                                              (showToast)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| Camera2BasicFragment.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/Camera2BasicFragment.java` | ソース | カメラプレビュー＋分類Fragment |
| ImageClassifier.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/ImageClassifier.java` | ソース | TFLite分類器の抽象基底クラス |
| ImageClassifierQuantizedMobileNet.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/ImageClassifierQuantizedMobileNet.java` | ソース | 量子化MobileNet分類器 |
| ImageClassifierFloatMobileNet.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/ImageClassifierFloatMobileNet.java` | ソース | 浮動小数点MobileNet分類器 |
| AutoFitTextureView.java | `tensorflow/lite/java/demo/app/src/main/java/com/example/android/tflitecamerademo/AutoFitTextureView.java` | ソース | アスペクト比自動調整TextureView |
| fragment_camera2_basic.xml | `tensorflow/lite/java/demo/app/src/main/res/layout/fragment_camera2_basic.xml` | レイアウト | Fragmentレイアウト |
