溝端 浩平 / Kohei Mizobata
Ocean Remote Sensing: Practical Data Analysis 06

Himawari画像から表層流速を推定する:MCC/PIVとOptical Flow

2時刻の衛星画像に写るSSTやクロロフィルa濃度の空間パターンが、次の画像でどこへ移動したかを探します。疑似データでMCC/PIVの原理を理解し、Himawari SST・CHLA画像へ適用し、最後にSST-PIVとCHLA-PIVを比較します。

MCCPIVMaximum Cross-CorrelationHimawariSSTCHLAQCOptical Flow

この演習の中心的な問い

衛星画像の「模様」は海面流に流されているのか。MCC/PIVはどのように移動量を推定し、雲・欠測・相関ピークの曖昧さをどう扱うのか。SSTとCHLAのPIVはどこまで一致するのかを考えます。

このページの構成

進め方:run06a〜run06dは穴埋め形式です。________ を自分で埋めて実行します。run06eは完全スクリプトです。各スクリプトは、上から順に「設定」「入力」「PIV計算」「QC」「図化」「保存」「関数群」という構造になっています。このページでは、その全ブロックで何をしているのかを説明します。

0. 配布ファイル

この演習では、MATLABスクリプトとHimawariのSST・CHLAデータを同じ作業フォルダに置いて実行します。Web配布では、画像・コード・データを orsprac06_assets/ にまとめます。

run06a:雲なし疑似データrun06a_MCC_synthetic_no_cloud_student.m
穴埋め版。真値変位とMCC/PIV推定値を比較します。
run06b:雲あり疑似データrun06b_MCC_synthetic_with_cloud_student_cloudQC.m
穴埋め版。雲・欠測とcloudBufferPixを含むQCを扱います。
run06c:Himawari SST-PIVrun06c_Himawari_SST_PIV_student_fine.m
穴埋め版。SST画像にMCC/PIVを適用します。
run06d:Himawari CHLA-PIVrun06d_Himawari_CHLA_PIV_student_fine.m
穴埋め版。log10(CHLA)画像にMCC/PIVを適用します。
run06e:SST-PIV / CHLA-PIV比較run06e_compare_Himawari_SST_CHLA_PIV_student_fine.m
完全版。run06c/dの出力を読み込んで比較します。
データ配置メモREADME_data_files.txt
必要なMATファイル名と配置場所のメモです。
必要なHimawari MATファイル用途
HIMAWARI_SST_Hokkaido_20260601_0100_subset.matrun06cの1時刻目SST
HIMAWARI_SST_Hokkaido_20260601_0200_subset.matrun06cの2時刻目SST
HIMAWARI_CHLA_Hokkaido_20260601_0100_subset.matrun06dの1時刻目CHLA
HIMAWARI_CHLA_Hokkaido_20260601_0200_subset.matrun06dの2時刻目CHLA
注意:4つのMATファイルは、ダウンロード後にMATLABスクリプトと同じ作業フォルダへ置いてください。あるいは、スクリプト内のファイルパスを orsprac06_assets/data/... に変更して実行してください。

1. MCC/PIVの原理:最大相互相関を探す

MCC/PIVの基本は、画像1の小窓に写る模様が、画像2のどこへ移動したかを探すことです。ここでいう「模様」は、SSTやCHLAの絶対値そのものではなく、小窓内の濃淡パターンです。相関が最大になる移動量 dx, dy を、その場所の見かけ変位とみなします。

MCC PIV schematic
図1. MCC/PIVの概念図。画像1のテンプレート窓を画像2の探索範囲内で動かし、相関が最大になる移動量を探します。相関マップのピーク位置が推定変位です。

1.1 小窓、探索範囲、相関マップ

  1. 画像1の中心点を決める。 その周囲に WINDOW_SIZE × WINDOW_SIZE の小窓を置きます。
  2. 画像2で候補位置を動かす。 dx=-MAX_SHIFT:MAX_SHIFT, dy=-MAX_SHIFT:MAX_SHIFT の範囲をすべて試します。
  3. 各候補位置で相関を計算する。 相関値を並べると、小さな相関マップになります。
  4. 最大相関ピークを探す。 その位置が整数pixelの推定変位です。
  5. ピーク周辺からサブピクセル補正を行う。 3点放物線近似により、整数pixelより細かい変位を求めます。
