LoginSignup
4
4

(簡易)光学迷彩プログラム

Last updated at Posted at 2024-05-27

目的

映像に映った人を透明化できる簡易的な光学迷彩1プログラムを作成する
(背景問わず透明化できるようにしたい2)

完成イメージ

今回は上図の赤字部分を対象にしてプログラム作成

環境

HW

  • PC:Lenovo ThinkBook 13s Gen 3
  • カメラ:PC内蔵のインカメラ

SW

  • Python:v3.11.5
  • Anaconda:conda v23.7.4
  • 物体検出モデル:YOLO v8

作業メモ

環境整備

参考サイト
https://qiita.com/shiganai/items/11537a0083f978e6821d
https://github.com/ultralytics/ultralytics

Anaconda の導入

これは、参考サイト に記載の手順でPCに導入しただけなので、詳細は省略

YOLO v8 の導入

参考サイト を参考にして導入していく

  • YOLO v8をclone
$ git clone https://github.com/ultralytics/ultralytics.git
$ cd ultralytics
  • ultralytics packageのinstall
$ pip install ultralytics
・・・
Successfully installed charset-normalizer-3.3.2 contourpy-1.1.1 cycler-0.12.1 filelock-3.13.1 fonttools-4.47.0 fsspec-2023.12.2 importlib-resources-6.1.1 kiwisolver-1.4.5 matplotlib-3.7.4 mpmath-1.3.0 networkx-3.1 nvidia-cublas-cu12-12.1.3.1 nvidia-cuda-cupti-cu12-12.1.105 nvidia-cuda-nvrtc-cu12-12.1.105 nvidia-cuda-runtime-cu12-12.1.105 nvidia-cudnn-cu12-8.9.2.26 nvidia-cufft-cu12-11.0.2.54 nvidia-curand-cu12-10.3.2.106 nvidia-cusolver-cu12-11.4.5.107 nvidia-cusparse-cu12-12.1.0.106 nvidia-nccl-cu12-2.18.1 nvidia-nvjitlink-cu12-12.3.101 nvidia-nvtx-cu12-12.1.105 opencv-python-4.9.0.80 pandas-2.0.3 pillow-10.2.0 psutil-5.9.7 py-cpuinfo-9.0.0 pyparsing-3.1.1 python-dateutil-2.8.2 pytz-2023.3.post1 requests-2.31.0 scipy-1.10.1 seaborn-0.13.1 sympy-1.12 thop-0.1.1.post2209072238 torch-2.1.2 torchvision-0.16.2 tqdm-4.66.1 triton-2.1.0 tzdata-2023.4 ultralytics-8.0.237 zipp-3.17.0

[notice] A new release of pip is available: 23.2.1 -> 23.3.2
[notice] To update, run: /usr/bin/python3 -m pip install --upgrade pip
  • jupyter notebookで以下を実行し、動作確認
from ultralytics import YOLO
model = YOLO("yolov8n.pt")
results = model(0 , show=True)

→ PCのインカメラで映像が取得でき、簡単な物体検出(人とかの検出)ができることを確認

カメラ映像から人を透過させる

前節の環境整備で人の検出ができることは確認したため、人を透過させる方法を検討する

参考サイト
https://docs.ultralytics.com/guides/isolating-segmentation-objects/#recipe-walk-through

どうやって透過するか・・

今回は、参考サイト の内容を利用する
YOLOの検出結果の一部に認識した物体のmask画像に関する要素があるようで、その座標情報を利用して、認識した人を透過し、事前に取得した背景画像を映像に映すようなプログラムとする

プログラム

  1. 準備段階として背景画像を取得 → [Esc]キーを押したタイミングで画像取得
  2. 再度映像を取得し、人が映っている場合はその部分を透過した映像を画面に表示
    • 透過した部分には始めに取得した背景画像を表示
  3. 終了したい場合は、[Esc]キーで抜ける
#!/usr/bin/env python
# coding: utf-8

# In[1]:


from ultralytics import YOLO
import cv2
import numpy as np


# In[2]:


model = YOLO("yolov8n-seg.pt")
cap = cv2.VideoCapture(0)


# In[3]:


