Pynote

Python、機械学習、画像処理について

OpenCV - 画像処理のパラメータを決めるには、ipywidgets が便利

概要

OpenCV で各種画像処理を行うためには決めなければならないパラメータがいくつか出てくる。
Notebook 上でスライダーやプルダウンメニューを使えるようにする GUI ウィジェットである ipywidgets を組み合わせることで、画像処理の結果を確認しながら、パラメータを決めることができる。

ipywidgets の導入方法

以下の記事を参照されたい。

pynote.hatenablog.com

2値化処理 (cv2.threshold)

pynote.hatenablog.com

cv2.threshold では、閾値 thresh 及び2値化処理の種類 type を決める必要がある。
thresh を [0, 255] の範囲のスライダー、type をプルダウンメニューで設定できるようにする。

import cv2
from IPython.display import Image, display
from ipywidgets import widgets

# 画像を読み込む。
img = cv2.imread("sample.jpg", cv2.IMREAD_GRAYSCALE)


def imshow(img):
    '''画像を Notebook 上に表示する。
    '''
    encoded = cv2.imencode(".png", img)[1]
    display(Image(encoded))


def threshold(thresh, type):
    '''2値化処理を行い、結果を表示する。
    '''
    ret, binary = cv2.threshold(img, thresh, maxval=255, type=type)
    imshow(binary)


# パラメータ thresh を設定するスライダー
slider = widgets.IntSlider(
    min=0, max=255, step=1, value=0, description="thresh: ")
slider.layout.width = "400px"

types = [(s, eval(s)) for s in [
    "cv2.THRESH_BINARY",
    "cv2.THRESH_BINARY_INV",
    "cv2.THRESH_TRUNC",
    "cv2.THRESH_TOZERO",
    "cv2.THRESH_TOZERO_INV",
]]

# パラメータ type を設定するプルダウンメニュー
dropdown = widgets.Dropdown(
    options=types, value=cv2.THRESH_BINARY, description="type: ")
dropdown.layout.width = "400px"

# ウィジェットを表示する。
widgets.interactive(threshold, thresh=slider, type=dropdown)

実行すると、以下の画面が表示される。
スライダーやプルダウンメニューを変更すると、即座に結果が反映される。


2値化処理 (cv2.inRange)

import cv2
from IPython.display import Image, display
from ipywidgets import widgets

# 画像を読み込む。
img = cv2.imread("test.jpg")


def imshow(img):
    """画像を Notebook 上に表示する。
    """
    ret, encoded = cv2.imencode(".png", img)
    display(Image(encoded))


def inRange(**kwargs):
    """2値化処理を行い、結果を表示する。
    """
    lower = tuple([int(l) for l, h in kwargs.values()])
    upper = tuple([int(h) for l, h in kwargs.values()])
    binary = cv2.inRange(img, lowerb=lower, upperb=upper)
    imshow(binary)


# パラメータ lower, upper を設定するスライダー
num_channels = 1 if img.ndim == 2 else img.shape[2]
parts = {}
for i in range(num_channels):
    slider = widgets.SelectionRangeSlider(
        options=np.arange(256), index=(0, 255), description=f"channel {i}"
    )
    slider.layout.width = "400px"

    parts[f"channel{i}"] = slider

# ウィジェットを表示する。
widgets.interactive(inRange, **parts)