% Image 1 small window
A = I1(r1:r2, c1:c2);

% Candidate window in Image 2
B = I2(r1+dy:r2+dy, c1+dx:c2+dx);

% Normalized cross correlation in the window
m = isfinite(A) & isfinite(B);
a = A(m);
b = B(m);
a = a - mean(a);
b = b - mean(b);
cc = sum(a .* b) / sqrt(sum(a.^2) * sum(b.^2));

1.2 なぜ小窓内で平均を引くのか

この演習では、画像全体から広域場を引くhigh-pass処理は主処理として使いません。代わりに、相関計算の各小窓内で平均を引きます。これは、SSTやCHLAの絶対値が少し変わっても、小窓内の濃淡パターンが一致していれば相関が高くなるようにするためです。

重要:「SST全体から広域水温勾配を引く」のではなく、「相関を取る各小窓の中で平均を引く」です。前者は追跡するスケールを人工的に変えますが、後者は正規化相互相関の標準的な前処理です。

1.3 相関ピークは一意とは限らない

最大相関が1点に鋭く立つとは限りません。直線的なフロント、周期的な模様、雲縁、テクスチャの弱い場所では、複数の候補で相関が高くなることがあります。そのため、rmax だけでなく peak_gap を使います。

% bestR  : highest correlation peak
% secondR: highest independent second peak
peak_gap = bestR - secondR;

basic_qc = P.rmax >= MIN_CORRELATION & ...
           P.peak_gap >= MIN_PEAK_GAP & ...
           P.valid_fraction >= MIN_VALID_FRACTION;
意味小さい/大きいとどう解釈するか
rmax最大相関係数低いと模様が一致していない。高くても一意性は保証されません。
peak_gap最大ピークと独立した第2ピークとの差小さいと移動先が曖昧。大きいとピークが比較的一意です。
valid_fraction相関窓内で有効な画素の割合小さいと雲・陸・欠測が多く、相関が不安定です。
texture窓内パターンの標準偏差小さいと模様が弱く、どこへ移動したか決まりにくいです。
edge_flag最大ピークが探索範囲の端にあるか端にある場合、本当のピークが探索範囲外にある可能性があります。
neighbor_qc周囲ベクトルとの整合性孤立して向きや大きさが違うベクトルを落とします。

2. run06a:雲なし疑似データでMCC/PIVを理解する

run06aは、実データに入る前の基礎編です。人工的なトレーサー画像を作り、あらかじめ決めた変位場で動かし、その移動をMCC/PIVで推定します。真値があるので、推定結果の良し悪しを直接確認できます。

run06aの全ブロック解説

1. Make synthetic tracer image at time 1

最初の画像 field1 を作ります。乱数ノイズだけではPIVが難しいため、複数のガウス状パッチ、背景勾配、波状の濃淡を重ねます。ここで作るのは海洋そのものではなく、SSTやCHLAに似た「追跡できる模様」を持つ教材用画像です。

  • xg, yg:格子座標。
  • field1:時刻1の疑似トレーサー画像。
  • robust_normalize:外れ値の影響を抑え、相関計算に使いやすくする関数。
2. Define known eddy-like displacement field

真値の変位場 uTrue, vTrue を作ります。ここでは単純な一様移動ではなく、渦のような回転成分と弱い背景流を含めます。学生が「真値」と「推定値」を比べられるようにするための重要ブロックです。

  • uTrue:x方向の真の変位。pixel単位です。
  • vTrue:y方向の真の変位。pixel単位です。
  • この段階では物理単位 m/s ではなく、画像格子上の移動量として扱います。
3. Create synthetic tracer image at time 2

field1 を真値変位場で移動させ、時刻2の画像 field2 を作ります。ここでは「時刻2の各格子点に来た水塊は、時刻1ではどこにいたか」を補間で求めるため、interp2 を使います。

