OpenCVの特徴的な機能

【概要】 OpenCVには、色空間変換、局所的コントラスト強調、動体追跡、幾何学的変換、形状解析、多重解像度解析、パターン検出、適応的二値化、セグメンテーション等の多彩な機能がある。これらの機能は、照明変動への対応、動き検出、形状認識など、実用的な画像処理に有効である。

【目次】

  1. Python のインストールと必要なPythonライブラリのインストール
  2. 色空間変換
  3. CLAHE
  4. オプティカルフロー
  5. アフィン変換
  6. モルフォロジー演算
  7. 画像ピラミッド
  8. テンプレートマッチング
  9. 適応的閾値処理
  10. GrabCut画像セグメンテーション
  11. カラー画像表示
  12. パソコンカメラ表示

【サイト内の関連情報】

OpenCV について [PDF][パワーポイント]

ドクセルの URL: https://www.docswell.com/s/6674398749/51X845-2022-02-18-085434

Python のインストールと必要なPythonライブラリのインストール(Windows上)

  1. Python 3.12 のインストール

    インストール済みの場合は実行不要。

    管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行する。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要である。

    REM Python をシステム領域にインストール
    winget install --scope machine --id Python.Python.3.12 -e --silent --accept-source-agreements --accept-package-agreements
    
    REM パス長制限の解除
    reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled /t REG_DWORD /d 1 /f
    reg query "HKLM\SYSTEM\CurrentControlSet\Control\FileSystem" /v LongPathsEnabled
    
    REM Python のパス設定
    set "PYTHON_PATH=C:\Program Files\Python312"
    set "PYTHON_SCRIPTS_PATH=C:\Program Files\Python312\Scripts"
    echo "%PATH%" | find /i "%PYTHON_PATH%" >nul
    if errorlevel 1 setx PATH "%PATH%;%PYTHON_PATH%" /M >nul
    echo "%PATH%" | find /i "%PYTHON_SCRIPTS_PATH%" >nul
    if errorlevel 1 setx PATH "%PATH%;%PYTHON_SCRIPTS_PATH%" /M >nul

    関連する外部ページ

    Python の公式ページ: https://www.python.org/

  2. AI エディタ Windsurf のインストール

    Pythonプログラムの編集・実行には、AI エディタの利用を推奨する。ここでは、Windsurfのインストールを説明する。

    管理者権限でコマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)し、以下を実行して、Windsurfをシステム全体にインストールする。管理者権限は、wingetの--scope machineオプションでシステム全体にソフトウェアをインストールするために必要となる。

    winget install --scope machine --id Codeium.Windsurf -e --silent --accept-source-agreements --accept-package-agreements

    関連する外部ページ

    Windsurf の公式ページ: https://windsurf.com/

  3. 必要なPythonライブラリのインストール
    1. Windowsで、管理者権限コマンドプロンプトを起動(手順:Windowsキーまたはスタートメニュー > cmd と入力 > 右クリック > 「管理者として実行」)。
    2. 以下のコマンドを実行し、必要なライブラリをインストールする。
      pip install -U numpy opencv-python

【関連する外部ページ】

【サイト内の関連ページ】

色空間変換

概要

色空間変換とは、デジタル画像の色表現を異なる色空間へと変換する画像処理である。BGRからHSVへの変換を行うことで、色相(Hue)、彩度(Saturation)、明度(Value)を独立させることができる。これにより、照明条件が変化する環境下での色検出が容易になる。

使用されている技術

ソースコード: BGRからHSV色空間への変換

BGRからHSV色空間への変換を行うプログラムである。

import cv2
import urllib.request

# 画像のダウンロード
url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

# 色空間変換
img = cv2.imread("fruits.jpg")
hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
cv2.imshow('HSV', hsv)
cv2.waitKey(0)
cv2.destroyAllWindows()
BGRからHSVへの色空間変換結果

ソースコード: BGRからL*a*b*色空間への変換

BGRからL*a*b*色空間への変換を行うプログラムである。

import cv2
import urllib.request

# 画像のダウンロード
url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

# 色空間変換
img = cv2.imread("fruits.jpg")
lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)
cv2.imshow('L*a*b*', lab)
cv2.waitKey(0)
cv2.destroyAllWindows()
BGRからL*a*b*への色空間変換結果

CLAHE

概要

CLAHE(Contrast Limited Adaptive Histogram Equalization、適応的ヒストグラム平衡化)は、画像の局所領域ごとにコントラストを強調する手法である。通常のヒストグラム平衡化と異なり、局所領域ごとに処理を行うため、画像全体の視認性を均一に向上させることができる。

