今日は旧正月の 29 日で、明日は春節の対句を投稿します。数年前に急いで記事を書いたものとも言えますし(あまりにも長い間何も投稿していませんでしたo.o)、オプティカル フロー推定の深層学習部分に関する私自身の研究の始まりとも言えます。 、インターンシップ、仕事と目の前には山のように積まれていますが、来年はうまくいきますように!
1. オプティカルフローの基本概念
1. オプティカルフローとオプティカルフロー分野
(1) オプティカルフロー
オプティカルフローとは、観察結像面上で空間的に移動する物体の画素移動の瞬間速度のことで、二次元平面画像における特定の画素の階調・輝度の瞬間的な変化率をオプティカルフローと定義する人もいます(
Optical flow can also be defined as the distribution of apparent velocities of movement of brightness pattern in an image.
) 、時間間隔が非常に長い場合(ビデオの連続する 2 つのフレームの間など)、画像平面内の空間点の投影点の変位にも相当します。一般に、オプティカル フローは、シーン内の前景オブジェクト自体の動き、カメラの動き、または両者の関節の動きによって生じ、相対的な動きをもたらします。
平たく言えば、人間の目が動く物体を観察するとき、その物体の光景は人間の目の網膜上に一連の連続的に変化する画像を形成し、この一連の連続的に変化する情報は網膜を通って継続的に「流れ」ます(つまり、 、画像面 ) は、光の「流れ」のように、画像の明るさ/グレースケール パターンの一連の動きを形成するため、オプティカル フローと呼ばれます。画像内のピクセル強度の流れとしても理解できます。オプティカルフローは画像の変化を表現しており、対象物の動きの情報が含まれているため、観察者は対象物の動きを把握することができます。
画像X (t-1 フレーム) と画像 Y (t フレーム) は通常、ビデオ ストリーム内の 2 つの隣接するフレームであり、画像 X 内の特定のピクセル A の位置は ( x 1 , y 1 ) (x_1, y_1 ) です。( ×1、y1)、動き後の画像 Y 内の位置は( x 2 , y 2 ) (x_2,y_2)( ×2、y2)の場合、このピクセル点 A のオプティカル フローは、 ( ux , uy ) = ( x 2 , y 2 ) − ( x 1 , y 1 ) (u_x,u_y) = (x_2,y_2) - (x_1) として計算できます。、y_1)(あなた×、あなたはい)=( ×2、y2)−( ×1、y1)、ベクトル( ux , uy ) (u_x,u_y)(あなた×、あなたはい)は、ピクセルによって生成されるオプティカル フローであり、x 方向と y 方向の動きを含み、オプティカル フローの値はサブピクセル浮動小数点値です。下の図 1 に示すように、左の図の点 A が右の図に移動し、矢印は 2 つの隣接するフレーム間の点 A のオプティカル フロー ベクトルを示します。
(2) オプティカルフローフィールド
一連のピクセル オプティカル フロー ベクトルの集合により、オプティカル フロー フィールドが形成されます。オプティカル フロー フィールドとは、画像内の一連のピクセルで構成される 2 次元 (2D) 瞬間速度フィールドを指し、2 次元速度ベクトルは、ターゲット オブジェクト内の可視点の 3 次元速度ベクトルの投影です。一般に、3次元モーションフィールドとは、2次元画像上に投影により形成されるオプティカルフローフィールドに相当する。
2. オプティカルフロー手法とスポーツ分野
(1) スポーツ分野
スポーツ フィールドは、実際には 3 次元の現実世界におけるオブジェクトの動きであり、一連の動きベクトルがスポーツ フィールドを構成し、オブジェクトの実際の動きの状態を記述するために使用できます。空間内のモーション フィールドを 2 次元の画像平面 (人間の目またはカメラ) に投影してオプティカル フロー フィールドを表現すると、モーション フィールドとオプティカル フロー フィールドの関係は下図のようになります。
上記から、オプティカル フロー ベクトルとモーション ベクトルの関係は非常に近いことがわかりますが、この 2 つは完全に一致しているわけではありません。また、スポーツ フィールドとそのオプティカル フロー フィールドの間には必ずしも完全な対応関係があるわけではありません。なぜなら、オプティカルフローの生成は物体とカメラとの相対的な動きによるものであり、この相対的な動きは実際の動きの状態と完全に一致するわけではないからです。生活の中でよくある例として、理髪店では集客のために回転看板をよく使います (下図参照) このとき、オプティカルフローフィールドの視点から見ると看板は上向きに回転していますが、視点から見ると上向きに回転しています。スポーツフィールド 見るからに、看板は実際に水平に動きます。したがって,オプティカル フロー フィールドは厳密にはスポーツ フィールドと等しくありませんが, このような状況はまれです.ほとんどの場合, 2 つのパフォーマンスは一貫しています. 次に, オプティカル フロー フィールドが スポーツ フィールド に対応すると仮定します, これはまた、それを動きベクトルに関連する問題に適用すると、可能性が得られます。
(2)オプティカルフロー方式
なぜなら、3次元空間でモーションフィールドを直接計算して解析することは非常に困難であり、モーションフィールドは投影によって2次元画像上に形成されるオプティカルフローフィールドに対応し、オプティカルフローは本質的に、 3 次元シーン内のオブジェクトの動きを 2 次元画像平面に表現します。表現されるピクセルの明るさの変化には、観察されたオブジェクトの動きの情報だけでなく、シーンの 3 次元構造に関する豊富な情報も含まれています。そのため、オプティカルフロー解析によって移動物体を解析することが可能となり、時代の要請に応じてオプティカルフロー手法が登場し、コンピュータビジョンにおける移動物体を解析するための重要なツールとなっています。
オプティカルフロー法は、時間領域の画像シーケンス内のピクセルの変化と隣接するフレーム間の相関を使用して、前のフレームと現在のフレーム間の対応関係を見つけ、隣接するフレーム間のオブジェクトの距離を計算します。運動情報の手法、すなわち、二次元画像データから物体の実際の運動状態(オプティカルフローフィールド→運動フィールド)を推定する手法。オプティカル フロー フィールドを研究する目的は、シーケンス画像から直接取得できない動きフィールドを近似し、画像内のピクセルのグレー値の強度変化に従って物体の動きの速度と方向を推定することです。一般的な理想的なケースでは、オプティカル フロー フィールドはモーション フィールドに対応する必要があります。
3. 疎なオプティカル フローと密なオプティカル フロー
オプティカルフロー計算の理想的な出力は、2 つの画像内の各ピクセルの速度の推定相関、または同等の、一方の画像内の各ピクセルの変位ベクトルであり、もう一方の画像内のそのピクセルの相対位置を示します。この方法は画像内の各ピクセルに使用され、通常は「密なオプティカル フロー」と呼ばれます。画像内の特定の点のサブセットのみが追跡される場合は、「疎なオプティカル フロー」と呼ばれます。
(1) 緻密なオプティカルフロー
高密度オプティカル フローは、画像または指定された領域に対して点ごとのマッチング計算を実行するオプティカル フロー計算手法であり、画像上のすべての点のオフセットを計算して、高密度のオプティカル フロー フィールドを形成します。この高密度のオプティカル フロー フィールドを通じて、ピクセル レベルの画像位置合わせを実行できます。オプティカル フロー ベクトルは密であるため、その登録の効果は、疎なオプティカル フローの登録の効果よりも明らかに優れています。しかし、その副作用も比較的顕著であり、各ピクセルのオフセットを計算する必要があるため、計算量も当然多く、適時性も悪い。
(2) スパースオプティカルフロー
スパースオプティカル フローは、画像の各ピクセルに対してポイントごとの計算を実行しません。通常、追跡する点のセットを指定する必要があります。この点のセットには、ハリス コーナー ポイントなどの明らかな特性があることが望ましいです。 .、そのため、追跡は比較的安定しており、信頼性が高くなります。疎な追跡は、密な追跡よりも計算コストがはるかに低くなります。
4. オプティカルフロー推定
オプティカルフロー推定は、2 つの画像フレーム間のオプティカル フロー フィールドを確立/計算する方法です。一般的なオプティカル フロー推定方法には、勾配ベースの方法、マッチング ベースの方法、ディープ ラーニング ベースの方法、エネルギー ベースの方法などが含まれます。以下の研究では、ディープ ラーニング ベースの研究方法に焦点を当てます。上記の導入から、オプティカル フロー推定の中心的な問題は、対応するオプティカル フロー ベクトルを計算するために、2 つの画像の対応するピクセルをどのように照合するかであることがわかります。
2. オプティカルフローの表現と可視化
1. オプティカルフローの表現方法
オプティカルフロー推定の結果は、元の画像と同じサイズの双通道
行列であり、通常は3 次元浮動小数点配列 [高さ, 幅, 2] で表されます。このうち、最初のチャネル (高さ、幅、0) は (高さ、幅) のピクセルの x 方向 (水平方向または画像行ベクトル方向) のオフセット ベクトルを表し、2 番目のチャネル (高さ、幅、1) は、ピクセルの y 方向 (垂直方向または画像の列ベクトル方向) のオフセット ベクトル (高さ、幅) を表します。次の点に注意してください。
- オプティカルフロー配列内の数値はオフセットを示し、正負の値はオフセット方向を示します
- オプティカル フロー配列の最終的な適用オブジェクトは、(x, y) のピクセル値ではなく、2 次元画像フレームのピクセル座標(x, y)です。
- オプティカル フロー配列の値は整数ではなく浮動小数点数です。これは、オプティカル フロー ワープ操作の後、t-1 フレーム画像のピクセル座標が t フレーム画像の整数座標に正確に一致しない可能性があり、他の処理が必要になる可能性があることを意味します。
2. オプティカルフローの可視化
オプティカルフローの計算結果は2チャンネルの3次元浮動小数点数配列ですが、多くの場合、物体の運動状態を直感的に反映させるためにオプティカルフロー結果を可視化する必要があります。オプティカル フロー フィールドはベクトル フィールドであるため、可視化する際に各ベクトルの大きさと方向を同時に示す必要があるため、一般的なオプティカル フローの可視化方法には次の 2 つがあります。
(1) オプティカルフローアロー図
最も単純な視覚化方法は、矢印を使用してオプティカル フローを表すことです。下の図に示すように、矢印の方向と長さは各オプティカル フロー ベクトルの方向とサイズを表します。矢印を使用してオプティカル フローを表す利点は、シンプルで直感的であることですが、いくつかの欠点もあります。まず、このように各ピクセルのオプティカルフローを矢印で一つ一つ表現しているのですが、画像の解像度が高くなってオプティカルフローのピクセルが非常に密になってしまうと、限られた範囲内ではオプティカルフローを完全に表現することができなくなります。領域; 次に、矢印の密度が増加すると、画像が非常に乱雑になります。したがって、オプティカル フロー アロー ダイアグラムは一般に、まばらなオプティカル フローの視覚化に適しています。
(2) オプティカルフロー色度図
高密度オプティカルフローの場合カラーモデルによるオプティカルフロー計算結果でオプティカルフローを色付けし、擬似カラーマップ(RGBカラーマップ)として可視化することができます。このうち、色相 (または色相、つまりさまざまな色) は動きの方向を示し、彩度 (または色相の強さ、つまり色の深さ) は動きの速さまたはオフセットの大きさを示します。最も中央の位置は動きがないことを表し、オフセットが発生します。上は色が白です。オプティカルフローの計算結果を色度図に変換する方法は主に2つありますが、色度図全体の可視化の参考となるカラーホイールは以下のとおりです。
(1) HSVカラーモデル変換
HSVは RGB 色空間を円錐として表す方法で、H は色相 (色相、色の種類)、S は彩度 (色相の強度、色の深さ)、V は値 (明るさ) を表します。HSV モデルの 3 つの主要コンポーネントは次のように紹介されます。
- H(色相、色相):このパラメータは角度で表され、値の範囲は0°~360°です。赤から始めて反時計回りに数えると、赤が 0°、緑が 120°、青が 240°になります。それらの補色は次のとおりです。黄色は 60°、シアンは 180°、紫は 300°です。
- S (彩度、色相の強さ): 放射状のスケール、値の範囲は 0.0 ~ 1.0 です。彩度はその色が分光色にどの程度近いかを示し、どの色も特定の分光色と白を混ぜた結果とみなすことができます。このうち、分光色の割合が大きいほど、分光色に近い色の度合いが高くなり、色の彩度が高くなり、色が濃くなります。
- V (明度、明るさ): 垂直方向、値の範囲は 0.0 (黒、下) ~ 1.0 (白、上) で、色の明るさを示します。
このカラー モデルをオプティカル フローの視覚的変換に使用する 具体的な手順は次のとおりです。
- まず、オプティカル フローのサイズを正規化してから、オプティカル フローの方向を色相成分 H にマッピングする必要があります。オプティカル フロー フィールドは 2 チャネルの 3 次元配列であるため、各位置のベクトルはデカルト座標系の座標 (x, y) として表現できます。次に、デカルト座標系 x および y を極座標にさらに変換できます。極角 actan2(y,x) は方向を表します (HSV モデルの色相にマッピングされます)。
- そして、オプティカルフローの大きさを彩度成分Sにマッピングし、オプティカルフローが大きいほど彩度が大きくなり、オプティカルフローが0の箇所は白く表示される。極座標系では、極半径 (x と y の平方根) がオフセットのサイズを表します。
- 最終的に、輝度成分 V を単一の値に統一できます。たとえば、画像を観察しやすくするために、最も明るい 255 に固定することができます。最後に、HSV モデル表現を RGB 形式の疑似カラー マップに変換して表示します。
参考記事とサンプルコードは以下の通りです。
def viz_flow(flow):
# 色调H:用角度度量,取值范围为0°~360°,从红色开始按逆时针方向计算,红色为0°,绿色为120°,蓝色为240°
# 饱和度S:取值范围为0.0~1.0
# 亮度V:取值范围为0.0(黑色)~1.0(白色)
h, w = flow.shape[:2]
hsv = np.zeros((h, w, 3), np.uint8)
# cv2.cartToPolar(x, y[, magnitude[, angle[, angleInDegrees]]]) → magnitude, angle
# - params x,y:直角坐标系的横坐标、纵坐标,ndarray 多维数组,浮点型。默认为弧度制
# - return magnitude, angle:极坐标系下的极径值、极角值,ndarray 多维数组,与输入的 x, y 具有相同的尺寸和数据类型
mag, ang = cv2.cartToPolar(flow[...,0], flow[...,1])
hsv[...,0] = ang*180/np.pi/2 # 弧度转化为角度
hsv[...,1] = cv2.normalize(mag,None,0,255,cv2.NORM_MINMAX) #标准化
# flownet是将V赋值为255, 此函数遵循flownet,饱和度S代表像素位移的大小,亮度都为最大,便于观看
# 也有的光流可视化讲s赋值为255,亮度代表像素位移的大小,整个图片会很暗,很少这样用
hsv[...,2] = 255
# cv2.cvtColor(frame,COLOR_STYLE) 改变图像的颜色空间,opencv中默认的颜色空间是BGR
# backward conversions HSV to RGB/BGR with H range 0..180 if 8 bit image
bgr = cv2.cvtColor(hsv,cv2.COLOR_HSV2BGR)
return bgr
(2) マンセル表色系変換
この方法では、マンセル カラー システム (MunsellColor System、Wiki ) を使用して、オプティカル フローの結果を変換します。マンセルカラーシステムは、1898年にアメリカの芸術家アルバート・H・マンセル(Albert H. Munsell, 1858-1918)によって作成された色記述システムです。円柱を使って色空間を大まかに分割しており、具体的な知識を自分で理解することができます。この手法は、オプティカル フローの計算結果を視覚化するために多くの論文 (FlowNet、PWC-Net など) で使用されており、多くの検証を受けています。
参考記事とサンプルコードは以下の通りです。
- 直接使用できる可視化ツール: https://github.com/tomrunia/OpticalFlow_Visualization
- 参考论文:《A Database and Evaluation Methodology for Optical Flow》
import numpy as np
def make_colorwheel():
"""
Generates a color wheel for optical flow visualization as presented in:
Baker et al. "A Database and Evaluation Methodology for Optical Flow" (ICCV, 2007)
URL: http://vision.middlebury.edu/flow/flowEval-iccv07.pdf
Code follows the original C++ source code of Daniel Scharstein.
Code follows the the Matlab source code of Deqing Sun.
Returns:
np.ndarray: Color wheel
"""
RY = 15
YG = 6
GC = 4
CB = 11
BM = 13
MR = 6
ncols = RY + YG + GC + CB + BM + MR
colorwheel = np.zeros((ncols, 3))
col = 0
# RY
colorwheel[0:RY, 0] = 255
colorwheel[0:RY, 1] = np.floor(255*np.arange(0,RY)/RY)
col = col+RY
# YG
colorwheel[col:col+YG, 0] = 255 - np.floor(255*np.arange(0,YG)/YG)
colorwheel[col:col+YG, 1] = 255
col = col+YG
# GC
colorwheel[col:col+GC, 1] = 255
colorwheel[col:col+GC, 2] = np.floor(255*np.arange(0,GC)/GC)
col = col+GC
# CB
colorwheel[col:col+CB, 1] = 255 - np.floor(255*np.arange(CB)/CB)
colorwheel[col:col+CB, 2] = 255
col = col+CB
# BM
colorwheel[col:col+BM, 2] = 255
colorwheel[col:col+BM, 0] = np.floor(255*np.arange(0,BM)/BM)
col = col+BM
# MR
colorwheel[col:col+MR, 2] = 255 - np.floor(255*np.arange(MR)/MR)
colorwheel[col:col+MR, 0] = 255
return colorwheel
def flow_uv_to_colors(u, v, convert_to_bgr=False):
"""
Applies the flow color wheel to (possibly clipped) flow components u and v.
According to the C++ source code of Daniel Scharstein
According to the Matlab source code of Deqing Sun
Args:
u (np.ndarray): Input horizontal flow of shape [H,W]
v (np.ndarray): Input vertical flow of shape [H,W]
convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False.
Returns:
np.ndarray: Flow visualization image of shape [H,W,3]
"""
flow_image = np.zeros((u.shape[0], u.shape[1], 3), np.uint8)
colorwheel = make_colorwheel() # shape [55x3]
ncols = colorwheel.shape[0]
rad = np.sqrt(np.square(u) + np.square(v))
a = np.arctan2(-v, -u)/np.pi
fk = (a+1) / 2*(ncols-1)
k0 = np.floor(fk).astype(np.int32)
k1 = k0 + 1
k1[k1 == ncols] = 0
f = fk - k0
for i in range(colorwheel.shape[1]):
tmp = colorwheel[:,i]
col0 = tmp[k0] / 255.0
col1 = tmp[k1] / 255.0
col = (1-f)*col0 + f*col1
idx = (rad <= 1)
col[idx] = 1 - rad[idx] * (1-col[idx])
col[~idx] = col[~idx] * 0.75 # out of range
# Note the 2-i => BGR instead of RGB
ch_idx = 2-i if convert_to_bgr else i
flow_image[:,:,ch_idx] = np.floor(255 * col)
return flow_image
def flow_to_color(flow_uv, clip_flow=None, convert_to_bgr=False):
"""
Expects a two dimensional flow image of shape.
Args:
flow_uv (np.ndarray): Flow UV image of shape [H,W,2]
clip_flow (float, optional): Clip maximum of flow values. Defaults to None.
convert_to_bgr (bool, optional): Convert output image to BGR. Defaults to False.
Returns:
np.ndarray: Flow visualization image of shape [H,W,3]
"""
assert flow_uv.ndim == 3, 'input flow must have three dimensions'
assert flow_uv.shape[2] == 2, 'input flow must have shape [H,W,2]'
if clip_flow is not None:
flow_uv = np.clip(flow_uv, 0, clip_flow)
u = flow_uv[:,:,0]
v = flow_uv[:,:,1]
rad = np.sqrt(np.square(u) + np.square(v))
rad_max = np.max(rad)
epsilon = 1e-5
u = u / (rad_max + epsilon)
v = v / (rad_max + epsilon)
return flow_uv_to_colors(u, v, convert_to_bgr)
3.オプティカルフローワープ
ワープは、歪み、変形、マッピングと翻訳できます。オプティカル フロー ワープ操作の意味は、計算されたオプティカル フローをターゲット イメージ フレームに適用して、オプティカル フローがオフセットまたはモーション変換に影響を与えた後に結果のイメージ フレームを取得することです。 。たとえば、画像フレーム t->t+1 のオプティカル フローがある場合、それを画像フレーム t に適用すると、理想的な結果は画像フレーム t+1 になるはずで、変換プロセス全体は一種の変換プロセスになります。オプティカル フロー ワープ操作。オプティカル フロー ワープには主に、次に紹介する前方ワープと後方ワープがあります。
1.順ワープ
隣接する画像が 2 フレーム (または左右) ある場合I 1 、I 2 I_1、I_2私1、私2,对应I 1 → I 2 I_1 \rightarrow I_2私1→私2オプティカル フロー Flow はF 1 → 2 F_{1\rightarrow2}F1 → 2(オプティカル フローは 2 つの画像上の対応する点のオフセット関係です)、順ワープ操作の下で、最初のフレーム画像のピクセル値 I 1 ( x , y ) I_1(x,y)私1( x ,y )は、画像I 2 ( ( x , y ) + F 1 → 2 ) I_2((x,y)+F_{1\rightarrow2}) の 2 番目のフレームに表示されます。私2(( x ,y )+F1 → 2)座標位置上、つまりI 1 ( x , y ) = I 2 ( x + Δ x , y + Δ y ) I_1(x,y) = I_2(x+\Delta x,y+\Delta y)私1( x ,y )=私2( ×+Δx 、_y+Δ y )、その中F 1 → 2 ( x , y ) = ( Δ x , Δ y ) F_{1\rightarrow2}(x,y) = (\Delta x,\Delta y)F1 → 2( x ,y )=( Δ x ,y ) _ _
前方ワープは、単純に「前方への変形/歪み」として理解できます。つまり、画像の変形の方向はオプティカル フローの流れの方向と同じであり、これは人間の固有の認知的思考と一致します。たとえば、I 1 → I 2 I_1\rightarrow I_2を使用します。私1→私2オプティカル フローはI 1 I_1になります。私1I 2 I_2に変換私2観点から見ると、これは前方ワープです。
順方向ワープの考え方は、オプティカル フローFS ソース → 宛先 F_{ソース\rightarrow 宛先}source image
を通じて各ポイントを横断することです。p_source
F送信元→宛先_ _ _ _ _ _ _ _中点の座標オフセットは、p_source
そのピクセル値を に投影することによってdestination image
取得されますp_destination
。p_destination
座標が整数でない場合は、通常、切り上げられるか、最近傍が選択されます。その簡単な実装コードは次のとおりです。
im1 = torch.zeros_like(im0)
B = im0.shape[0]
H = im0.shape[2]
W = im0.shape[3]
round_flow = torch.round(flow)
for b in range(B):
# 遍历source image中的每个点p_source
for h in range(H):
for w in range(W):
# 获取投影到destination image中的对应坐标点p_destination,采用四舍五入取整
x = w + int(round_flow[b, h, w, 0])
y = h + int(round_flow[b, h, w, 1])
# 判断映射位置是否在有效范围内,若在则赋值,否则保留zero
if x >= 0 and x < W and y >= 0 and y < H:
im1[b, :, y, x] = im0[b, :, h, w]
return im1
フォワードワープの実装とアイデアは非常にシンプルですが、多くの問題も引き起こします。
-
ホール問題:順ワープのマッピング関係は単射的でも全射的でもなく、離散化されたランダムなマッピングです。これにより、
destination image
一部の位置ではそこから投影される点が存在しないかsource image
、一部の位置では複数の点source image
が同時に投影されるため、多くの穴と波紋のような効果が生じます。その解決策は次のように考えられます。- マルチポイント マッピング:複数のポイントが同時に 1 つのポイントにマップされる状況では、「移動範囲」が最も大きいポイントを選択できます。これは、「移動範囲」が通常は前景であり、前景の方がより多く移動するためです。そして前景は主に予約されています。
- 無意味なマッピング:この状況は一般に補間によって処理されると考えられています。ただし、投影されたフレームとしては、各位置の点が均一に分布していないため、固定の線形位置を必要とする双線形補間アルゴリズムを直接使用することは困難で、
destination image
最も簡単な方法は、最近傍点を直接使用するか、切り上げを使用することです。
もちろん、順反りボイドの問題を解決する方法を専門とする人もおり、softmax-splattingの記事など、多くの新しいアイデアや方法を提案しています。
-
技術的な制限:フォワード ワープで点を取得するために最近傍法または丸め法がよく使用されるため、フォワード ワープでバックプロパゲーション アルゴリズムを使用することができなくなり、ディープ ラーニングへの応用が明確になりません。
-
スレッド セーフ:マルチスレッドおよび並列シナリオの場合、CUDA バージョンには依然としてスレッド セーフの問題があり、速度に影響します。
2.逆ワープ
隣接する画像が 2 フレーム (または左右) ある場合I 1 、I 2 I_1、I_2私1、私2,对应I 2 → I 1 I_2 \rightarrow I_1私2→私1オプティカル フロー Flow はF 2 → 1 F_{2\rightarrow1}F2 → 1次に、後方ワープ操作の下で、2 番目のフレーム画像のピクセル点I 2 ( x , y ) I_2(x,y)私2( x ,y )は、画像I 1 ( ( x , y ) + F 2 → 1 ) I_1((x,y)+F_{2\rightarrow1}) の最初のフレームにあります。私1(( x ,y )+F2 → 1) 座標位置範囲内の値を求める( I 1 I_1に相当)私1は既知です、I 2 I_2私2未知)、つまりI 2 ( x , y ) = I 1 ( x + Δ x , y + Δ y ) I_2(x,y) = I_1(x+\Delta x,y+\Delta y)私2( x ,y )=私1( ×+Δx 、_y+Δ y ),その中F 2 → 1 ( x , y ) = ( Δ x , Δ y ) F_{2\rightarrow1}(x,y) = (\Delta x,\Delta y)F2 → 1( x ,y )=( Δ x ,Δy ) ._ _ 後方ワープでは、値を検索するときにマッピング座標が整数ではないという状況が、I 1 I_1注意してください私1は既知です、I 2 I_2私2は不明ですが、私たちはI 2 I_2を支持します私2(x,y) の各座標( x , y )( x ,y)在 I 1 I_1 私1中( x + Δ x , y + Δ y ) (x+\デルタ x,y+\デルタ y)( ×+Δx 、_y+Δ y )なので整数ではない座標はI 1 I_1見つかり私1計算はの範囲内で双一次補間により近似するため、順反りの穴問題は発生しません。
逆方向のワープは、「逆方向の変形/歪み」、つまり、画像の変形方向がオプティカル フローの流れの方向と逆であると理解でき、これは人間の固有の認知的思考とはまったく異なります。たとえば、I 2 → I 1 I_2\rightarrow I_1を使用します。私2→私1オプティカル フローはI 1 I_1になります。私1I 2 I_2に変換私2; またはI 1 → I 2 I_1\rightarrow I_2を使用します。私1→私2オプティカル フロー、I 2 I_2になりますか?私2I 1 I_1に変換私1見方によれば、これは一種の後方ワープです。
逆方向ワープの考え方は、オプティカル フローFD estination → Source F_{Destination\rightarrow Source}を介して、トラバーサルdestination image
の各ポイントをトラバースすることです。p_destination
F宛先→送信元_ _ _ _ _ _ _ _のピクセル値が の値と等しくなるように、p_destination
の点Source image
に対応する点を計算します。座標が整数でない場合、一般に共一次補間を使用して計算を近似する (既知で参照されている) ため、問題はありません。その簡単な実装コードは次のとおりです。p_source
p_destination
p_source
p_source
Source Image
Forward Warping
def backward_warp(self, x, flo):
"""
warp an image/tensor (im2) back to im1, according to the optical flow(im1->im2)
x: [B, C, H, W] (im2)
flo: [B, 2, H, W] flow
"""
B, C, H, W = x.size()
# mesh grid
xx = torch.arange(0, W).view(1,-1).repeat(H,1)
yy = torch.arange(0, H).view(-1,1).repeat(1,W)
xx = xx.view(1,1,H,W).repeat(B,1,1,1)
yy = yy.view(1,1,H,W).repeat(B,1,1,1)
grid = torch.cat((xx,yy),1).float()
if x.is_cuda:
grid = grid.cuda()
vgrid = Variable(grid) + flo
# scale grid to [-1,1]
vgrid[:,0,:,:] = 2.0*vgrid[:,0,:,:].clone() / max(W-1,1)-1.0
vgrid[:,1,:,:] = 2.0*vgrid[:,1,:,:].clone() / max(H-1,1)-1.0
vgrid = vgrid.permute(0,2,3,1)
# 双线性插值 functional.grid_sample
output = nn.functional.grid_sample(x, vgrid)
# implementational hack in PyTorch0.2 for the warping function.
mask = torch.autograd.Variable(torch.ones(x.size())).cuda()
mask = nn.functional.grid_sample(mask, vgrid)
# if W==128:
# np.save('mask.npy', mask.cpu().data.numpy())
# np.save('warp.npy', output.cpu().data.numpy())
mask[mask<0.9999] = 0
mask[mask>0] = 1
return output*mask
バックワードワープの実装とアイデアも非常に明確で、主に補間を合理的に使用してデータを処理する方法がわかります。後方ワープには、次のような利点と欠点もあります。
- アルゴリズムの最適化:バックワード ワープでは、座標を計算するためにさまざまな補間が導入されます。これにより、画像が分割されたり、穴が開いたりすることはありません。また、バックワード ワープはバックプロパゲーション計算を実行できるため、バックワード ワープの適用がより広範囲かつ簡単になります。特に、研究分野。
- ゴーストの問題:後方ワープは、画像内でゴーストの問題を引き起こします。これは、この順序を保持しない変換により、マッピングの前後でピクセル間の位置関係が変化するためです。前景と背景に相対的な動きがある場合、重くなります。この曖昧さと無効な情報の本質的な理由は、相対運動によって形成されるオクルージョンです。ゴーストの問題に対する一般的な解決策は、オクルージョン マスクを導入して画像を洗練することです。
参考記事は以下の通りです。
- 画像処理の基礎 (18) オプティカルフローにおけるワープとオクルージョンの検出
- [プリンストン大学 CS426 講義、2000 年秋]
- 参考論文:「自由形状変形を使用した非剛体レジストレーション」
4. オプティカルフローの応用
オプティカルフローは、ビデオ フレーム補間、オクルージョン検出、動き推定、および一部の指標計算 (医療における心臓の緊張指標の分析など) などのシーンで広く使用されており、オプティカル フロー テクノロジはこれらのアプリケーションで良好な結果を達成しています。そして継続的な開発により、従来のオプティカル フロー テクノロジーに加えて、深層学習に基づくいくつかのオプティカル フロー テクノロジーも成熟しており、人々の生活にますます利便性をもたらしています。