OpenCV でビデオカメラ画像の表示,ファイル書き出し,濃淡画像処理(Python を使用)
【目次】
【関連する外部ページ】
- OpenCV の公式ページ: https://opencv.org
- GitHub の OpenCV のページ: https://github.com/opencv/opencv/releases
【付記】 本ページのプログラムはAIのアシストを受けて作成しています
【サイト内の関連ページ】
- OpenCV について [PDF] , [パワーポイント]
- OpenCVとPythonを活用した画像・ビデオ処理プログラム: 別ページ »
前準備
Python のインストール(Windows,Ubuntu 上)
- Windows での Python 3.10,関連パッケージ,Python 開発環境のインストール(winget を使用しないインストール): 別ページ »で説明
- Ubuntu では,システム Pythonを使うことができる.Python3 開発用ファイル,pip, setuptools のインストール: 別ページ »で説明
【サイト内の関連ページ】
- Python のまとめ: 別ページ »にまとめ
- Google Colaboratory の使い方など: 別ページ »で説明
【関連する外部ページ】 Python の公式ページ: https://www.python.org/
Python 開発環境のインストール
- Windows での Python 開発環境として,Jupyter Qt Console, Jupyter ノートブック (Jupyter Notebook), Jupyter Lab, Nteract, spyder のインストール: 別ページ »で説明
- Windows での PyCharm のインストール: 別ページ »で説明
- Windows での PyScripter のインストール: 別ページ »で説明
OpenCV Python のインストール
Python で OpenCV を動かすためのもの.
OpenCV Python のインストールは:別ページ »で説明1~2 コマンドの実行でインストールできる.
カメラ画像の表示
USB接続できるビデオカメラを準備し,パソコンに接続しておく.
Python プログラムの実行
- Windows では python (Python ランチャーは py)
- Ubuntu では python3
【サイト内の関連ページ】 Python のまとめ: 別ページ »
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
cv2.imshow("カメラ映像", f)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()
止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
表示サイズを変える
ビデオカメラを準備し,パソコンに接続しておく.
Python プログラムの実行
- Windows では python (Python ランチャーは py)
- Ubuntu では python3
【サイト内の関連ページ】 Python のまとめ: 別ページ »
【プログラムの機能】
カメラからリアルタイムで映像を取得し,指定した幅(640ピクセル)にリサイズして表示する.アスペクト比を保持しながらフレームをリサイズする.'q'キーで終了する.
【プログラムの説明】
OpenCVを使用したリアルタイムカメラ映像のリサイズと表示
- opencv-python の使用
opencv-python は,OpenCV を Python から利用するためのもの
- リサイズを行う resize_frame 関数
resize_frame関数は,入力された画像を指定した幅にリサイズする.この際,アスペクト比を保持するように高さを計算する.
- メインループ
while True ループ内で以下の処理を繰り返す.
- カメラから1フレーム読み取り
- フレームをリサイズ
- リサイズしたフレームを表示
- キー入力のチェック('q'キーで終了)」
- エラー処理
カメラが開けない場合や,フレームの読み取りに失敗した場合にはエラーメッセージを表示し,プログラムを終了する.
- リソースの解放
プログラム終了時には,v.release()でカメラを解放し,cv2.destroyAllWindows()で作成したウィンドウを閉じる.
- カスタマイズ
resize_width変数を変更することで,リサイズする幅を調整できる.また,cv2.VideoCapture(0)の0を変更することで,異なるカメラを選択できる.
【プログラムの実行法】
このプログラムを実行すると,カメラの映像が表示され,'q'キーで終了できる. 注意点として,カメラへのアクセス権限が必要で,既定(デフォルト)ではインデックス0のカメラを使用する.リサイズ幅はプログラムを書き換えることで調整可能である.また,プログラムは適切にリソースを解放するが,強制終了時('q'キーで終了しなかった場合)にはカメラが解放されない場合がある.
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# フレームをリサイズ
resized_frame = resize_frame(f, resize_width)
cv2.imshow("カメラ映像", resized_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()
止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
カラー画像から濃淡画像への変換
USB接続できるビデオカメラを準備し,パソコンに接続しておく.
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
def convert_to_grayscale(frame):
return cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# フレームをリサイズ
resized_frame = resize_frame(f, resize_width)
# カラー画像を濃淡画像に変換
gray_frame = convert_to_grayscale(resized_frame)
# カラー画像を表示
cv2.imshow("カラーカメラ映像", resized_frame)
# 濃淡画像を表示
cv2.imshow("濃淡カメラ映像", gray_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()

* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
動画ファイルの書き出し
USB接続できるビデオカメラを準備し,パソコンに接続しておく.
import cv2
import numpy as np
import time
# 表示用にリサイズする幅を指定(例:640ピクセル)
display_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
def create_video_writer(output_filename, fps, frame_size):
fourcc = cv2.VideoWriter_fourcc(*'XVID')
return cv2.VideoWriter(output_filename, fourcc, fps, frame_size)
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
# 動画ファイルの設定
fps = 20.0
frame_width = int(v.get(cv2.CAP_PROP_FRAME_WIDTH))
frame_height = int(v.get(cv2.CAP_PROP_FRAME_HEIGHT))
frame_size = (frame_width, frame_height)
output_filename = f"output_{time.strftime('%Y%m%d_%H%M%S')}.avi"
video_writer = create_video_writer(output_filename, fps, frame_size)
print(f"録画を開始します: {output_filename}")
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# オリジナルのフレームを動画ファイルに書き込む
video_writer.write(f)
# 表示用にフレームをリサイズ
display_frame = resize_frame(f, display_width)
cv2.imshow("カメラ映像", display_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
video_writer.release()
cv2.destroyAllWindows()
print(f"録画を終了しました: {output_filename}")

* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
止めると、動画ファイル C:/image/output.avi ができる。ディレクトリ C:/image は前もって作っておくこと
ヒストグラム平坦化 (histogram equalization)
ヒストグラム平坦化は、モノクロ画像の表示をあざやかにするなどで役に立つ方法
USB接続できるビデオカメラを準備し,パソコンに接続しておく.
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
def apply_clahe(frame):
# グレースケールに変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# CLAHEオブジェクトを作成
# clipLimit: コントラスト制限のしきい値。デフォルトは40.0
# tileGridSize: 局所領域のサイズ。デフォルトは(8, 8)
clahe = cv2.createCLAHE(clipLimit=2.0, tileGridSize=(8,8))
# CLAHEを適用
equalized = clahe.apply(gray)
return equalized
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# フレームをリサイズ
resized_frame = resize_frame(f, resize_width)
# ヒストグラム平坦化を適用
equalized_frame = apply_clahe(resized_frame)
# 元の画像とヒストグラム平坦化後の画像を横に並べて表示
combined_frame = np.hstack((cv2.cvtColor(resized_frame, cv2.COLOR_BGR2GRAY), equalized_frame))
cv2.imshow("Original vs Equalized", combined_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()

* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
2値化
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
def apply_adaptive_threshold(frame):
# グレースケールに変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 適応的閾値処理を適用
# パラメータの説明:
# cv2.ADAPTIVE_THRESH_GAUSSIAN_C: ガウス重み付け(周辺ピクセルの重要度が中心から離れるほど小さくなる)
# 11: 閾値を計算する際の近傍領域のサイズ(奇数である必要がある)
# 2: 計算された閾値から引く定数
binary = cv2.adaptiveThreshold(gray, 255, cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
cv2.THRESH_BINARY, 11, 2)
return binary
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# フレームをリサイズ
resized_frame = resize_frame(f, resize_width)
# 二値化を適用
binary_frame = apply_adaptive_threshold(resized_frame)
# 元の画像と二値化後の画像を横に並べて表示
combined_frame = np.hstack((cv2.cvtColor(resized_frame, cv2.COLOR_BGR2GRAY), binary_frame))
cv2.imshow("Original vs Binary", combined_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()

止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
輪郭抽出
import cv2
import numpy as np
# リサイズする幅を指定(例:640ピクセル)
resize_width = 640
def resize_frame(frame, width):
height = int(frame.shape[0] * (width / float(frame.shape[1])))
return cv2.resize(frame, (width, height), interpolation=cv2.INTER_AREA)
def extract_contours(frame):
# グレースケールに変換
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# Cannyエッジ検出を適用
# パラメータの説明:
# 100: 下側の閾値。この値以下の勾配はエッジとして検出されません。
# 200: 上側の閾値。この値以上の勾配は確実にエッジとして検出されます。
edges = cv2.Canny(gray, 100, 200)
# 輪郭を検出
# cv2.RETR_EXTERNAL: 最も外側の輪郭のみを検出
# cv2.CHAIN_APPROX_SIMPLE: 輪郭を表現する点を削減し、メモリを節約
contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
# 輪郭を描画
contour_image = np.zeros_like(frame)
cv2.drawContours(contour_image, contours, -1, (0, 255, 0), 2)
return contour_image
v = cv2.VideoCapture(0)
if not v.isOpened():
print("カメラを開けませんでした。")
exit()
while True:
r, f = v.read()
if not r:
print("フレームの読み取りに失敗しました。")
break
# フレームをリサイズ
resized_frame = resize_frame(f, resize_width)
# 輪郭抽出を適用
contour_frame = extract_contours(resized_frame)
# 元の画像と輪郭抽出後の画像を横に並べて表示
combined_frame = np.hstack((resized_frame, contour_frame))
cv2.imshow("Original vs Contours", combined_frame)
# 'q'キーで終了
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()

止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
動画ファイルを使って試す
前準備として,動画ファイルを準備する
ここで使用する動画ファイル:sample1.mp4
この動画ファイルのダウンロードは, Windows でコマンドプロンプトを管理者として開き 次のコマンドを実行する.
mkdir c:\image
cd c:\image
curl -O https://www.kkaneko.jp/sample/face/sample1.mp4
上のコマンドがうまく
* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
ここでの輪郭抽出は、2値化の結果を利用して輪郭を抽出している
* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
次のことを行う
* 止めたいとき,右上の「x」をクリックしない.画面の中をクリックしてから,「q」のキーを押して閉じる
1列目:フレーム番号、2列目:OTSU の方法による2値化の結果白色となった画素数、3列目:L成分の平均、4列目:a成分の平均、5列目:b成分の平均
OTSU の方法による2値化
import os
import numpy as np
import cv2
IMROOT=os.environ['LOCALAPPDATA'] + '/'
v = cv2.VideoCapture(IMROOT + 'sample1.mp4')
while(v.isOpened()):
r, f = v.read()
if ( r == False ):
break
mono = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
r, dst = cv2.threshold(mono, 0, 255, cv2.THRESH_OTSU)
cv2.imshow("f", f)
cv2.imshow("dst", dst)
# Press Q to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()
輪郭抽出
import os
import numpy as np
import cv2
IMROOT=os.environ['LOCALAPPDATA'] + '/'
v = cv2.VideoCapture(IMROOT + 'sample1.mp4')
while(v.isOpened()):
r, f = v.read()
if ( r == False ):
break
mono = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
r, dst = cv2.threshold(mono, 0, 255, cv2.THRESH_OTSU)
contours, hierarchy = cv2.findContours(dst, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(f, contours, -1, (0, 255, 0), 3)
cv2.imshow("f", f)
# Press Q to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
cv2.destroyAllWindows()
OTSU の方法による2値化のあと, 数え上げと画素値の平均
import os
import numpy as np
import cv2
IMROOT=os.environ['LOCALAPPDATA'] + '/'
v = cv2.VideoCapture(IMROOT + 'sample1.mp4')
i = 0
res = open(IMROOT + 'result.csv', mode='a')
while(v.isOpened()):
r, f = v.read()
if ( r == False ):
break
mono = cv2.cvtColor(f, cv2.COLOR_BGR2GRAY)
r, dst = cv2.threshold(mono, 0, 255, cv2.THRESH_OTSU)
lab = cv2.cvtColor(f, cv2.COLOR_BGR2LAB)
cv2.imshow("f", f)
cv2.imshow("dst", dst)
cv2.imshow("L", lab[:,:,0])
cv2.imshow("A", lab[:,:,1])
cv2.imshow("B", lab[:,:,2])
total = np.sum(dst)
print( "%d, %d, %f, %f, %f" % (i, total, np.sum(lab[:,:,0])/total, np.sum(lab[:,:,1])/total, np.sum(lab[:,:,2])/total ) )
res.write( "%d, %d, %f, %f, %f\n" % (i, total, np.sum(lab[:,:,0])/total, np.sum(lab[:,:,1])/total, np.sum(lab[:,:,2])/total ) )
i = i + 1
# Press Q to exit
if cv2.waitKey(1) & 0xFF == ord('q'):
break
v.release()
res.close()
cv2.destroyAllWindows()