3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

PythonAdvent Calendar 2022

Day 20

cv2 Select Multiple ROIsの自作

Last updated at Posted at 2022-12-19

はじめに

マウスクリックで画像から複数のROI Boxを描画します。

ROI(Region of Interest)とは、画像データのうち、操作の対象として選ぶ領域のことです。「対象領域」「注目領域」「関心領域」などともいいます。

例えば、画像の一部分にだけ処理を施す場合にROIという言葉を使います。

キャプチャ.JPG

既存の関数を利用した場合

opencvを使用すると比較的簡単に複数のROI Boxを描画可能です。
cv2.selectROIs()を使用します。

事前にモジュールのインストールが必要です。

pip install opencv-python

適当な画像で試してみます。コードは以下の通り。

from random import randint
import cv2

# 画像ファイルのパス
path = 'abc.JPG'

# 画像読み込み
img_raw = cv2.imread(path)

# 複数領域の指定
ROIs = cv2.selectROIs("Select Rois", img_raw, 0, 0)
cv2.destroyWindow("Select Rois")
print(ROIs)

# boxの描画
for roi in ROIs:
    x1, y1, x2, y2 = roi
    B, G, R = randint(0, 255), randint(0, 255), randint(0, 255)
    cv2.rectangle(img_raw,
              pt1=(x1, y1),
              pt2=(x1+x2, y1+y2),
              color=(B, G, R),
              thickness=3,
              lineType=cv2.LINE_4,
              shift=0)

# boxを描画した画像の表示
cv2.imshow('img', img_raw)
# キー入力で閉じる
cv2.waitKey(0)
cv2.destroyAllWindows()

"""
print(ROIs)
[[x0, y0, width, hight]]
>>
[[136 137  63  53]
 [320  93  77  77]
 [261 241  76  79]
 [ 70 281  71  52]]
"""

Animation_tmp.gif

gifでは分かりにくいですが、ROI boxを1つ描画するごとにスペースキーで領域選択を確定しています(少し面倒)。そして2つ目以降のROI boxを描画しているときに前のboxが消えてしまいます。このあたりが不便。

cv2.selectROIsの自作

事前にモジュールのインストールが必要です。

pip install opencv-python
pip install numpy
pip install keyboard
import numpy as np
import cv2
from copy import deepcopy
from random import randint
import keyboard
import time

class MultiBoxDrawer:
    # 参考 https://qiita.com/ryo_ryo/items/973007667c528ef23abb
    def draw(self, img):
        m = MouseEventHandler(img)

        cv2.imshow('Select Rois',img)
        cv2.setMouseCallback ("Select Rois",
                            lambda event, x, y, flags, param:
                            m.mouse_event(event, x, y, flags, param, img))

        while True:
            img = m.clone_img
            cv2.imshow("Select Rois", img)
            k = cv2.waitKey(10)
            if keyboard.is_pressed("space") | keyboard.is_pressed("enter"):
                time.sleep(0.3)
                break

        cv2.destroyWindow("Select Rois")
        # 複数のバウンディングボックスの座標情報をreturn
        return m.ROIRegion

class MouseEventHandler:
    def __init__(self, img):
        self.drawing = False # true if mouse is pressed
        self.ix, self.iy = -1, -1
        self.ROIRegion = []
        self.init_img = deepcopy(img)
        self.clone_img = deepcopy(img)
        self.tmp_img = deepcopy(img)

    def mouse_event(self, event, x, y, flags, param, img):
        if event == cv2.EVENT_LBUTTONDOWN: # 左クリック(押し込み)した瞬間の処理
            self.drawing = True
            self.ix, self.iy = x,y
            self.tmp_img = deepcopy(img)

        elif event == cv2.EVENT_MOUSEMOVE: #ドラッグ中の処理
            if self.drawing == True:
                self.clone_img = deepcopy(self.tmp_img)
                cv2.rectangle(self.clone_img, (self.ix, self.iy), (x, y), (0, 0, 255), 2)

        elif event == cv2.EVENT_LBUTTONUP: # 左クリック(離し)した瞬間の処理
            self.drawing = False
            if self.ix != x and self.iy != y:
                self.ROIRegion.append([min(self.ix, x), min(self.iy, y), abs(x-self.ix), abs(y-self.iy)])

        elif event == cv2.EVENT_RBUTTONDOWN: # 右クリック(離し)した瞬間の処理
            self.ROIRegion = []
            self.clone_img = deepcopy(self.init_img)


multiboxdrawer = MultiBoxDrawer()
#スペースキーもしくはエンターキーで画像を閉じる
# 画像ファイルのパス
path = 'abc.JPG'
# 画像読み込み
img_raw = cv2.imread(path)
ROIs = multiboxdrawer.draw(img_raw)
print(ROIs)

# boxの描画
for roi in ROIs:
    x1, y1, x2, y2 = roi
    B, G, R = randint(0, 255), randint(0, 255), randint(0, 255)
    cv2.rectangle(img_raw,
            pt1=(x1, y1),
            pt2=(x1+x2, y1+y2),
            color=(B, G, R),
            thickness=3,
            lineType=cv2.LINE_4,
            shift=0)

while True:
    # boxを描画した画像の表示
    cv2.imshow('img', img_raw)
    k = cv2.waitKey(10)
    # Escキー入力で閉じる
    if keyboard.is_pressed("escape"):
        time.sleep(0.3)
        break

cv2.destroyAllWindows()

"""
print(ROIs)
[[x0, y0, width, hight]]
>>
[[136 137  63  53],
 [320  93  77  77],
 [261 241  76  79],
 [ 70 281  71  52]]
"""

Animation_tmp2.gif

ROI boxを1つ描画するごとに入れていた確定処理が必要なくなり、2つ目以降のROI boxを描画しているときに前のboxが残るようになりました。右クリックで初期化も可能です。スペースキーで複数の領域選択を確定します。複数のROI box描画中の四角の色がすべて同じなのが気になるところ。改善の余地ありです。

応用例はこちら

参考

3
2
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
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?