OpenCVの特徴的な機能
【概要】 OpenCVには,色空間変換,局所的コントラスト強調,動体追跡,幾何学的変換,形状解析,多重解像度解析,パターン検出,適応的二値化,セグメンテーション等の多彩な機能がある.これらの機能は,照明変動への対応,動き検出,形状認識など,実用的な画像処理に有効である.
【目次】
- Python のインストールと必要なPythonライブラリのインストール
- 色空間変換
- CLAHE
- オプティカルフロー
- アフィン変換
- モルフォロジー演算
- 画像ピラミッド
- テンプレートマッチング
- 適応的閾値処理
- GrabCut画像セグメンテーション
- カラー画像表示
- パソコンカメラ表示
画像の色空間を変換する.BGRからHSVへの変換は,色検出にも有効である.
局所的コントラスト強調による適応的ヒストグラム平衡化により,画像の視認性を大幅に向上させる.
連続画像間の動きを検出し,リアルタイムな動体追跡とモーション解析を実現.
画像に対する平行移動,回転,拡大縮小などの変換である.
ノイズ除去,形状解析にも有用な場合がある.
異なる解像度の画像を階層的に生成し,スケール不変な画像解析を可能する基礎技術である.
画像内の特定パターンを検出する.
局所的な明るさに基づく二値化により,照明変動に頑健な処理を実現する.
グラフカットを用いた前景と背景の分離である.
【サイト内の関連情報】
ドクセルの URL: https://www.docswell.com/s/6674398749/51X845-2022-02-18-085434
Python のインストールと必要なPythonライブラリのインストール(Windows上)
- Python のインストール
注:既にPython(バージョン3.12を推奨)がインストール済みの場合は,この手順は不要である.
winget(Windowsパッケージマネージャー)を使用してインストールを行う
- 必要なPythonライブラリのインストール
【関連する外部ページ】
【サイト内の関連ページ】
色空間変換
概要
色空間変換とは,デジタル画像の色表現を異なる色空間へと変換する画像処理である.
特徴
BGRからHSVへの変換を行うことで,色相(Hue),彩度(Saturation),明度(Value)を独立させることができる.これは,照明条件が変化する環境下での解析に適する.
使用されている技術
- HSV変換は,色相・彩度・明度の3要素を用いた色表現手法である.人の視覚特性に基づいた画像処理を実現する.
- cv2.cvtColorは,OpenCVの色空間変換関数であり,BGRからHSVへの変換などを実現する.
- urllib.requestは,ネットワーク上の画像データをダウンロードするときに役立つ.
ソースコード: BGRからHSV色空間への変換
BGRからHSV色空間への変換プログラムである.OpenCVのcv2.cvtColor関数で色空間変換を行い,色相・彩度・明度を分離する.urllib.requestで画像を取得し,cv2.imshowで表示する.照明変動の影響を抑制できる特徴がある.
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からL*a*b*色空間への変換
BGRからL*a*b*色空間への変換プログラムである.L*a*b*色空間は,L*が輝度,a*とb*が色度を表す.OpenCVのcv2.cvtColor関数で色空間変換を行い,輝度と色度成分を分離する.urllib.requestで画像を取得し,cv2.imshowで表示する.色度成分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()

CLAHE
概要
CLAHE(適応的ヒストグラム平衡化)は,画像の局所領域のコントラストを強調し,画像全体の視認性を向上させる画像処理手法である.
使用されている技術
- ヒストグラム平衡化は,画像のコントラストを調整する処理手法である.
- urllib.requestは,ネットワーク上の画像データをダウンロードするときに役立つ.
ソースコード: CLAHEによるコントラスト強調(輝度成分のみ)
CLAHE(適応的ヒストグラム平衡化)のプログラムである.OpenCVのcreateCLAHE関数を使用し,局所的なコントラスト強調を行う.clipLimitとtileGridSizeのパラメータにより細部の強調度を制御し,画像の視認性を向上させる.
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によるコントラスト強調(カラー画像)
BGRからL*a*b*色空間に変換し,L*成分にCLAHEを適用する.その後BGRに戻して表示する.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()