PIVで推定したいのは、field1field2 の間の見かけ変位です。ここでは真値を知っているので、推定の正しさを評価できます。
4. Plot input images and true displacement

入力画像と真値ベクトルを図にします。ここで、模様がどの方向へ流されているかを目で確認します。PIVの前に、画像に追跡可能な構造があるかを確認するためのブロックです。

5. MCC/PIV settings

PIVのパラメータを設定します。ここでの設定が結果の見た目と信頼性を大きく変えます。

パラメータ意味
win相関を取る小窓の大きさ。大きいほど安定、小さいほど細かい構造に敏感。
stepベクトルを計算する間隔。小さいほどベクトル密度が上がります。
maxShift探索する最大変位。真値より小さいと正しく推定できません。
minValidFraction雲なしではほぼ1に近くできます。run06b以降で重要になります。
minCorrelation, minPeakGap, minTextureStd相関の高さ、一意性、模様の強さに関するQC閾値です。
6. MCC/PIV calculation

このブロックがPIVの本体です。robust_normalize で画像を標準化し、mcc_piv_core で各窓の最大相互相関を探します。その後、basic QCとneighbor QCを順にかけます。

I1 = robust_normalize(field1, 3.0);
I2 = robust_normalize(field2, 3.0);

P = mcc_piv_core(I1, I2, win, step, maxShift, ...
                 minValidFraction, peakExcludeRadius);

basic_qc = raw_mask & ...
           P.valid_fraction >= minValidFraction & ...
           P.rmax >= minCorrelation & ...
           P.peak_gap >= minPeakGap & ...
           P.texture >= minTextureStd & ...
           ~P.edge_flag;

neighbor_qc = neighbor_consistency_qc(P.dx, P.dy, basic_qc, maxNeighborDiff);
final_qc = basic_qc & neighbor_qc;

basic_qc は各ベクトル単体の品質、neighbor_qc は周囲との整合性です。どちらか一方だけでは不十分です。

7. Plot true vs estimated vectors

真値ベクトルと推定ベクトルを並べます。ここでは「推定できている場所」と「推定が怪しい場所」を目で確認します。真値があるrun06aでしかできない重要な診断です。

8. Plot components and correlation diagnostics

dx, dy, rmax, peak_gap などを地図状に表示します。ベクトル図だけでは、なぜ落ちたのか・なぜ残ったのかが分かりにくいため、QC診断図を必ず確認します。

9. Save result

結果をMATファイルに保存します。後から比較・図の再作成・誤差計算をするため、推定ベクトルだけでなく、真値、QCマスク、相関診断量も保存します。

Local functions

スクリプト末尾には、計算を支えるローカル関数があります。授業では中身を全部書く必要はありませんが、役割は理解します。

関数役割
mcc_piv_core小窓を走査し、相関最大の変位を求めるPIV本体。
window_corrNaNを除き、小窓内平均を引いて正規化相互相関を計算。
second_peak_excluding_radius最大ピークの肩を除外し、独立した第2ピークを探す。
parabola_subpixel相関ピークの周辺3点からサブピクセル補正。
neighbor_consistency_qc周囲ベクトルの中央値と大きく違う孤立ベクトルを落とす。
run06a input
図2. run06aの入力画像と真値変位。疑似データなので、どこへ動いたかがあらかじめ分かっています。
run06a true vs estimated
図3. 真値ベクトルとMCC/PIV推定ベクトルの比較。推定値が真値に近い場所と、QCで落とすべき場所を確認します。
run06a diagnostics
図4. dx, dy, 相関係数などの診断図。ベクトルが合っているかを成分ごとに確認できます。

3. run06b:雲あり疑似データと cloudBufferPix

run06bは、run06aに雲・欠測を加えた版です。MCC/PIVは窓内に十分な有効画素があれば相関を計算できてしまうため、中心点が雲上にあるベクトルや、推定された移動先が雲上にあるベクトルを明示的に落とす必要があります。

run06bの全ブロック解説

1〜3. 疑似画像と真値変位場の作成

