新4年生用

【Python入門3】OpenCVで画像処理&カメラ制御

はじめに

このテキストは、Python初心者むけのOpenCVライブラリを使った画像処理・コンピュータビジョンの基礎講座です。新大学4年生を対象とし、C言語の基礎知識はあるものの、Pythonはほとんど触れたことがない方向けです。Windows 11環境のSpyderを使用して、PCに搭載されたウェブカメラを活用した実践的な内容となっています。

前回はPythonの基本的な構文の理解とOpenCVの基本を少しだけ取り扱いました。

今回はより実践向けの内容として、以下の目標を設定して取り組みます。すべて覚えようとせず、こういうことが出来るということだけでも覚えておいてもらうだけで、後々役に立つと思います。

学習目標

  • 画像処理の基本概念を理解する
  • ウェブカメラからのリアルタイム画像処理ができる

所要時間: 約2時間
必要環境:

  • Windows 11
  • Spyder (Python IDE)
  • ウェブカメラ

目次

  1. 画像処理の基礎
    • 画像のリサイズと回転
    • 画像のトリミングと合成
    • 基本的なフィルタリング処理
  2. ウェブカメラの活用
    • カメラからの映像取得
    • リアルタイム画像処理
    • キー入力によるインタラクション

画像のリサイズと回転

画像のサイズ変更や回転などの基本的な変換操作を行います。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像の読み込み
img = cv2.imread('sample.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# リサイズ
resized = cv2.resize(img, (320, 240))  # 幅320px, 高さ240pxに変更

# 回転
height, width = img.shape[:2]
center = (width // 2, height // 2)
rotation_matrix = cv2.getRotationMatrix2D(center, 45, 1.0)  # 45度回転
rotated = cv2.warpAffine(img, rotation_matrix, (width, height))

# 表示
plt.figure(figsize=(12, 4))

plt.subplot(131)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Original')
plt.axis('off')

plt.subplot(132)
plt.imshow(cv2.cvtColor(resized, cv2.COLOR_BGR2RGB))
plt.title('Resized (320x240)')
plt.axis('off')

plt.subplot(133)
plt.imshow(cv2.cvtColor(rotated, cv2.COLOR_BGR2RGB))
plt.title('Rotated (45°)')
plt.axis('off')

plt.tight_layout()
plt.show()

画像のトリミングと合成

画像の一部を切り出したり、複数の画像を合成したりする方法です。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像の読み込み
img = cv2.imread('sample.jpg')

# トリミング(画像の一部を切り出す)
height, width = img.shape[:2]
# 中央付近を切り出す
start_x = width // 4
start_y = height // 4
end_x = start_x + width // 2
end_y = start_y + height // 2
cropped = img[start_y:end_y, start_x:end_x]

# 画像の合成(加重平均)
# 同じサイズの別の画像が必要
img2 = cv2.imread('sample2.jpg')  # 別の画像
if img2 is not None and img2.shape == img.shape:
    blended = cv2.addWeighted(img, 0.7, img2, 0.3, 0)
else:
    # 別の画像がない場合は、元画像のぼかしたバージョンと合成
    blurred = cv2.GaussianBlur(img, (99, 99), 0)
    blended = cv2.addWeighted(img, 0.7, blurred, 0.3, 0)

# 表示
plt.figure(figsize=(12, 4))

plt.subplot(131)
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('Original')
plt.axis('off')

plt.subplot(132)
plt.imshow(cv2.cvtColor(cropped, cv2.COLOR_BGR2RGB))
plt.title('Cropped')
plt.axis('off')

plt.subplot(133)
plt.imshow(cv2.cvtColor(blended, cv2.COLOR_BGR2RGB))
plt.title('Blended')
plt.axis('off')

plt.tight_layout()
plt.show()

基本的なフィルタリング処理

画像にフィルターを適用して、ぼかしやエッジ強調などの効果を与えます。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像の読み込み
img = cv2.imread('sample.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# グレースケールに変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# ガウシアンぼかし
blurred = cv2.GaussianBlur(img, (15, 15), 0)

# ソーベルフィルタ(エッジ検出)
sobelx = cv2.Sobel(gray, cv2.CV_64F, 1, 0, ksize=3)
sobely = cv2.Sobel(gray, cv2.CV_64F, 0, 1, ksize=3)
sobelx = np.absolute(sobelx)
sobely = np.absolute(sobely)
sobel_combined = cv2.bitwise_or(sobelx.astype(np.uint8), sobely.astype(np.uint8))

# 表示
plt.figure(figsize=(12, 8))

plt.subplot(221)
plt.imshow(img_rgb)
plt.title('Original')
plt.axis('off')

plt.subplot(222)
plt.imshow(cv2.cvtColor(blurred, cv2.COLOR_BGR2RGB))
plt.title('Gaussian Blur')
plt.axis('off')

plt.subplot(223)
plt.imshow(gray, cmap='gray')
plt.title('Grayscale')
plt.axis('off')

plt.subplot(224)
plt.imshow(sobel_combined, cmap='gray')
plt.title('Sobel Edge Detection')
plt.axis('off')

plt.tight_layout()
plt.show()

演習: 画像フィルタリングの実験

いくつかの異なるフィルターを適用して、その効果を比較してみましょう。

import cv2
import numpy as np
import matplotlib.pyplot as plt

# 画像の読み込み
img = cv2.imread('sample.jpg')
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

# グレースケールに変換
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# いくつかの異なるフィルター
# 1. 平均化フィルタ(単純なぼかし)
blur = cv2.blur(img, (15, 15))

# 2. メディアンフィルタ(ノイズ除去に効果的)
median = cv2.medianBlur(img, 15)

# 3. バイラテラルフィルタ(エッジを保持しながらぼかし)
bilateral = cv2.bilateralFilter(img, 15, 75, 75)

# 4. シャープニング
kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]])
sharpened = cv2.filter2D(img, -1, kernel)