オプティカルフロー
概要
オプティカルフローは,連続する画像フレーム間の動きを検出する技術である.動体追跡,モーション解析に用いられる.
使用されている技術
- Farneback法は,Dense Optical Flowを計算するアルゴリズムである.
- cv2.calcOpticalFlowFarnebackは,オプティカルフローを計算する関数である.
- urllib.requestは,ネットワーク上の画像データをダウンロードするときに役立つ.
- cv2.cartToPolarは,フローの大きさと角度を計算する関数である.
- cv2.normalizeは,フロー強度を所定の範囲に調整する関数である.
- cv2.cvtColorは,HSVとBGR間の色空間変換を行う関数である.
ソースコード(2つの画像に関する処理)
連続する画像フレーム間の動きを検出するプログラムである.Farneback法でDense Optical Flowを算出し,cv2.cartToPolarで動きの大きさと角度を算出する.検出した動きは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カメラを使用(例: python script.py 0)
- ファイル名を指定: 指定された動画ファイルを使用(例: python script.py video.mp4)
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()
アフィン変換
概要
アフィン変換は,画像の幾何学的変換を行う手法である.平行移動,回転,拡大縮小と,その複合的な変換を実現する.
使用されている技術
- アフィン変換行列は,複雑な幾何学的変換を記述する行列である.
- cv2.getAffineTransformは,3点のペアからアフィン変換行列を生成する関数である.
- cv2.warpAffineは,アフィン変換行列を用いて画像を変換する関数である.
- urllib.requestは,ネットワーク上の画像データをダウンロードするときに役立つ.
ソースコード
アフィン変換のプログラムである.cv2.getAffineTransformで3点のペアから変換行列を生成し,cv2.warpAffineで画像を変換する.平行移動・回転・拡大縮小などの幾何学的変換を行う.画像範囲内での変換を保証するようにしている.
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()

モルフォロジー演算
概要
モルフォロジー演算は,画像の形状に基づく処理を行う演算である.ノイズ除去,形状解析に有用である.
使用されている技術
- 膨張と収縮は,基本的なモルフォロジー演算である.
- cv2.erodeは,画像の収縮処理の関数である.
- urllib.requestは,ネットワーク上の画像データをダウンロードするときに役立つ.
- kernelは,モルフォロジー演算の処理範囲を定義する行列である.
ソースコード
収縮処理を実装したプログラムである.画像サイズに応じたkernelを生成し,cv2.erode関数で処理を行う.形状の縮小とノイズ除去が可能である.
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()

画像ピラミッド
概要
画像ピラミッドとは,異なる解像度の画像を生成し,多重解像度解析を可能とする手法である.解像度の階層化により,スケール不変な解析を実現する.ピラミッドダウン/アップでは,解像度を下げる/上げる操作を行い,画像の多重スケール解析に用いられる.
ソースコード
画像ピラミッド処理を実装したプログラムである.cv2.pyrDownとcv2.pyrUpにより画像の解像度を階層的に変更する.低解像度化と高解像度化の双方向の解像度変換を行う.
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()

テンプレートマッチング
概要
テンプレートマッチングは,画像内での特定パターンの検出を行う手法である.パターン検出により,画像内の類似部分を特定する.
ソースコード
テンプレートマッチングを実装したプログラムである.相関法により画像とテンプレートの類似度を計算し,正規化相互相関係数を用いた検出を実現する.cv2.matchTemplateと正規化相互相関係数(TM_CCOEFF_NORMED)を用いて画像内の類似パターンを検出する.閾値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()

適応的閾値処理
概要
適応的閾値処理は,画像の局所的な明るさに基づいて二値化を行う手法である.局所的な二値化により,照明変動の影響を抑制する.適応的二値化では局所領域ごとに閾値を計算し二値化を行う.
ソースコード
適応的閾値処理のプログラムである.cv2.adaptiveThresholdを用いて局所的な明るさに基づく二値化を行う.画像サイズに応じたブロックサイズを設定し,ガウシアン重み付けによる局所閾値で処理する.
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は,画像の前景と背景を半自動的に分離するアルゴリズムである.グラフカットアルゴリズムにより,エネルギー最小化に基づくセグメンテーションを実現する.
ソースコード
GrabCutアルゴリズムによる画像セグメンテーションのプログラムである.マスク値が2(背景推定)または0(背景確定)の領域を背景として除去し,前景領域を抽出する.cv2.grabCutと65次元特徴空間のモデルを用いて前景と背景を分離する.グラフカットベースの最適化により,5回の反復で領域分割を行う.
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()

カラー画像表示
概要
カラー画像を読み込み,画像幅が1024ピクセルを超える場合には,画像幅に応じて1/2倍または1/4倍で,INTER_AREA法による面積平均を用いた縮小処理を行う.
ソースコード
画像の縮小のプログラムである.OpenCVの画像読み込み(imread)によりBGRカラー形式で画像データを取得し,cv2.resizeとINTER_AREA法で縮小処理を行う.
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()

パソコンカメラ表示
概要
パソコンのカメラから映像を取得し,映像幅に応じて,INTER_AREA法で,1/2倍または1/4倍の縮小を行う.
ソースコード
PCカメラの画像の映像処理のプログラムである.cv2.VideoCaptureでカメラからフレームを取得し,INTER_AREA法で縮小処理を行う.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()