run06aと同じです。雲を入れる前の「本当なら追跡できる画像」を作ります。ここをrun06aと同じ構造にすることで、雲の影響だけを比較できます。

4. Add artificial clouds

人工的な雲マスク cloudMask1, cloudMask2 を作り、雲の場所をNaNにします。雲は「値が見えない領域」です。PIVではNaNを相関計算から除外しますが、それだけでは雲縁や中心点の問題が残ります。

  • cloudMask1:画像1の雲。
  • cloudMask2:画像2の雲。
  • field1_cloudy, field2_cloudy:雲部分をNaNにした画像。
5. Plot clean and cloudy images

雲なし画像と雲あり画像を比較します。雲によって相関窓がどの程度欠けるかを視覚的に確認します。

6. MCC/PIV settings

run06aの設定に加えて、雲QC用の cloudBufferPix を設定します。

cloudBufferPix の意味

cloudBufferPix = 2 は、雲本体に加えて、その周囲2 pixelも危険域として扱うという意味です。3や4にすると安全側になりますが、良いベクトルまで消えてしまうことがあります。この演習では、雲縁の危険性を見せつつ、推定可能領域を残すために2を使います。

7. MCC/PIV calculation using valid pixels only

雲あり画像をrobust normalizeしてMCC/PIVを実行します。相関計算では isfinite(A) & isfinite(B) により、NaN画素を除外します。しかし、窓の一部が雲で欠けていても相関は出るため、追加でcloud QCを行います。

cloudMask1_buffer = buffer_logical_mask(cloudMask1, cloudBufferPix);
cloudMask2_buffer = buffer_logical_mask(cloudMask2, cloudBufferPix);

origin_clear = sample_logical_mask(~cloudMask1_buffer, P.ix, P.iy);
target_clear = sample_logical_mask(~cloudMask2_buffer, P.ix + P.dx, P.iy + P.dy);

cloud_qc = raw_mask & origin_clear & target_clear;

origin_clear はベクトル始点、target_clear は推定された移動先を調べます。これにより、中心点が雲上なのに窓の周辺だけで相関が出てしまう問題を防ぎます。

8. Plot bad vectors before QC

QC前のベクトルをあえて表示します。雲や雲縁の上にもベクトルが出てしまうことを確認するためです。この図は「なぜQCが必要か」を理解するために重要です。

9. Plot QC steps

valid_fraction, rmax, peak_gap, cloud_qc, basic_qc, neighbor_qc, final_qc を段階的に表示します。どのQCでどのベクトルが落ちたかを確認します。

10. Plot final vectors

最終QC後のベクトルを表示します。雲ありでは推定可能領域が減りますが、雲のない場所ではPIVが成立することを確認します。雲縁に少し残るベクトルは、実データでも起こり得る注意点です。

11. Plot final components and error

最終QC後の dx, dy, 誤差、相関を表示します。雲あり条件で、残ったベクトルがどの程度真値に合っているかを確認します。

12. Save result

雲マスク、cloud QC、最終QC、真値、推定値を保存します。保存しておくことで、雲バッファや閾値を変えたときの比較ができます。

Local functions
関数役割
buffer_logical_mask雲マスクを指定pixelだけ膨張させ、雲縁の危険域を作る。
sample_logical_mask浮動小数点の始点・終点位置で、雲マスク上かどうかを最近傍で調べる。
mcc_piv_core, window_corrrun06aと同じPIV本体。NaNを除外して相関を計算します。
neighbor_consistency_qc孤立した変なベクトルを落とす。
run06b cloudy
図5. 雲なし画像と雲あり画像。雲はNaNとして扱い、相関計算から除外します。
run06b bad vectors
図6. QC前のベクトル。雲や雲縁の影響で、明らかに怪しいベクトルが含まれます。
run06b qc
図7. QCの各段階。Cloud-origin/target QC により、雲上・雲縁付近のベクトルを落とします。
run06b final
図8. 最終QC後のベクトル。雲があると推定可能領域は減りますが、雲のない領域ではPIVが成立します。
run06b diagnostics
図9. 最終QC後の成分・相関診断。雲あり条件で、どの場所の推定が信頼できるかを確認します。