使用されている技術

ソースコード: CLAHEによるコントラスト強調(グレースケール画像)

グレースケール画像に対してCLAHEを適用するプログラムである。

import cv2
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

img = cv2.imread("fruits.jpg", 0)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(img)
cv2.imshow('CLAHE', cl1)
cv2.waitKey(0)
cv2.destroyAllWindows()
CLAHEによるグレースケール画像のコントラスト強調結果

ソースコード: CLAHEによるコントラスト強調(カラー画像)

カラー画像に対してCLAHEを適用するプログラムである。L*a*b*色空間に変換し、L*成分のみにCLAHEを適用することで、色情報を保持したままコントラストを強調する。

import cv2
import urllib.request

# 画像のダウンロード
url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

# 色空間変換
img = cv2.imread("fruits.jpg")
lab = cv2.cvtColor(img, cv2.COLOR_BGR2Lab)

# L*a*b*の各チャネルを分離
l, a, b = cv2.split(lab)

# L*成分にCLAHEを適用
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8, 8))
cl1 = clahe.apply(l)

# チャネルを結合
lab_clahe = cv2.merge([cl1, a, b])

# BGRに戻す
bgr = cv2.cvtColor(lab_clahe, cv2.COLOR_Lab2BGR)
cv2.imshow('Result', bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
CLAHEによるカラー画像のコントラスト強調結果

オプティカルフロー

概要

オプティカルフローは、連続する画像フレーム間の各画素の動きをベクトルとして検出する技術である。動体追跡やモーション解析に用いられる。

使用されている技術

ソースコード(2つの画像に関する処理)

2枚の連続画像間の動きを検出し、HSV色空間で可視化するプログラムである。動きの方向を色相、大きさを明度で表現する。

import cv2
import numpy as np
import urllib.request

url1 = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/rubberwhale1.png"
url2 = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/rubberwhale2.png"
urllib.request.urlretrieve(url1, "frame1.png")
urllib.request.urlretrieve(url2, "frame2.png")

prev_img = cv2.imread('frame1.png', cv2.IMREAD_GRAYSCALE)
next_img = cv2.imread('frame2.png', cv2.IMREAD_GRAYSCALE)

# オプティカルフローの計算
flow = cv2.calcOpticalFlowFarneback(prev_img, next_img, None, 0.5, 3, 15, 3, 5, 1.2, 0)

# フロー可視化用のHSV画像を生成
hsv = np.zeros((prev_img.shape[0], prev_img.shape[1], 3), dtype=np.uint8)
hsv[..., 1] = 255

# フローの大きさと角度を計算
mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
hsv[..., 0] = ang * 180 / np.pi / 2
hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)

# HSVからBGRに変換して表示
bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)

# 結果を表示
cv2.imshow('Optical Flow', bgr)
cv2.waitKey(0)
cv2.destroyAllWindows()
オプティカルフローの可視化結果

ソースコード(動画に関する処理)

動画またはWebカメラからオプティカルフローを計算するプログラムである。引数により入力ソースを切り替えることができる。

import cv2
import numpy as np
import urllib.request
import sys
import os

def print_usage():
    print("Usage:")
    print("  No argument: Download and use sample video (vtest.avi)")
    print("  Number (0,1,...): Use webcam with specified device number")
    print("  Filename: Use specified video file")

# 入力ソースの決定
if len(sys.argv) == 1:
    # 引数なし: サンプル動画をダウンロードして使用
    print("Using sample video (vtest.avi)")
    video_url = "https://github.com/opencv/opencv/raw/master/samples/data/vtest.avi"
    urllib.request.urlretrieve(video_url, "vtest.avi")
    cap = cv2.VideoCapture("vtest.avi")
elif sys.argv[1].isdigit():
    # 数字: WebCamを使用
    device_num = int(sys.argv[1])
    print(f"Using webcam device {device_num}")
    cap = cv2.VideoCapture(device_num)
else:
    # その他: ファイル名として解釈
    filename = sys.argv[1]
    if not os.path.exists(filename):
        print(f"Error: File '{filename}' not found")
        print_usage()
        exit()
    print(f"Using video file: {filename}")
    cap = cv2.VideoCapture(filename)

# 最初のフレームの読み込みとグレースケール変換
ret, prev_frame = cap.read()
if not ret:
    print("Error opening video source")
    print_usage()
    exit()
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)

# HSV画像の準備
hsv = np.zeros_like(prev_frame)
hsv[..., 1] = 255

