開発記事公開日
格子サンプリングで遠隔巡視の「見える」を判定する

SiteVision Plannerの2Dカバレッジ判定の設計を紹介します。敷地を格子に切って1点ずつ画角・距離・遮蔽・画素密度を確かめる順序、見えなかった理由の絞り方、そしてカバー率が良くても遠隔巡視を候補にしないハードゲートの考え方です
カメラの配置図に「この範囲はたぶん見える」と書くわけにはいきません。遠隔巡視の成立性を机上で検証するSiteVision Plannerを作るとき、最初に決めなければならなかったのは、「見える」という言葉を計算可能な問いに分解することでした。この記事では、敷地を格子に切って1点ずつ判定する2Dカバレッジの設計と、その結果を「遠隔巡視に切り替えてよいか」の判定へつなぐ二段階評価の実装を紹介します。
「見える」を4つの問いに分解する
判定の単位は、巡視ゾーンの内側に等間隔で置いたサンプル点です。1つの点について、カメラごとに次の4つを順に確かめます。カメラの向きと水平画角の中に入っているか。設定したNearとFarの距離範囲に入っているか。カメラとその点を結ぶ線が構造物に遮られていないか。そして、そのカメラで映したときに要求する画素密度に届くか。
// 1点×1台の判定(抜粋)。外れた時点で理由を返す
if (!isFullCircleCoverageRad(camera.hfovRad)) {
if (Math.abs(Math.atan2(local.rightM, local.forwardM)) > camera.hfovRad / 2) {
return { visible: false, distanceM, reason: "OUT_OF_VIEW" };
}
}
if (distanceM < camera.nearM || distanceM > camera.farM) {
return { visible: false, distanceM, reason: "OUT_OF_RANGE" };
}
for (const obstacle of obstacles) {
if (pointInPolygon(sample, obstacle.corners)) {
return { visible: false, distanceM, reason: "OCCLUDED" };
}
// カメラと点を結ぶ線分が、構造物の4辺のどれかと交わるか
...
}
return { visible: true, distanceM, reason: null };
順序には意味があります。最初の3つは幾何の問いで、どれか1つでも外れれば、そのカメラからは映りません。4つめは映っていることを前提にした品質の問いです。だから点の状態は3種類に分かれます。どのカメラからも映らない「不可視」、映るカメラはあるが品質が足りない「映るが品質不足」、そして「品質OK」です。
複数のカメラがある場合、映るカメラのうち最も近いものがその点の担当になります。品質の判定も、その担当カメラまでの距離で行います。
格子の細かさは面積から逆算する
格子の間隔を細かくすれば精度は上がりますが、計算量は間隔の2乗で増えます。ブラウザで動かす以上、上限は先に決めておく必要がありました。
実装では、1ゾーンあたりのサンプル数を4,000点以下に抑える、と決めました。間隔の候補は0.5m、1m、2m、4mの4つで、ゾーンを囲む矩形の面積からサンプル数を見積もり、上限に収まる最も細かい間隔を選びます。1,200平方メートル程度の敷地なら1m間隔で収まり、画面上では格子1マスが1mとして表示されます。
画素密度という物差し
「見える」の品質は画素密度で測ります。対象の実寸1mが画像上で何画素に写るかを表す値で、単位はpx/mです。ピンホールカメラのモデルでは、画素単位の焦点距離をfx、カメラから対象までの距離をZとして、fx/Zで近似できます。近いほど密度は上がり、遠いほど下がります。
判定では、この式を逆に使います。要求する密度が決まれば、それを満たせる最大距離がfxを要求密度で割った値として求まるので、担当カメラまでの距離がこの最大距離以内かどうかを見るだけで済みます。点ごとに密度を計算し直す必要はありません。
要求密度の既定値は100px/mです。この値と、概況把握なら0.5倍、詳細確認なら2倍という品質プリセットの倍率、ゾーンの優先度ごとの要求カバー率(必須95%、高80%、通常60%、低30%)は、いずれも実機での校正を経ていない仮設定値です。アプリの画面とレポートでは、これらをASSUMEDという区分で明示しています。物理定数のように見せてはいけない、というのが計算仕様の側の決まりです。