# 表示
plt.figure(figsize=(15, 10))

plt.subplot(231)
plt.imshow(img_rgb)
plt.title('Original')
plt.axis('off')

plt.subplot(232)
plt.imshow(cv2.cvtColor(blur, cv2.COLOR_BGR2RGB))
plt.title('Average Blur')
plt.axis('off')

plt.subplot(233)
plt.imshow(cv2.cvtColor(median, cv2.COLOR_BGR2RGB))
plt.title('Median Blur')
plt.axis('off')

plt.subplot(234)
plt.imshow(cv2.cvtColor(bilateral, cv2.COLOR_BGR2RGB))
plt.title('Bilateral Filter')
plt.axis('off')

plt.subplot(235)
plt.imshow(cv2.cvtColor(sharpened, cv2.COLOR_BGR2RGB))
plt.title('Sharpening')
plt.axis('off')

plt.tight_layout()
plt.show()

4. ウェブカメラの活用

カメラからの映像取得

PCに接続されたウェブカメラから映像を取得し、リアルタイムで表示します。

import cv2

# カメラをキャプチャ
cap = cv2.VideoCapture(0)  # 0は通常、最初のカメラデバイス

# カメラが正しく開かれたか確認
if not cap.isOpened():
    print("カメラを開けませんでした")
    exit()

print("カメラからの映像を表示します。終了するには 'q' キーを押してください。")

while True:
    # フレームを取得
    ret, frame = cap.read()
    
    # フレームが正しく取得できたか確認
    if not ret:
        print("フレームを取得できませんでした")
        break
    
    # フレームを表示
    cv2.imshow('Webcam', frame)
    
    # 'q'キーが押されたら終了
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# リソースを解放
cap.release()
cv2.destroyAllWindows()

リアルタイム画像処理

ウェブカメラからの映像にリアルタイムで画像処理を適用します。

import cv2
import numpy as np

# カメラをキャプチャ
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラを開けませんでした")
    exit()

print("リアルタイム画像処理のデモです。終了するには 'q' キーを押してください。")
print("処理モードの切り替え: '1'=通常, '2'=グレースケール, '3'=エッジ検出, '4'=ぼかし")

mode = 1  # 初期モードは通常表示