4. run06c:Himawari SST画像への適用

run06cでは、疑似データではなくHimawariのSST画像2時刻を使います。ここからは真値がありません。したがって、相関診断、QC、物理的に妥当な速度範囲、SSTパターンとの対応を見て判断します。

run06cの全ブロック解説

0. User settings

入力ファイル、出力フォルダ、PIVモード、ROIを設定します。ここを変えるだけで、広域・fine・ROI集中解析を切り替えられます。

設定意味
PIV_MODE = 'standard'広域で安定なベクトルを優先。窓は大きめ。
PIV_MODE = 'fine'沿岸・小渦を拾いやすくする標準設定。本演習の基本。
PIV_MODE = 'roi_eddy'148E, 38.5N付近など、ROIだけ高密度に見る設定。
ROI_LON, ROI_LATズーム図やROI解析に使う領域。
1. Load data

SSTのMATファイル2つを読み込みます。想定される変数は lon, lat, SST です。緯度が降順になっている場合は、図化・計算しやすいように昇順へ直します。

  • ensure_lat_ascending:緯度配列とデータを南から北へ並べ直します。
  • crop_domain:ROIモードでは指定範囲だけ切り出します。
  • SSTの非現実的な値や欠測はNaNとして扱います。
2. Analysis settings

格子間隔、時間差、PIV窓、QC閾値を決めます。SSTはCHLAより滑らかなので、テクスチャ閾値は厳しすぎるとベクトルが残りません。

設定意味
WINDOW_SIZE相関窓の大きさ。SSTでは大きいほど安定しますが、小渦は平均化されます。
STEPPIVベクトルの間隔。
MAX_SHIFT1時間差で探索する最大pixel変位。
MIN_TEXTURE_STDSSTの模様の強さ。厳しすぎると滑らかな海域のベクトルが消えます。
MAX_SPEED_MS物理的に大きすぎる見かけ速度を落とす閾値。
3. Make matching images

SST画像をMCC/PIV用画像 I1, I2 に変換します。ここでは画像全体から広域場を引きません。raw SSTを robust_normalize し、相関計算の各小窓内で平均を引きます。

% SST matching images: no broad high-pass subtraction
I1 = robust_normalize(SST1, 3.0);
I2 = robust_normalize(SST2, 3.0);

SSTは南北勾配や水塊境界が強いため、模様が滑らかな場所では移動先が曖昧になります。そのため rmax だけでなく peak_gapneighbor_qc を必ず確認します。

4. MCC/PIV calculation

mcc_piv_core で変位 dx, dy を求め、格子間隔と時間差から U, V, speed に変換します。ここで初めて pixel変位が m/s になります。

P = mcc_piv_core(I1, I2, lon, lat, WINDOW_SIZE, STEP, MAX_SHIFT, ...
                 MIN_VALID_FRACTION, PEAK_EXCLUDE_RADIUS);

[P.U, P.V, P.speed] = grid_displacement_to_velocity(P.dx, P.dy, ...
    P.lat, dlon, dlat, dt_seconds);

basic_qc = P.valid_fraction >= MIN_VALID_FRACTION & ...
           P.rmax >= MIN_CORRELATION & ...
           P.peak_gap >= MIN_PEAK_GAP & ...
           P.texture >= MIN_TEXTURE_STD & ...
           P.speed <= MAX_SPEED_MS & ...
           ~P.edge_flag & ...
           isfinite(P.dx) & isfinite(P.dy);
5. Figures

入力画像、QC前後、最終ベクトル、QC診断、ROIズームを作ります。PIVは数値だけでは信頼性を判断しにくいため、必ずQC診断図を一緒に見ます。

6. Save figures and result files

図、MATファイル、CSVを保存します。MATファイルには、lon_piv, lat_piv, U_piv, V_piv, speed_piv, mask_final などを保存します。run06eはこの出力を読みます。