while True:
    # 次のフレームの読み込み
    ret, next_frame = cap.read()
    if not ret:
        break
    next_gray = cv2.cvtColor(next_frame, cv2.COLOR_BGR2GRAY)

    # オプティカルフローの計算
    flow = cv2.calcOpticalFlowFarneback(prev_gray, next_gray, None, 0.5, 3, 15, 3, 5, 1.2, 0)

    # フローの大きさと角度を計算
    mag, ang = cv2.cartToPolar(flow[..., 0], flow[..., 1])
    hsv[..., 0] = ang * 180 / np.pi / 2
    hsv[..., 2] = cv2.normalize(mag, None, 0, 255, cv2.NORM_MINMAX)

    # HSVからBGRに変換して表示
    bgr = cv2.cvtColor(hsv, cv2.COLOR_HSV2BGR)
    cv2.imshow('Optical Flow', bgr)

    # 'q'キーを押すと終了
    if cv2.waitKey(30) & 0xFF == ord('q'):
        break

    # 現在のフレームを次のループのprev_frameとして設定
    prev_gray = next_gray

cap.release()
cv2.destroyAllWindows()

アフィン変換

概要

アフィン変換は、画像に対して平行移動、回転、拡大縮小、せん断などの幾何学的変換を行う手法である。変換後も平行線は平行線として保存される。

使用されている技術

ソースコード

3組の対応点を指定してアフィン変換を行うプログラムである。

import cv2
import numpy as np
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

img = cv2.imread("fruits.jpg")
rows, cols, ch = img.shape

# 変換元の点を画像サイズ内に制限
pts1 = np.float32([[min(50, cols-1), min(50, rows-1)],
                  [min(200, cols-1), min(50, rows-1)],
                  [min(50, cols-1), min(200, rows-1)]])

# 変換先の点を画像サイズ内に制限
pts2 = np.float32([[min(10, cols-1), min(100, rows-1)],
                  [min(200, cols-1), min(50, rows-1)],
                  [min(100, cols-1), min(250, rows-1)]])

M = cv2.getAffineTransform(pts1, pts2)
dst = cv2.warpAffine(img, M, (cols, rows))
cv2.imshow('Affine Transform', dst)
cv2.waitKey(0)
cv2.destroyAllWindows()
アフィン変換の結果

モルフォロジー演算

概要

モルフォロジー演算は、画像の形状に基づく処理を行う演算である。主に二値画像に対して適用され、ノイズ除去や形状の整形に用いられる。基本演算として膨張(dilation)と収縮(erosion)がある。

使用されている技術

ソースコード

収縮処理を行うプログラムである。

import cv2
import numpy as np
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

img = cv2.imread("fruits.jpg", 0)

