ビデオは知識や情報を広めるための重要なメディアの 1 つとなっています。ただし、簡単に共有、アーカイブ、印刷できるようにビデオ講義をスライドや画像に変換するなど、ビデオ コンテンツを静的な形式で保存する必要がある場合があります。幸いなことに、強力なコンピューター ビジョン ライブラリである OpenCV は、ビデオ素材を PDF 画像に変換できるさまざまな技術とツールを提供します。
この記事では、OpenCV の基本的なフレーム差分モデルと、KNN (K 最近傍法) や GMG (ガウス混合ベースの背景/前景セグメンテーション) などの統計的背景減算モデルを使用して、ビデオ素材を対応するスライドに変換する方法を説明します。これらのモデルは、ビデオ内のキーフレームを抽出して PDF 画像として保存し、各キーフレームをスライドショーのページにすることができます。
このガイドを読むと、次のことがわかります。
ビデオをスライドショー画像に変換: OpenCV を使用したビデオ素材変換ガイド
背景減算とは
背景減算は、前景オブジェクトを抽出し、ビデオから背景を除去するために一般的に使用されるコンピューター ビジョン技術です。背景のモデルを構築し、ビデオ フレームをこのモデルと比較し、背景と異なるピクセルを検出することによって、前景領域を決定します。背景減算は、動き検出、物体追跡、ビデオ分析など、多くの分野で幅広い用途があります。
バックグラウンド減算の処理手順
- 背景モデルを構築する: まず、ビデオ内の静的な背景を表す背景モデルを構築する必要があります。これは、フレームの初期セットを使用するか、適応方法を使用することによって取得できます。
- フレーム差の計算: 背景モデルが確立された後、ビデオの各フレームについて、それを背景モデルと比較して、ピクセルレベルの差を計算します。一般的なフレーム差分計算方法には、絶対差分、差分二乗、差分閾値などがあります。
- 前景検出: フレーム差分計算の結果に応じて、前景検出を行うことができます。これには通常、適切なしきい値を設定して前景と背景の区別を決定するために差分画像を 2 値化することが含まれます。
- 前景の最適化: 前景の検出結果をさらに最適化するために、穴を埋めるかノイズを除去するための形態学的操作 (膨張、侵食) などのいくつかの画像処理技術を適用できます。
- ターゲットの抽出: 前景の検出に基づいて、輪郭検出や接続領域分析などの方法を使用して、前景にあるターゲット オブジェクトを抽出できます。
- 背景の更新: シーン内の動的な変化に適応するには、背景モデルを更新する必要があります。移動平均法や適応背景モデリングなどの技術を使用して、背景モデルを継続的に更新できます。
OpenCV を背景減算に使用する場合、KNN (K-最近傍法) や GMG (ガウス混合ベースの背景/前景セグメンテーション) などのアルゴリズムを使用して、背景モデリングと前景抽出のステップを実装できます。これらのアルゴリズムは、バックグラウンド減算のプロセスを容易かつ迅速に実装するために、対応する関数とメソッドを OpenCV ライブラリに提供します。
opencv は背景の減算にフレーム差分を使用します
背景減算は、ビデオ内の前景オブジェクトを検出するために使用できる一般的なコンピューター ビジョン技術です。OpenCVでは背景減算を実現するためのさまざまな方法が提供されていますが、その一つにフレーム差分(Frame Difference)を利用する方法があります。
フレーム差分法では、各フレーム画像と前のフレーム画像の差に基づいて前景を検出します。OpenCV を使用したフレーム差分の背景減算の一般的な手順は次のとおりです。
- ビデオの読み取り: OpenCV を使用してビデオ ファイルをロードし、ビデオの各フレームを取得します。
- グレースケール変換: 処理手順を簡素化するために、画像の各フレームをグレースケール画像に変換します。
- フレーム差分計算:現フレームと前フレームとの差分画像を減算演算により計算します。差分画像により、前景のオブジェクトが強調表示されます。
- 閾値処理: 差分画像の閾値処理では、差が大きいピクセルを前景 (白) としてマークし、差が小さいピクセルを背景 (黒) としてマークします。
- 前景の最適化: 膨張や侵食などの形態学的操作を適用して前景領域を埋めるかノイズを除去することにより、前景の検出結果を最適化します。
- 対象物抽出: 前景画像に基づいて、輪郭検出や連結領域解析などの手法を使用して、前景にある対象物を抽出できます。
上記の手順により、OpenCV のフレーム差分メソッドを使用して背景の減算を実装し、ビデオから前景オブジェクトを抽出できます。
opencv バックグラウンド減算技術
OpenCV は、KNN、ガウス混合 (MOG v2)、GMG などのさまざまなバックグラウンド減算技術を提供します。これらのアルゴリズムには、背景モデルの構築と前景の抽出に関して異なる原理と計算式があります。
KNN ベースのバックグラウンド減算
KNN 背景減算アルゴリズムは最近傍分類の原理に基づいており、ピクセルが背景に属するか前景に属するかを決定するために使用されます。各ピクセルについて、最も近いピクセルとの差を計算し、差の値に基づいて分類します。OpenCV で KNN バックグラウンド減算モデルのオブジェクトを作成するための関数プロトタイプは次のとおりです。
cv2.createBackgroundSubtractorKNN([, history[, dist2Threshold[, detectShadows]]])
元の画像を I、各ピクセルの位置を (x, y) とすると、KNN 背景減算の原理は次の式で表すことができます。
- ピクセルとその最近傍ピクセルの差を計算します。
△ I ( x , y ) = ∑ i = 1 N ∣ I ( x , y ) − I i ( xi , yi ) ∣ \triangle I(x,y) = \sum_{i=1}^N|I( x,y)-I_i(x_i,y_i)|△私(× 、y )=i = 1∑N∣ I ( x ,y )−私私は( ×私は、y私は) ∣
- ピクセルが背景に属するか前景に属するかを決定します。
M ( x , y ) = { 1 , △ I ( x , y ) < = T 0 , それ以外の場合 } M(x,y)=\lbrace1,if \triangle I(x,y)<=T \space 0 、それ以外の場合は \r中括弧M ( x ,y )={ 1 、i f △ I ( x ,y )<=T0 、_ それ以外の方が賢明です}
このうち、M(x,y)は画素(x,y)の分類結果を表し、Tは閾値である。
ガウスの混合 (MOG v2)
Mixture of Gaussian (MOG v2) は、ガウス混合モデルに基づくバックグラウンド減算法です。各ピクセルについて、複数のガウス分布を使用してその背景値をモデル化し、加重合計を使用してピクセルが背景に属するか前景に属するかを決定します。その機能的なプロトタイプは次のとおりです。
cv2.createBackgroundSubtractorMOG2([, history[, varThreshold[, detectShadows]]])
元の画像を I、各ピクセルの位置を (x, y) とすると、混合ガウス (MOG v2) の原理は次の式で表すことができます。
- 背景モデルを構築します。
B ( x , y ) = ∑ i = 1 K wi ( x , y ) ⋅ N ( I ( x , y ) ; μ i ( x , y ) , σ i ( x , y ) ) B(x,y) =\sum_{i=1}^Kw_i(x,y) \cdot N(I(x,y);μ_i(x,y),\sigma_i(x,y))B ( x ,y )=i = 1∑Kw私は( x ,y )⋅N ( I ( x ,y ) ;メートル私は( x ,y ) 、p私は( x ,y ))
其中, B ( x , y ) B(x, y) B ( x ,y )はピクセル( x , y ) (x, y)( x ,y )、K はガウス分布の数、wi ( x , y ) w_i(x, y)w私は( x ,y )、μ i ( x , y ) μ_i(x, y)メートル私は( x ,y )和σ i ( x , y ) σ_i(x, y)p私は( x ,y ) は、それぞれ i 番目のガウス分布の重み、平均、分散を表します。
- ピクセルが背景に属するか前景に属するかを決定します。
M ( x , y ) = { 1 、1 の場合 K ∑ i = 1 K wi ( x , y ) ⋅ N ( I ( x , y ) ; μ i ( x , y ) , , σ i ( x , y ) ) < = T 0、それ以外の場合 } M(x,y)=\lbrace1,if \frac{1}{K}\sum_{i=1}^Kw_i(x,y)\cdot N(I(x,y );μ_i(x,y),,\sigma_i(x,y))<= T\space 0、それ以外の場合は \rbraceM ( x ,y )={
1 、私はK1i = 1∑Kw私は( x ,y )⋅N ( I ( x ,y ) ;メートル私は( x ,y ) 、、p私は( x ,y ))<=T0 、_ このうち、M(x,y)は画素( x , y)の分類結果を表し、 Tは
閾値である。
GMG バックグラウンド減算
GMG (ガウス混合ベースの背景/前景セグメンテーション) は、ガウス混合モデルに基づく背景減算アルゴリズムであり、ピクセルが背景に属するか前景に属するかを決定するために使用されます。GMG は、一連のピクセル値をモデル化し、ベイジアン推論を使用してピクセルの背景または前景の確率を計算することによって機能します。その機能的なプロトタイプは次のとおりです。
cv2.bgsegm.createBackgroundSubtractorGMG([, initializationFrames[, decisionThreshold]])
元の画像を I、各ピクセルの位置を (x, y) とすると、GMG 背景減算の原理は次の式で表すことができます。
- 方程式を使用してみましょう:
P ( x , y ) ( I t ) = ∑ c = 1 C wc ( x , y ) ⋅ N ( I t ; μ c ( x , y ) , σ c ( x , y ) . ) P(x,y)(I_t)=\sum_{c=1}^Cw_c(x,y)\cdot N(I_t;μ_c(x,y),\sigma_c(x,y))P ( x ,y ) (私た)=c = 1∑Cwc( x ,y )⋅N (私た;メートルc( x ,y ) 、pc( x ,y ))
ただし、P ( x , y ) ( I t ) P(x, y)(I_t)P ( x ,y ) (私た)はピクセル( x , y ) (x, y)( x ,y )時刻 t におけるI t I_t私たモデル、C はガウス分布の数、wc ( x , y w_c(x, ywc( x ,y )、μ c ( x , y ) μ_c(x, y)メートルc( x ,y )和σ c ( x , y ) σ_c(x, y)pc( x ,y ) は、それぞれ c 番目のガウス分布の重み、平均、分散を表します。
- ピクセルが前景に属する確率を計算します。
P ( x , y ) (前景) = 1 − P ( x , y ) ( I t ) (背景 ) P ( x , y ) ( I t ) (背景 ) + P ( x , y ) ( I t ) (前景 ) P(x,y)(前景)=1-\frac{P(x,y)(I_t)(背景)}{P(x,y)(I_t)(背景)+P(x,y) (I_t)(前景)}P ( x ,y ) (前景) _ _ _ _ _ _=1−P ( x ,y ) (私た) (バックグラウンド) _ _ _ _ _ _+P ( x ,y ) (私た) (前景) _ _ _ _ _ _P ( x ,y ) (私た) (バックグラウンド) _ _ _ _ _ _
ただし、P ( x , y ) ( 前景 ) P(x, y)(前景)P ( x ,y ) ( fore ground )はピクセル( x , y ) (x, y )を意味します( x ,y )は前景の確率P ( x , y ) ( 背景 ) P(x, y)(背景)P ( x ,y ) ( back ground )はピクセル( x , y ) (x, y )を意味します( x ,y )背景に属する確率。
- ピクセルが背景に属するか前景に属するかを決定します。
M ( x , y ) = { 1 、 P ( x , y ) ( フォアグラウンド ) > = T 0 、それ以外の場合 } M(x,y)=\lbrace1,if P(x,y)(フォアグラウンド) >=T \スペース 0、それ以外の場合は \r中括弧M ( x ,y )={
1 、if P ( x , _y ) (前景) _ _ _ _ _ _>=T0 、_ このうち、M(x,y)は画素( x , y)の分類結果を表し、 Tは
閾値である。
ビデオからスライドショーへのアプリのワークフロー
フローの説明:
- 始める
- ビデオ フレームの読み取り: OpenCV を使用してビデオ ファイルを読み取り、ビデオの各フレームを取得します。
- フレーム差分法を適用する: 画像の各フレームに対して、フレーム差分法を使用して背景の減算を実行し、前景マスクを計算し、前景のパーセンテージを計算します。
- 前景のパーセンテージがしきい値を超えているかどうかを判断します。
- 「はい」の場合、フレームを保存します (大きな動きのある静的なフレームを表します)。
- そうでない場合は、次のステップに進みます。
- 確率的背景減算を適用する: 画像の各フレームに対して、確率的背景減算手法を使用して背景減算を実行し、前景マスクを計算し、前景パーセンテージを計算します。
- 前景のパーセンテージがしきい値を超えているかどうかを判断します。
- 「はい」の場合は、動きが安定するまで待ち、ステップ 5 に戻ります。
- そうでない場合は、フレームを保存します (モーションが安定化されたフレームを表します)。
- スライドショーの生成: タイトルやテキストなどの追加を含め、保存されたフレームをスライドショーに変換します。
- PDF 画像として保存: 生成されたスライドショーを PDF 形式の画像として保存します。
- 終了
実装コード
import cv2
import numpy as np
from PIL import Image
from fpdf import FPDF
# 计算图像的感知哈希值
def calculate_hash(image):
# 转换为灰度图像并调整大小为8x8像素
if len(image) ==3:
image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
image = cv2.resize(image, (8, 8))
# 计算均值并二值化图像
mean = np.mean(image)
_, image = cv2.threshold(image, mean, 255, cv2.THRESH_BINARY)
# 将图像转换为一维数组
image = image.flatten()
return image
# 计算汉明距离
def calculate_hamming_distance(hash1, hash2):
return np.count_nonzero(hash1 != hash2)
# 判断两个图像是否相似
def is_duplicate(frame1, frame2, threshold):
hash1 = calculate_hash(frame1)
hash2 = calculate_hash(frame2)
distance = calculate_hamming_distance(hash1, hash2)
print(distance)
# 如果汉明距离小于阈值,则判定为重复帧
if distance < threshold:
return True
else:
return False
# 背景减法帧差
def frame_difference(frame, prev_frame):
# 将帧转换为灰度图像
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
if len(prev_frame.shape) == 2:
prev_gray = prev_frame
pass
else:
prev_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
# 计算帧之间的绝对差异
diff = cv2.absdiff(gray, prev_gray)
# 进行形态学操作,去除噪声
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5, 5))
diff = cv2.morphologyEx(diff, cv2.MORPH_OPEN, kernel)
# 计算前景掩码
_, thresh = cv2.threshold(diff, 30, 255, cv2.THRESH_BINARY)
return thresh
# 使用OpenCV对背景像素进行统计建模
def background_subtraction(frame, bg_model):
# 使用背景减法模型传递帧
fg_mask = bg_model.apply(frame, learningRate=-1)
# 计算前景百分比
height, width = fg_mask.shape[:2]
foreground_pixels = cv2.countNonZero(fg_mask)
foreground_percent = (foreground_pixels / (width * height)) * 100
return fg_mask, foreground_percent
# 视频到幻灯片转换处理(包括重复帧检测与删除)
def video_to_slides(video_path, output_path, frame_difference_threshold, bg_subtraction_threshold, duplicate_threshold):
# 打开视频
video = cv2.VideoCapture(video_path)
# 读取第一帧
_, prev_frame = video.read()
prev_frame_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
# 创建概率背景减法模型
bg_model = cv2.createBackgroundSubtractorMOG2()
# 幻灯片计数器
slide_counter = 0
# 保存非重复帧的列表
unique_frames = [prev_frame_gray]
while True:
# 读取当前帧
ret, frame = video.read()
if not ret:
break
# 背景减法帧差
diff_frame = frame_difference(frame, prev_frame)
# 判断是否保存帧
if cv2.countNonZero(diff_frame) > frame_difference_threshold:
cv2.imwrite(f"slide_{
slide_counter}.jpg", frame)
slide_counter += 1
# 使用概率背景减法
fg_mask, foreground_percent = background_subtraction(frame, bg_model)
# 判断是否保存帧
if foreground_percent > bg_subtraction_threshold:
cv2.imwrite(f"slide_{
slide_counter}.jpg", frame)
slide_counter += 1
# 更新前一帧
prev_frame = frame.copy()
prev_frame_gray = cv2.cvtColor(prev_frame, cv2.COLOR_BGR2GRAY)
# 判断是否为重复帧并进行删除
is_duplicate_frame = False
for unique_frame in unique_frames:
if is_duplicate(prev_frame_gray, unique_frame, duplicate_threshold):
is_duplicate_frame = True
break
if not is_duplicate_frame:
unique_frames.append(prev_frame_gray)
# 生成幻灯片和保存为PDF图片(请使用适当的库实现)
# 生成幻灯片和保存为PDF图片
pdf = FPDF()
# 设置页面尺寸为A4
pdf.set_auto_page_break(auto=True, margin=15)
for i in range(slide_counter):
pdf.add_page()
pdf.image(f"slide_{
i}.jpg", x=15, y=15, w=pdf.w,h=pdf.h - 100)
# 保存PDF文件
pdf.output(output_path)
# 关闭视频
video.release()
# 调用函数进行视频到幻灯片转换处理
video_to_slides("input_video.mp4", "output_slides.pdf", 5000, 5000, 7)