Local functions
関数役割
build_piv_structrun06eで読みやすい共通形式にPIV結果をまとめる。
write_piv_csv比較・表計算用にベクトルをCSV出力。
mcc_piv_core2画像間の変位推定の本体。
grid_displacement_to_velocitypixel変位をm/sに変換。経度方向は緯度によって距離が変わります。
plot_vectors, plot_piv_fieldベクトル図と速度場を描く。
SST input
図10. Himawari SST画像とMCC入力画像。広域high-passではなく、robust normalizeしたSSTを使います。
SST QC
図11. SST-PIVのQC前後。QC前は怪しいベクトルが多く、QC後はSSTパターンが追える場所にベクトルが残ります。
SST final
図12. 最終SST-PIVベクトル。SSTはCHLAより滑らかなため、ベクトル密度はやや低くなります。
SST diagnostics
図13. SST-PIVのQC診断。rmax, peak_gap, texture, basic QC, neighbor QC を確認します。
SST ROI
図14. 148E, 38.5N付近のROI拡大図。広域図では見えにくい小渦・沿岸構造を確認します。

5. run06d:Himawari CHLA画像への適用

run06dはrun06cのCHLA版です。ただし、CHLAは値の範囲が広く、0や負値を含むとlog変換できないため、SSTとは前処理が少し違います。

run06dの全ブロック解説

0. User settings

入力CHLAファイル、出力フォルダ、PIVモード、ROIを設定します。roi_eddy では0.01°のCHLAを活かすこともできますが、通常のfine modeではSSTと比較しやすいように0.02°程度へ粗視化します。

1. Load data

CHLAのMATファイル2つを読み込みます。CHLAは海色アルゴリズム由来の値なので、SSTより欠測・ノイズ・沿岸影響が多くなります。緯度方向の並びをそろえ、必要ならROIを切り出します。

2. Analysis settings

CHLA用のPIVパラメータを設定します。CHLAは細かいパッチやフィラメントが多く、SSTよりベクトルが出やすい一方、ノイズや大気補正の影響も拾いやすいです。

設定意味
COARSEN_FACTOR0.01°CHLAを何pixel平均するか。2なら0.02°程度になります。
CHLA_CLIM図の背景表示範囲。PIV計算の閾値ではありません。
VECTOR_COLOR = 'r'CHLA背景上でベクトルを見やすくするため、赤で表示します。
3. Make matching images

CHLAはまず正値だけを残し、log10(CHLA) に変換します。その後、必要に応じて粗視化し、robust normalizeします。SSTと同様、画像全体のhigh-passは行いません。

CHLA1_native(CHLA1_native <= 0) = NaN;
CHLA2_native(CHLA2_native <= 0) = NaN;

LCHLA1_native = log10(CHLA1_native);
LCHLA2_native = log10(CHLA2_native);

[lon, lat, LCHLA1] = block_nanmean_2d(lon0, lat0, LCHLA1_native, COARSEN_FACTOR);
[~,   ~,   LCHLA2] = block_nanmean_2d(lon0, lat0, LCHLA2_native, COARSEN_FACTOR);

I1 = robust_normalize(LCHLA1, 3.0);
I2 = robust_normalize(LCHLA2, 3.0);
4. MCC/PIV calculation

run06cと同じMCC/PIV関数を使います。SSTとCHLAで同じ思想の相関計算を使うことで、run06eで比較しやすくします。違うのは、CHLAでは log10 と粗視化を先に行う点です。

5. Figures

入力画像、QC前後、最終ベクトル、QC診断、ROIズームを保存します。CHLAはベクトルが多く出るので、図としては密になります。これは必ずしも全部が正しいという意味ではなく、追跡できる濃淡パターンが多いという意味です。

6. Save figures and result files

MATとCSVを保存します。run06eは、SSTと同じ形式の piv 構造体を読み、SST-PIVとCHLA-PIVを比較します。

Local functions

run06cとほぼ同じ関数群に加え、CHLA粗視化のための block_nanmean_2d が重要です。