# kernelサイズを画像サイズに応じて設定
kernel_size = max(3, min(5, img.shape[0]//100))
kernel = np.ones((kernel_size, kernel_size), np.uint8)

erosion = cv2.erode(img, kernel, iterations=1)
cv2.imshow('Erosion', erosion)
cv2.waitKey(0)
cv2.destroyAllWindows()
モルフォロジー演算(収縮)の結果

画像ピラミッド

概要

画像ピラミッドは、同一画像を異なる解像度で階層的に表現する手法である。物体検出やテンプレートマッチングにおいて、スケールの異なる対象を効率的に探索するために用いられる。

使用されている技術

ソースコード

画像の解像度を縮小・拡大するプログラムである。

import cv2
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

img = cv2.imread("fruits.jpg")
lower = cv2.pyrDown(img)
higher = cv2.pyrUp(lower)
cv2.imshow('Lower Resolution', lower)
cv2.imshow('Higher Resolution', higher)
cv2.waitKey(0)
cv2.destroyAllWindows()
画像ピラミッドによる解像度変換結果

テンプレートマッチング

概要

テンプレートマッチングは、画像内から指定したテンプレート画像と類似する領域を検出する手法である。

使用されている技術

ソースコード

テンプレートマッチングにより類似領域を検出するプログラムである。類似度0.8以上の領域を緑色矩形、テンプレート位置を赤色矩形で表示する。

import cv2
import numpy as np
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/smarties.png"
urllib.request.urlretrieve(url, "smarties.png")
img = cv2.imread("smarties.png", cv2.IMREAD_COLOR)  # カラー画像として読み込み

# テンプレート領域
template_x, template_y = 350, 50
template_w, template_h = 60, 60
template = img[template_y:template_y+template_h, template_x:template_x+template_w].copy()  # copyで切り出し

# 表示用画像のコピー作成
img_display = img.copy()

# テンプレートマッチング
result = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)

# スコア0.8以上の位置を緑色で表示
locations = np.where(result >= 0.8)
for y, x in zip(*locations):
    _ = cv2.rectangle(img_display, (x, y), (x+template_w, y+template_h), (0,255,0), 2)

# テンプレート位置を赤色で表示
_ = cv2.rectangle(img_display, (template_x,template_y), (template_x+template_w,template_y+template_h), (0,0,255), 2)

cv2.imshow('Template Matching', img_display)
cv2.waitKey(0)
cv2.destroyAllWindows()
テンプレートマッチングの結果

適応的閾値処理

概要

適応的閾値処理は、画像の局所領域ごとに閾値を計算して二値化を行う手法である。照明が不均一な画像に対しても適切な二値化が可能である。

使用されている技術

ソースコード

適応的閾値処理により二値化を行うプログラムである。

import cv2
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/sudoku.png"
urllib.request.urlretrieve(url, "sudoku.png")
img = cv2.imread("sudoku.png", 0)

# 画像サイズに応じたブロックサイズの設定
blockSize = max(3, min(img.shape[0], img.shape[1]) // 50)
if blockSize % 2 == 0:
   blockSize += 1  # ブロックサイズは奇数である必要がある

thresh = cv2.adaptiveThreshold(img, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                            cv2.THRESH_BINARY, blockSize, 2)

cv2.imshow('Adaptive Threshold', thresh)
cv2.waitKey(0)
cv2.destroyAllWindows()
適応的閾値処理による二値化結果

GrabCut画像セグメンテーション

概要

GrabCutは、画像の前景と背景を分離するセグメンテーションアルゴリズムである。ユーザが指定した矩形領域を基に、グラフカットによる最適化で前景を抽出する。

使用されている技術

ソースコード

矩形領域を指定して前景を抽出するプログラムである。

import cv2
import numpy as np
import urllib.request

url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/messi5.jpg"
urllib.request.urlretrieve(url, "messi5.jpg")
img = cv2.imread("messi5.jpg")
mask = np.zeros(img.shape[:2], np.uint8)
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
rect = (50, 50, 450, 290)
cv2.grabCut(img, mask, rect, bgdModel, fgdModel, 5, cv2.GC_INIT_WITH_RECT)
mask2 = np.where((mask == 2) | (mask == 0), 0, 1).astype('uint8')
img = img * mask2[:, :, np.newaxis]
cv2.imshow('GrabCut', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
GrabCutによる前景抽出結果

カラー画像表示

概要

カラー画像を読み込み、表示用に適切なサイズへ縮小するプログラムである。画像幅が1024ピクセルを超える場合に縮小処理を行う。

使用されている技術

ソースコード

画像を読み込み、必要に応じて縮小して表示するプログラムである。

import cv2
import urllib.request

# 画像のダウンロード
url = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/fruits.jpg"
urllib.request.urlretrieve(url, "fruits.jpg")

# 画像表示
img = cv2.imread("fruits.jpg")
height, width = img.shape[:2]

# 幅を1024以下にするための1/2または1/4倍リサイズ
if width > 1024:
   scale_factor = 0.5 if width / 2 > 1024 else 0.25
   new_width = int(width * scale_factor)
   new_height = int(height * scale_factor)
   resized_img = cv2.resize(img, (new_width, new_height),
                           interpolation=cv2.INTER_AREA)
else:
   resized_img = img

cv2.imshow('Resized Image', resized_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
カラー画像の表示結果

パソコンカメラ表示

概要

パソコンのカメラから映像を取得し、表示用に適切なサイズへ縮小するプログラムである。

使用されている技術

ソースコード

カメラ映像を取得し、縮小して表示するプログラムである。qキーで終了する。

import cv2
# カメラのキャプチャ
cap = cv2.VideoCapture(0)
while cap.isOpened():
   ret, frame = cap.read()
   if not ret:
       break
   height, width = frame.shape[:2]

   # 幅を1024以下にするための1/2または1/4倍リサイズ
   if width > 1024:
       scale_factor = 0.5 if width / 2 > 1024 else 0.25
       new_width = int(width * scale_factor)
       new_height = int(height * scale_factor)
       resized_frame = cv2.resize(frame, (new_width, new_height),
                                interpolation=cv2.INTER_AREA)
   else:
       resized_frame = frame
   cv2.imshow('Webcam', resized_frame)
   if cv2.waitKey(1) & 0xFF == ord('q'):
       break
cap.release()
cv2.destroyAllWindows()