while True:
    # フレームを取得
    ret, frame = cap.read()
    
    if not ret:
        print("フレームを取得できませんでした")
        break
    
    # 処理モードに応じて画像処理
    if mode == 1:
        # 通常表示
        display_frame = frame
    elif mode == 2:
        # グレースケール
        display_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 3チャンネルに戻す(表示用)
        display_frame = cv2.cvtColor(display_frame, cv2.COLOR_GRAY2BGR)
    elif mode == 3:
        # エッジ検出(Canny)
        edges = cv2.Canny(frame, 100, 200)
        display_frame = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
    elif mode == 4:
        # ガウシアンぼかし
        display_frame = cv2.GaussianBlur(frame, (15, 15), 0)
    
    # フレームを表示
    cv2.imshow('Processed Webcam', display_frame)
    
    # キー入力をチェック
    key = cv2.waitKey(1) & 0xFF
    
    # 'q'で終了
    if key == ord('q'):
        break
    # '1'~'4'でモード切替
    elif key == ord('1'):
        mode = 1
    elif key == ord('2'):
        mode = 2
    elif key == ord('3'):
        mode = 3
    elif key == ord('4'):
        mode = 4

# リソースを解放
cap.release()
cv2.destroyAllWindows()

キー入力によるインタラクション

キー入力に応じて様々な効果を切り替えるインタラクティブなアプリケーションを作成します。

import cv2
import numpy as np

def apply_cartoon_effect(img):
    # エッジ検出
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    gray = cv2.medianBlur(gray, 5)
    edges = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_MEAN_C, 
                                cv2.THRESH_BINARY, 9, 9)
    
    # 色の量子化
    color = cv2.bilateralFilter(img, 9, 300, 300)
    
    # エッジと色を組み合わせる
    cartoon = cv2.bitwise_and(color, color, mask=edges)
    
    return cartoon

# カメラをキャプチャ
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラを開けませんでした")
    exit()

print("インタラクティブカメラのデモです。終了するには 'q' キーを押してください。")
print("エフェクト切替: '1'=通常, '2'=グレースケール, '3'=エッジ検出")
print("            '4'=ぼかし, '5'=セピア, '6'=カートゥーン")

mode = 1  # 初期モードは通常表示
recording = False
frames = []