見えなかった理由を、打ち手に近い1つへ絞る
カバー率が62%だとわかっても、それだけでは次に何をすればよいかわかりません。そこで、品質OKにならなかった点には、必ず理由を1つ付けることにしました。
難しいのは、カメラが複数あるときです。同じ点が、あるカメラからは画角外で、別のカメラからは遮蔽されている、ということが普通に起きます。理由を全部並べると読めなくなるので、1つを選ぶ規則が要ります。
採用したのは、打ち手に近い理由を残す、という優先順です。遮蔽、距離範囲外、画角外の順に優先し、あとから見つかった理由がより優先度の高いものなら置き換えます。遮蔽なら角度の違う位置へ移す、距離範囲外なら近づける、というように打ち手が具体的だからです。画角外だけは特定のカメラの問題ではないので、カメラには紐づけません。
さらに、画素密度不足の点の中では、実測の密度が最も高い点を「最も惜しい地点」として、担当カメラと実測値、要求値をセットで示します。あと少しで届く場所と、その差がわかれば、機種を変えるか近づけるかの判断材料になります。
ハードゲートは点数で相殺しない
ここまでの計算はすべて、カメラに見る能力があるかを測るものです。しかし、遠隔巡視に切り替えてよいかは、能力だけでは決まりません。直接巡視が必須の作業がある現場や、異常時に対応する担当者がいない現場は、カバー率が100%でも遠隔化の候補にはできません。
評価を二段階にしたのはそのためです。第1段階はハードゲートで、直接巡視必須の領域があるか、深刻度が最高のリスクがあるか、視覚以外の情報(臭気や温度など)が必須のリスクがあるか、異常時に対応する現場担当者がいるか、といった項目を確かめます。第2段階が、ゾーンごとのカバー率の定量評価です。
// 結果区分。ハードゲート不適合は定量結果で相殺しない
if (coverageZoneCount === 0 || input.activeCameraCount === 0) {
finalResult = "NOT_EVALUATED";
} else if (failedGates.length > 0) {
finalResult = "DIRECT_PATROL_PRIORITY";
} else if (failedZones.length > 0) {
finalResult = "NEEDS_IMPROVEMENT";
} else if (unknownGates.length > 0) {
finalResult = "NEEDS_VERIFICATION";
} else {
finalResult = "REMOTE_CANDIDATE";
}
この順序には、もう1つ判断が埋め込まれています。ハードゲートの状態は適合と不適合の2値ではなく、未確認(UNKNOWN)を持ちます。リスク評価をまだ実施していない現場は、登録済みのリスクが0件でも「リスクなし」ではありません。「評価していない」と「評価した結果リスクがなかった」を同じ合格として扱うと、何も入力していない現場ほど判定が甘くなってしまいます。未確認が残る場合は、数値がすべて合格でも「要実測検証」で止めます。


2D近似という割り切りと、次の一手
既定の判定は、上面図での2D近似です。カメラの高さや俯角、構造物の高さは考慮していません。これは意図的な割り切りで、配置の当たりを素早く付けるスクリーニングとして、まず平面で成立しない配置を捨てることを優先しました。高さ方向の関係を合否に反映したいゾーンには、3D重点評価をゾーン単位で有効にできますが、既定では使いません。
もう1つの割り切りは、判定の結果を「候補」と呼ぶことです。要求密度もカバー率も仮設定値である以上、机上の結果は実機PoCで確かめるまで確定しません。だからレポートには、判定と一緒に「実機で確認すべき項目」を載せます。実機PoCで確かめた要求密度をプロジェクトに記録すると、画面の仮設定値の表示は校正済みの根拠区分へ切り替わり、判定とレポートに一貫して反映されます。
判定のロジックを作ってみて残ったのは、数字より言葉の問題でした。カバー率という1つの数字に、能力と運用と前提のすべてを背負わせない。そのための構造がハードゲートと未確認の区分であり、この記事で紹介した設計の中心です。配置を考える側の視点からは、ガイド「遠隔巡視のカメラ配置は、何から決めればよいか」にまとめています。
SiteVision Plannerベータ版
現場図面と候補カメラから、遠隔巡視の配置案・死角・確認品質を机上で検証し、説明可能なレポートにまとめる計画支援ツール。カメラを買う前の検討に使えます