関数役割
block_nanmean_2dNaNを無視して2×2などのブロック平均を行い、CHLAを粗視化します。
plot_vectorsCHLA版では色と線幅を指定できるようにしてあります。
mcc_piv_core, window_corrSSTと同じ相関計算。小窓内平均を引きます。
CHLAの解釈:CHLAパターンは海流に流されるだけでなく、生物増殖・減衰、光条件、大気補正、沿岸濁り、CDOM、雲縁の影響も受けます。したがって、CHLA-PIVは「見かけのパターン速度」として解釈します。
CHLA input
図15. CHLA画像とMCC入力画像。log10変換後の空間パターンを追跡します。
CHLA QC
図16. CHLA-PIVのQC前後。CHLAは細かな濃淡パターンが多く、SSTより多くのベクトルが得られます。
CHLA final
図17. 最終CHLA-PIVベクトル。ベクトル密度は高いですが、全てが純粋な流れを示すとは限りません。
CHLA diagnostics
図18. CHLA-PIVのQC診断。CHLAはテクスチャが多い一方、ノイズや雲縁の影響にも注意します。
CHLA ROI
図19. ROI拡大図。CHLAのフィラメントやパッチに沿った見かけ速度を確認します。

6. run06e:SST-PIVとCHLA-PIVの比較

run06eは完全スクリプトです。run06cとrun06dで保存したPIV結果を読み、SST-PIVとCHLA-PIVを比較します。SSTとCHLAは同じ海流場に影響されますが、トレーサーとしては異なるため、完全一致は期待しません。

run06eの全ブロック解説

0. Header and settings

run06c/dの出力MATファイル名、出力フォルダ、ROI、比較半径を設定します。run06eは穴埋めではありません。比較の考え方を読むための完全版です。

Load SST and CHLA PIV results

run06c_SST_PIV_vectors.matrun06d_CHLA_PIV_vectors.mat を読みます。これらには、ベクトル位置、U/V成分、速度、QCマスクが入っています。

Overlay figure

全域でSST-PIVを黒、CHLA-PIVを赤で重ねます。これは全体像を見る図です。CHLAの方がベクトル数が多いため、見た目だけで一致・不一致を判断するのは危険です。

ROI overlay figure

148E, 38.5N付近など、注目領域だけを拡大して重ねます。広域図では見えない局所的な一致・不一致を確認します。

Nearest-neighbor comparison at SST vector points

各SSTベクトルに対して、近傍のCHLAベクトルを探し、速度差と方向差を計算します。現行版では、SSTベクトル位置から一定距離内のCHLAベクトルを対応させる比較を行います。

% Concept:
% For each SST-PIV vector, find a nearby CHLA-PIV vector.
% Then compare:
%   speed difference    = CHLA speed - SST speed
%   direction difference = angle between SST and CHLA vectors
Statistics figure

速度散布図、速度差ヒストグラム、方向差ヒストグラムを作ります。速度差が0付近にピークを持つなら、速度スケールは大きく破綻していません。方向差が0°側に山を持つなら、少なくとも一部では同じ移流場を反映していると考えられます。

Save comparison table

SSTとCHLAの対応ベクトル、速度差、方向差をMATファイルやCSVに保存します。後で条件を変えて再解析するために、図だけでなく数値表も残します。

Local functions
関数役割
extract_vectorsPIV構造体から、最終QCを通ったベクトルだけを取り出す。
plot_vectors_structPIV構造体から指定色でベクトルを描く。
save_figure_set複数図をPNGとして保存。
速度差CHLA speed - SST speed が0付近にピークを持つなら、速度スケールは近いと解釈できます。
方向差0°に近いほど同じ向きです。大きな尾は、トレーサー差・ノイズ・PIVの曖昧さを示します。
一致域SSTとCHLAの両方で似たベクトルが出る場所は、流れを反映している可能性が高いです。
不一致域不一致は失敗とは限りません。SSTとCHLAは異なるトレーサーであり、変化過程も異なります。
SST CHLA overlay
図20. SST-PIV(黒)とCHLA-PIV(赤)の重ね描き。CHLAは高密度に得られるため、見た目だけでは一致・不一致を判断しにくいこともあります。
SST CHLA ROI
図21. ROI拡大比較。局所的に向きが近い場所と、ずれる場所があることを確認します。
SST CHLA stats
図22. 速度差と方向差の統計。速度差が0 m s-1 付近にピークを持つことは、SST-PIVとCHLA-PIVの速度スケールが大きく破綻していないことを示します。一方、方向差は広がりを持つため、トレーサー差や画像ノイズの影響を考える必要があります。
演習としての解釈:SST-PIVとCHLA-PIVは完全一致しません。しかし、速度差が0付近に集まり、方向差も0°側に山を持つなら、少なくとも一部では同じ移流場を反映していると説明できます。複数トレーサーで一致する場所は信頼度が高く、不一致の場所はトレーサー特性・雲・ノイズ・相関ピークの曖昧性を疑います。