while True:
    # フレームを取得
    ret, frame = cap.read()
    
    if not ret:
        print("フレームを取得できませんでした")
        break
    
    # 処理モードに応じて画像処理
    if mode == 1:
        # 通常表示
        display_frame = frame.copy()
    elif mode == 2:
        # グレースケール
        display_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # 3チャンネルに戻す(表示用)
        display_frame = cv2.cvtColor(display_frame, cv2.COLOR_GRAY2BGR)
    elif mode == 3:
        # エッジ検出(Canny)
        edges = cv2.Canny(frame, 100, 200)
        display_frame = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)
    elif mode == 4:
        # ガウシアンぼかし
        display_frame = cv2.GaussianBlur(frame, (15, 15), 0)
    elif mode == 5:
        # セピア効果
        kernel = np.array([[0.272, 0.534, 0.131],
                           [0.349, 0.686, 0.168],
                           [0.393, 0.769, 0.189]])
        display_frame = cv2.transform(frame, kernel)
    elif mode == 6:
        # カートゥーン効果
        display_frame = apply_cartoon_effect(frame)
    
    # モード表示
    mode_text = f"Mode: {mode}"
    cv2.putText(display_frame, mode_text, (10, 30), 
                cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    
    # 録画中表示
    if recording:
        cv2.putText(display_frame, "REC", (display_frame.shape - 70, 30), 
                    cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
        frames.append(display_frame.copy())
    
    # フレームを表示
    cv2.imshow('Interactive Camera', display_frame)
    
    # キー入力をチェック
    key = cv2.waitKey(1) & 0xFF
    
    # 'q'で終了
    if key == ord('q'):
        break
    # '1'~'6'でモード切替
    elif key >= ord('1') and key <= ord('6'):
        mode = key - ord('0')  # '1'->1, '2'->2, ...
    # 'r'で録画開始/停止
    elif key == ord('r'):
        recording = not recording
        if not recording and frames:
            print("録画を保存中...")
            # 動画を保存
            height, width = frames[0].shape[:2]
            fourcc = cv2.VideoWriter_fourcc(*'XVID')
            out = cv2.VideoWriter('output.avi', fourcc, 20.0, (width, height))
            
            for frame in frames:
                out.write(frame)
            
            out.release()
            frames = []
            print("録画を保存しました: output.avi")

# リソースを解放
cap.release()
cv2.destroyAllWindows()

演習: シンプルな写真アプリ

簡単な写真撮影アプリを作成します。スペースキーで写真を撮影し、保存します。

import cv2
import time
import os

# 保存ディレクトリの作成
save_dir = 'captured_photos'
if not os.path.exists(save_dir):
    os.makedirs(save_dir)

# カメラをキャプチャ
cap = cv2.VideoCapture(0)

if not cap.isOpened():
    print("カメラを開けませんでした")
    exit()

print("シンプル写真アプリです。終了するには 'q' キーを押してください。")
print("写真撮影: スペースキー")

counter = 0  # 撮影カウンター
countdown = 0  # カウントダウン用
last_capture_time = 0  # 最後に撮影した時間

while True:
    # フレームを取得
    ret, frame = cap.read()
    
    if not ret:
        print("フレームを取得できませんでした")
        break
    
    # 表示用フレーム
    display_frame = frame.copy()
    
    # 現在の時間
    current_time = time.time()
    
    # カウントダウン中の処理
    if countdown > 0:
        # 大きなカウントダウン表示
        cv2.putText(display_frame, str(countdown), 
                    (display_frame.shape//2 - 20, display_frame.shape[0]//2 + 20), 
                    cv2.FONT_HERSHEY_SIMPLEX, 3, (0, 255, 255), 5)
        
        # 1秒経過したらカウントダウンを減らす
        if current_time - last_capture_time >= 1:
            countdown -= 1
            last_capture_time = current_time
            
            # カウントダウンが0になったら撮影
            if countdown == 0:
                # 写真のファイル名
                filename = os.path.join(save_dir, f'photo_{counter}.jpg')
                cv2.imwrite(filename, frame)
                print(f"写真を保存しました: {filename}")
                counter += 1
                
    # 操作ガイド表示
    cv2.putText(display_frame, "Space: Capture Photo", (10, 30), 
                cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
    
    # 最後に撮影した写真の名前を表示(撮影直後)
    if current_time - last_capture_time < 2 and countdown == 0 and counter > 0:
        cv2.putText(display_frame, f"Saved as: photo_{counter-1}.jpg", 
                    (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)
    
    # フレームを表示
    cv2.imshow('Photo App', display_frame)
    
    # キー入力をチェック
    key = cv2.waitKey(1) & 0xFF
    
    # 'q'で終了
    if key == ord('q'):
        break
    # スペースキーで撮影(カウントダウン開始)
    elif key == 32 and countdown == 0:  # 32はスペースキーのASCIIコード
        countdown = 3  # 3秒カウントダウン
        last_capture_time = current_time

# リソースを解放
cap.release()
cv2.destroyAllWindows()

問題: リアルタイムフィルターアプリケーション

これまで学んだOpenCVの知識を活用して、ウェブカメラからのリアルタイム映像に複数の画像処理効果を適用するアプリケーションを作成してください。

要件:

  1. 以下の4つの処理モードを実装し、キー入力で切り替えられるようにします:
    • ノーマル (キー: 1): 通常のカメラ映像
    • スプリットビュー (キー: 2): 画面を4分割し、それぞれに異なる処理を適用(元画像、グレースケール、エッジ検出、ぼかし)
    • カラーフィルター (キー: 3): 特定の色相範囲のみを表示し、他はグレースケール化
    • ミラーモード (キー: 4): 画面を左右に分割し、片方は通常、もう片方は左右反転
  2. 画面上部にテキストで現在のモードを表示
  3. ‘s’キーを押すと、現在の画面を画像ファイルとして保存
  4. ‘q’キーで終了

ヒント 1: 画面分割には、NumPy配列の操作(スライシングや連結)を使うと便利です。

ヒント 2: カラーフィルターには、HSV色空間に変換して色相(Hue)の範囲でマスクを作成する方法が効果的です。

ヒント 3: 画像の左右反転には、cv2.flip()関数が使えます。

オプション課題: トラックバーを追加して、カラーフィルターの色相範囲やぼかしの強度をリアルタイムで調整できるようにしてみましょう。

解答例

import cv2
import numpy as np
import os
from datetime import datetime

def apply_color_filter(frame, hue_min=20, hue_max=40):
    # HSV色空間に変換
    hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)  # BGRからHSVに変換

    # 指定した色相範囲のマスクを作成
    lower_bound = np.array([hue_min, 50, 50])  # 下限値(色相、彩度、明度)
    upper_bound = np.array([hue_max, 255, 255])  # 上限値
    mask = cv2.inRange(hsv, lower_bound, upper_bound)  # マスク作成

    # 元の画像をグレースケール化
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    gray_bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)  # 3チャネルに戻す

    # マスクを使って合成(マスク部分はカラー、他はグレースケール)
    result = frame.copy()  # 元の画像をコピー
    gray_bgr_masked = cv2.bitwise_and(gray_bgr, gray_bgr, mask=~mask)  # マスク外をグレースケール
    color_masked = cv2.bitwise_and(frame, frame, mask=mask)  # マスク内をカラーで
    result = cv2.add(gray_bgr_masked, color_masked)  # 2つの画像を合成

    return result

def save_frame(frame):
    # 保存ディレクトリの作成
    if not os.path.exists('captured'):
        os.makedirs('captured')

    # タイムスタンプ付きのファイル名を生成
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    filename = os.path.join('captured', f'frame_{timestamp}.jpg')

    # 画像を保存
    cv2.imwrite(filename, frame)  # ファイルに保存
    return filename

def main():
    # カメラをキャプチャ
    cap = cv2.VideoCapture(0)  # 0番目のカメラを使用

    if not cap.isOpened():
        print("カメラを開けませんでした")
        return

    print("リアルタイムフィルターアプリケーション")
    print("モード切替: '1'=通常, '2'=スプリットビュー, '3'=カラーフィルター, '4'=ミラーモード")
    print("'s'キーで画面保存, 'q'キーで終了")

    mode = 1  # 初期モードは通常表示
    hue_min, hue_max = 20, 40  # 初期の色相範囲(黄色系)

    # ウィンドウとトラックバーの設定
    cv2.namedWindow('Filter App')
    cv2.createTrackbar('Hue Min', 'Filter App', hue_min, 179, lambda x: None)  # 色相の最大値は179
    cv2.createTrackbar('Hue Max', 'Filter App', hue_max, 179, lambda x: None)

    while True:
        # フレームを取得
        ret, frame = cap.read()  # カメラから1フレーム読み込み

        if not ret:
            print("フレームを取得できませんでした")
            break

        # トラックバーの値を取得
        hue_min = cv2.getTrackbarPos('Hue Min', 'Filter App')  # トラックバーから最小色相値を取得
        hue_max = cv2.getTrackbarPos('Hue Max', 'Filter App')  # トラックバーから最大色相値を取得

        # 処理モードに応じて画像処理
        if mode == 1:
            # 通常表示
            display_frame = frame.copy()  # 元のフレームをそのまま表示
            mode_text = "Mode: Normal"  # 表示するモードテキスト

        elif mode == 2:
            # スプリットビュー(4分割)
            height, width = frame.shape[:2]
            half_h, half_w = height // 2, width // 2

            # 各種処理を適用
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)  # グレースケール
            gray_bgr = cv2.cvtColor(gray, cv2.COLOR_GRAY2BGR)  # 3チャンネルに戻す

            edges = cv2.Canny(frame, 100, 200)  # エッジ検出
            edges_bgr = cv2.cvtColor(edges, cv2.COLOR_GRAY2BGR)  # 3チャンネルに戻す

            blurred = cv2.GaussianBlur(frame, (15, 15), 0)  # ぼかし

            # 1/4サイズにリサイズ
            frame_small = cv2.resize(frame, (half_w, half_h))  # 元画像を縮小
            gray_small = cv2.resize(gray_bgr, (half_w, half_h))  # グレースケールを縮小
            edges_small = cv2.resize(edges_bgr, (half_w, half_h))  # エッジを縮小
            blurred_small = cv2.resize(blurred, (half_w, half_h))  # ぼかしを縮小

            # 上半分と下半分を作成して連結
            top_row = np.hstack((frame_small, gray_small))  # 上段:元画像とグレースケール
            bottom_row = np.hstack((edges_small, blurred_small))  # 下段:エッジとぼかし
            display_frame = np.vstack((top_row, bottom_row))  # 上下段を連結

            mode_text = "Mode: Split View"  # 表示するモードテキスト

        elif mode == 3:
            # カラーフィルター
            display_frame = apply_color_filter(frame, hue_min, hue_max)  # 色相フィルタを適用
            mode_text = f"Mode: Color Filter (Hue: {hue_min}-{hue_max})"  # 表示するモードテキスト

        elif mode == 4:
            # ミラーモード
            height, width = frame.shape[:2]
            half_w = width // 2

            # 左半分は通常
            left = frame[:, :half_w].copy()  # 左半分を抽出

            # 右半分は左右反転
            right = cv2.flip(frame[:, :half_w], 1)  # 左半分を左右反転

            # 左右を連結
            display_frame = np.hstack((left, right))  # 左右を連結

            mode_text = "Mode: Mirror Mode"  # 表示するモードテキスト

        # モード表示
        cv2.putText(display_frame, mode_text, (10, 30), 
                    cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2)  # テキストを画像に追加

        # フレームを表示
        cv2.imshow('Filter App', display_frame)  # 処理したフレームを表示

        # キー入力をチェック
        key = cv2.waitKey(1) & 0xFF

        # 'q'で終了
        if key == ord('q'):
            break
        # '1'~'4'でモード切替
        elif key >= ord('1') and key <= ord('4'):
            mode = key - ord('0')  # キーコードを数値に変換('1'→1)
        # 's'で画面保存
        elif key == ord('s'):
            filename = save_frame(display_frame)  # 現在の表示フレームを保存
            print(f"画面を保存しました: {filename}")

    # リソースを解放
    cap.release()  # カメラをリリース
    cv2.destroyAllWindows()  # すべてのウィンドウを閉じる

if __name__ == "__main__":
    main()

解説

このプログラムは、ウェブカメラの映像に複数のフィルター効果を適用するインタラクティブなアプリケーションです。主な機能と実装のポイントを解説します:

1. 基本構造

  • カメラのキャプチャと初期設定を行うメインループを実装
  • モード変数を使って、4つの異なる表示モードを切り替え
  • トラックバーを実装して、カラーフィルターのパラメータをリアルタイムで調整できるようにしています

2. 実装された機能

  1. 通常モード (mode=1): カメラの映像をそのまま表示します。
  2. スプリットビュー (mode=2):
    • 画面を4分割して、それぞれに異なる処理を適用
    • 元画像、グレースケール、エッジ検出、ぼかしを同時に表示
    • np.hstack()とnp.vstack()を使って画像を連結しています
  3. カラーフィルター (mode=3):
    • HSV色空間で指定した色相範囲のみをカラー表示し、それ以外をグレースケール化
    • cv2.inRange()でマスクを作成し、cv2.bitwise_and()とcv2.add()で合成
    • トラックバーで色相範囲を調整可能
  4. ミラーモード (mode=4):
    • 画面を左右に分割し、一方は通常、もう一方は左右反転
    • cv2.flip()関数でフレームを反転
  5. 画面保存機能: 'sキーで現在の表示画面を日時付きのファイル名で保存

3. 技術的なポイント

  • 色空間変換: カラーフィルターではBGR→HSV変換を活用して、特定の色相範囲を抽出しています。
  • 画像連結: NumPyのhstack()とvstack()関数を使って、複数の画像を結合しています。
  • マスク処理: マスクと論理演算を組み合わせて、選択的な画像処理を実現しています。
  • インタラクティブな調整: OpenCVのトラックバー機能を使って、リアルタイムでパラメータを調整できるようにしています。

4. テキストで学んだ内容の活用

このプログラムでは、テキストで学んだ以下の要素を組み合わせています:

  • ウェブカメラからのリアルタイム映像取得
  • 基本的な画像処理(グレースケール変換、エッジ検出、ぼかし)
  • キー入力によるインタラクション
  • 画像の保存
  • 画面へのテキスト表示
  • トラックバーによるパラメータ調整

5. 発展・改良のアイデア

このプログラムをさらに発展させるためのアイデア:

  • 顔検出と組み合わせて、検出された顔にのみエフェクトを適用
  • より多くのフィルター効果(セピア、モザイク、漫画風など)を追加
  • 動画として録画する機能の追加
  • GUIボタンでモード切替できるようにする

まとめ

今回はOpenCVの基本的な画像処理とカメラの制御を取り扱いました。

次回は顔検出やモーション検出を行います。