# (初期処理)Webカメラから背景画像を取得
try:
    cap.isOpened()
    while True:
        ret, img_bak = cap.read()
        cv2.imshow("background",img_bak)
    
        # 背景画像の再取得が不要な場合、Escキーで抜ける
        if cv2.waitKey(1) == 27:
            cv2.destroyAllWindows()
            break
            
except:
    # Webカメラが起動できない場合の例外処理
    cv2.destroyAllWindows()
    cap.release()
    print("Web camera can't open")


# In[4]:


while True:
    # Webカメラ映像取得
    ret, img_main = cap.read()
    results = model(img_main)

    # 取得した映像の検出結果(の一部)を保持
    for r in results:
        boxes_xyxy = r.boxes.numpy().xyxy

    # 人(person)が映像に映っている場合に以下の処理を実施
    if r.boxes.numpy().cls.size > 0 and r.boxes.numpy().cls[0] == 0:
        # 人をmask(消す)するための画像生成
        # https://docs.ultralytics.com/guides/isolating-segmentation-objects/#recipe-walk-through
        img_main_mask = np.zeros(r.boxes.numpy().orig_shape, np.uint8)
        contour = r[0].masks.xy.pop()
        contour = contour.astype(np.int32)
        contour = contour.reshape(-1, 1, 2)
        
        # 取得した輪郭からmask画像生成
        _ = cv2.drawContours(img_main_mask,
                             [contour],
                             -1,
                             (255, 255, 255),
                             cv2.FILLED)
        
        img_bak_mask  = cv2.bitwise_not(img_main_mask)

        # mask画像はグレースケールのため、BGRに変換
        img_main_mask = cv2.cvtColor(img_main_mask, cv2.COLOR_GRAY2BGR)
        img_bak_mask  = cv2.cvtColor(img_bak_mask, cv2.COLOR_GRAY2BGR)

        # Webカメラ画像をmask(人を消す)する
        img_main_masked = cv2.bitwise_or(img_main, img_main_mask)
        img_bak_masked  = cv2.bitwise_or(img_bak, img_bak_mask)
        img_masked      = cv2.bitwise_and(img_main_masked, img_bak_masked)

        # お試しにmaskした範囲を見える化
#        cv2.rectangle(img_masked, (int(boxes_xyxy[0][0]), int(boxes_xyxy[0][1])), (int(boxes_xyxy[0][2]), int(boxes_xyxy[0][3])), (255, 255, 0))
        _ = cv2.drawContours(img_masked,
                             [contour],
                             -1,
                             (255, 255, 0),
                             3)
        
        img_last = img_masked.copy()
        
    # 人(person)が映像に映っていない場合はWebカメラの画像をそのまま映す
    else:
        img_last = img_main.copy()
        
    # mask済み映像表示
    cv2.imshow("Web camera(masked)",img_last)
    
    # 処理を終了する場合は、Escキーで抜ける
    if cv2.waitKey(1) == 27:
        break
        
cv2.destroyAllWindows()
cap.release()

デモ

実際に動作させたときのデモ動画3が以下になる

  • 始めにbackgroundウィンドウが開き、そこでEscキーを押して背景画像を取得
  • 次にWeb camera(masked)ウィンドウが開き、人が映っている部分を透過した映像が表示される
    • お試しに透過範囲を見える化している
  • 最後にEscキーで抜ける

output2.gif

まとめ

簡易だが、目標は達成!

映像に映った人を透明化できる簡易的な光学迷彩プログラムを作成する
(背景問わず透明化できるようにしたい)

ただし、まだまだ課題があるので修正は必要と考えられる

  • 人の動きに追従しきれず、透過できないケースがある
    (追従しきれないのは、PCスペックにもよると思うが)
  • 複数人の透過には未対応
  1. https://ja.wikipedia.org/wiki/%E5%85%89%E5%AD%A6%E8%BF%B7%E5%BD%A9

  2. 背景が単色の場合は、クロマキー合成という手法でできるというのはよく聞くが、今回の目的はどんな背景でもできるようにすること(https://ja.wikipedia.org/wiki/%E3%82%AF%E3%83%AD%E3%83%9E%E3%82%AD%E3%83%BC)

  3. 以下のツールを使用して、一部モザイクをかけている(https://jp.cyberlink.com/products/powerdirector-video-editing-software/overview_ja_JP.html)

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4