GroundingDINOの使い方

## 前書き
Grounding DINOは、2Dオープンボキャブラリーオブジェクト検出とフレーズグラウンディング（AIが言葉や概念を、具体的なものや実際の世界と結びつけて理解する能力）を統合した、グラウンディングの事前学習モデルです。
GroundingDINOの使い方です  
[https://github.com/IDEA-Research/GroundingDINO/tree/main?tab=readme-ov-file#hammer_and_wrench-install](https://github.com/IDEA-Research/GroundingDINO/tree/main?tab=readme-ov-file#hammer_and_wrench-install)  
GroundingDINOのGitHubリポジトリのREADME.mdにも載っていますが、ChatGPT-4で日本語に翻訳したものです。

最後にGoogle Colabで実際にハンズオンする流れを記載します。

# 使い方
## 注意
CUDA環境がある場合は、環境変数 `CUDA_HOME` が設定されていることを確認してください。CUDAが利用できない場合は、CPUのみのモードでコンパイルされます。

インストール手順に厳密に従ってください。そうでないと、プログラムが以下のようなエラーを発生させる可能性があります：
```shell
NameError: name '_C' is not defined
```
このようなエラーが発生した場合は、gitを再クローンして、すべてのインストール手順を再度行って、groundingDINOを再インストールしてください。

### CUDAのチェック方法:
[CUDAのチェック方法](https://github.com/IDEA-Research/GroundingDINO#how-to-check-cuda) 

```shell
echo $CUDA_HOME
```
何も表示されない場合は、パスが設定されていないことを意味します。

現在のシェルで環境変数を設定するためにこれを実行してください。
```shell
export CUDA_HOME=/path/to/cuda-11.3
```
cudaのバージョンはCUDAランタイムと一致している必要があります。同時に複数のcudaが存在する可能性があります。

`CUDA_HOME`を永続的に設定したい場合は、以下のように保存してください。
```shell
echo 'export CUDA_HOME=/path/to/cuda' >> ~/.ba
```
その後、`bashrc`ファイルをソースして`CUDA_HOME`をチェックしてください：
```shell
source ~/.bashrc
echo $CUDA_HOME
```
この例では、`/path/to/cuda-11.3`はCUDAツールキットがインストールされているパスに置き換える必要があります。これは、ターミナルで**which nvcc**と入力することで見つけることができます。

例えば、出力が `/usr/local/cuda/bin/nvcc`の場合：
```shell
export CUDA_HOME=/usr/local/cuda
```

## インストール
 GitHubからGroundingDINOリポジトリをクローンします。
```shell
git clone https://github.com/IDEA-Research/GroundingDINO.git
```
現在のディレクトリをGroundingDINOフォルダに変更します。
```
cd GroundingDINO/
```
現在のディレクトリで依存パッケージをインストールする
```
pip install -e .
```

事前学習済みモデルの重みをダウンロードします。
```shell
mkdir weights
cd weights
wget -q https://github.com/IDEA-Research/GroundingDINO/releases/download/v0.1.0-alpha/groundingdino_swint_ogc.pth
cd ..
```

## 使う
（GPUを使う場合のみ）GPU-IDをチェックする。GPU IDを確認するには、次のコマンドを使用してください：
```shell
nvidia-smi
```
以下のコマンドで `GPU ID`、`検知したい画像.jpg`、`"アウトプットの格納先"` を適切な値に置き換えてください。
```shell
CUDA_VISIBLE_DEVICES={GPU ID} python demo/inference_on_a_image.py 
-c groundingdino/config/GroundingDINO_SwinT_OGC.py 
-p weights/groundingdino_swint_ogc.pth 
-i 検知したい画像.jpg 
-o "アウトプットの格納先" 
-t "chair"
 [--cpu-only] # CPUモードのために使う
```

特定のフレーズを検出するためのデモは以下のようになります：
```shell
CUDA_VISIBLE_DEVICES={GPU ID} python demo/inference_on_a_image.py 
-c groundingdino/config/GroundingDINO_SwinT_OGC.py 
-p ./groundingdino_swint_ogc.pth 
-i .asset/cat_dog.jpeg 
-o logs/1111 
-t "There is a cat and a dog in the image ." 
--token_spans "[[[9, 10], [11, 14]], [[19, 20], [21, 24]]]"
 [--cpu-only] # open it for cpu mode
```
`token_spans`はフレーズの開始位置と終了位置を指定します。たとえば、最初のフレーズは`[[9, 10], [11, 14]]`です。
例えば、`"There is a cat and a dog in the image."[9:10] = 'a'`、`"There is a cat and a dog in the image."[11:14] = 'cat'`です。したがって、これはフレーズ`a cat`を指しています。同様に、`[[19, 20], [21, 24]]`はフレーズ`a dog`を指します。

詳細は`demo/inference_on_a_image.py`を参照してください。
**Pythonで実行:**
```python
from groundingdino.util.inference import load_model, load_image, predict, annotate
import cv2

model = load_model("groundingdino/config/GroundingDINO_SwinT_OGC.py", "weights/groundingdino_swint_ogc.pth")
IMAGE_PATH = "weights/dog-3.jpeg"
TEXT_PROMPT = "chair . person . dog ."
BOX_TRESHOLD = 0.35
TEXT_TRESHOLD = 0.25

image_source, image = load_image(IMAGE_PATH)

boxes, logits, phrases = predict(
    model=model,
    image=image,
    caption=TEXT_PROMPT,
    box_threshold=BOX_TRESHOLD,
    text_threshold=TEXT_TRESHOLD
)

annotated_frame = annotate(image_source=image_source, boxes=boxes, logits=logits, phrases=phrases)
cv2.imwrite("annotated_image.jpg", annotated_frame)
```

## Google Colab環境での使い方
ColabをPython3とGPUを使うように設定します。  
編集-ノートブックの設定-ランタイムのタイプ-Python3
編集-ノートブックの設定-ハードウェア アクセラレータ-GPU
というふうに設定します。

データ管理をやりやすくするために、ルートディレクトリをHOME定数にします。
```
import os
HOME = os.getcwd()
print(HOME)
```
**実行結果**
```
/content
```
 
 GitHubからGroundingDINOリポジトリをクローンして、GroundingDinoをインストールします。
```shell
%cd {HOME}
git clone https://github.com/IDEA-Research/GroundingDINO.git
%cd {HOME}/GroundingDINO
!pip install -q -e .
```
**実行結果**
```
/content Cloning into 'GroundingDINO'... remote: Enumerating objects: 421, done. 
remote: Counting objects: 100% (182/182), done. 
remote: Compressing objects: 100% (58/58), done. 
remote: Total 421 (delta 136), reused 131 (delta 124), pack-reused 239 
Receiving objects: 100% (421/421), 12.85 MiB | 16.11 MiB/s, done. 
Resolving deltas: 100% (214/214), done. /content/GroundingDINO 
Preparing metadata (setup.py) ... done
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 254.7/254.7 kB 4.9 MB/s eta 0:00:00
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2.2/2.2 MB 49.9 MB/s eta 0:00:00 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77.5/77.5 kB 9.6 MB/s eta 0:00:00 
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 49.1/49.1 MB 13.2 MB/s eta 0:00:00
```

後ほど画像検知するためにCONFIG_PATH定数を設定します
```
import os
CONFIG_PATH = os.path.join(HOME, "GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py")
print(CONFIG_PATH, os.path.isfile(CONFIG_PATH))
```
**実行結果**
```
/content/GroundingDINO/groundingdino/config/GroundingDINO_SwinT_OGC.py True
```

重みをダウンロードします。
```
%cd {HOME}
!mkdir {HOME}/weights
%cd {HOME}/weights

!wget -q https://github.com/IDEA-Research/GroundingDINO/releases/download/v0.1.0-alpha/groundingdino_swint_ogc.pth
```
**実行結果**
```
/content 
/content/weights
```

ダウンロードしてきた重みを定数に設定する
```
import os

WEIGHTS_NAME = "groundingdino_swint_ogc.pth"
WEIGHTS_PATH = os.path.join(HOME, "weights", WEIGHTS_NAME)
print(WEIGHTS_PATH, "; exist:", os.path.isfile(WEIGHTS_PATH))
```

**画像検知用のデータを用意する**
画像のエンコーディングがおかしいことがあるので、エンコーディングをUTF-8にします。
```
import locale
locale.getpreferredencoding = lambda: "UTF-8"
```

**Webから画像ダウンロード**
```shell
%cd {HOME}
!mkdir {HOME}/data
%cd {HOME}/data

!wget -q [webからの画像リンクhttps://xxx/xxx.jpg]
```

**ローカルから画像アップロード**
Google Driveをマウントします。
```
from google.colab import drive 
drive.mount('/content/drive') 
%cd /content/drive/MyDrive
```
ローカルの画像をGoogle Driveにアップロードして、`cp`コマンドで`/content/data`にコピーして、次のステップに入ります。

**GroundingDinoモデルをロードする**
```
%cd {HOME}/GroundingDINO

from groundingdino.util.inference import load_model, load_image, predict, annotate

model = load_model(CONFIG_PATH, WEIGHTS_PATH)
```
画像検知の実行
```python
import os
import supervision as sv

IMAGE_NAME = "xxx.jpg"  # 画像をファイル名で指定する
IMAGE_PATH = os.path.join(HOME, "data", IMAGE_NAME)

TEXT_PROMPT = "bag" # ここで検知したい物体を指すプロンプトを入力する
BOX_TRESHOLD = 0.35
TEXT_TRESHOLD = 0.25

image_source, image = load_image(IMAGE_PATH)
boxes, logits, phrases = predict(
    model=model,
    image=image,
    caption=TEXT_PROMPT,
    box_threshold=BOX_TRESHOLD,
    text_threshold=TEXT_TRESHOLD
)

annotated_frame = annotate(image_source=image_source, boxes=boxes, logits=logits, phrases=phrases)

%matplotlib inline

sv.plot_image(annotated_frame, (16, 16))
```