7. おまけ:Optical Flowとは何か

Optical Flowは、画像中の明るさパターンが連続的にどう動いたかを、画素ごと、または高密度格子で推定する手法です。MCC/PIVが「小窓ごとに最も似ている場所」を探すのに対し、Optical Flowはより密な変位場を求めます。

7.1 Optical Flowの基本仮定

多くのOptical Flow法は、短い時間では同じ模様の明るさが保存されるという仮定を置きます。これを brightness constancy と呼びます。

brightness constancy の考え方

時刻1で位置 (x,y) にあった模様が、時刻2で (x+u, y+v) に移動したとき、明るさがほぼ同じだと仮定します。SSTやCHLAでは、この仮定は近似です。SSTは加熱・冷却、CHLAは生物過程や大気補正の影響を受けます。

7.2 MCC/PIVとの違い

項目MCC/PIVOptical Flow
推定単位小窓ごと画素ごと、または高密度格子
考え方相関が最大になる位置を探す明るさ保存と平滑性から連続変位場を推定
長所相関ピーク、peak gap、valid fractionなどQCが明示しやすい密なベクトル場が得られ、滑らかな流れを表現しやすい
短所窓サイズに依存し、小スケールと安定性の両立が難しい滑らかに見えるが、物理的に正しいとは限らない
衛星海洋画像での注意雲・陸・低テクスチャで相関が曖昧SSTの日変化、CHLAの生物過程、雲縁を流れとして誤推定しやすい

7.3 MATLABでの例

Computer Vision Toolboxが使える環境では、opticalFlowFarneback などを用いてOptical Flowを試せます。ただし、密なベクトル場が出るからといって、MCC/PIVより正しいとは限りません。むしろ、QCと物理的な解釈が難しくなることがあります。

% Example idea only
opticFlow = opticalFlowFarneback;
flow1 = estimateFlow(opticFlow, I1_gray);
flow2 = estimateFlow(opticFlow, I2_gray);

u = flow2.Vx;
v = flow2.Vy;
この演習でMCC/PIVを主役にする理由:MCC/PIVは「どの窓で相関が高いか」「最大ピークが一意か」「雲や欠測の影響があるか」を学生が追いやすい方法です。Optical Flowは発展課題として、MCC/PIVと結果を比較するのがよいです。

最後の考察課題

  1. MCC/PIVで、rmax が高いのに信頼できないベクトルが出るのはどのような場合ですか。
  2. peak_gap は何を表し、なぜ最大相関だけでは不十分なのですか。
  3. run06bで、valid_fraction だけでなく cloud_qc が必要な理由を説明してください。
  4. cloudBufferPix を2から4に増やすと何が起きますか。安全側になる一方で、どのような欠点がありますか。
  5. SST-PIVではCHLA-PIVよりベクトル数が少なくなることがあります。その理由を、トレーサーの空間パターンの違いから説明してください。
  6. CHLA-PIVで得られる見かけ速度が、必ずしも海流そのものではない理由を説明してください。
  7. run06eの速度差・方向差ヒストグラムから、SST-PIVとCHLA-PIVの一致・不一致をどう解釈しますか。
  8. Optical Flowを用いる場合、MCC/PIVと比べてどのような利点と危険性がありますか。

戻る