EV74 視覺前端節點
請透過公開 Graph 節點工廠使用 EV74 運算,並安裝相符的 Core、Scheduler、Runner、Kernels 與 EV74 韌體套件。舊版圖 ID 不能用於檢查原生韌體相容性;應用程式不需要分派器 ID。
品質選項保留既有原始碼用法與預設輸出位置,但會變更 TrackKLTOptions 的 C++ 配置,因此既有 C++ 二進位檔不具 ABI 相容性。請針對相符的 Core 版本重新建置 C++ 應用程式與 Python 擴充套件。v2 追蹤器要求須使用相符的 Kernels、Runner、Scheduler 與 EV74 韌體組合。既有的原生 v1 要求仍受支援,但這不代表 v2 要求與舊版韌體相容。
| 節點工廠 | 用途 |
|---|---|
nodes::FeatureHistogram / pyneat.nodes.feature_histogram | 灰階直方圖 |
nodes::GriderFast / pyneat.nodes.grider_fast | 網格分布的 FAST 特徵點 |
nodes::TrackDescriptor / pyneat.nodes.track_descriptor | FAST 特徵點與 BRIEF 描述子 |
nodes::TrackKLT / pyneat.nodes.track_klt | 金字塔 KLT 追蹤及選用的目前影格特徵偵測 |
張量契約
影像張量的邏輯形狀是 [B,H,W],其中 B 為 batch_size。不要將批次併入影像高度。裝置輸入可使用獨立配置或有效的共用儲存檢視,不需要 CPU 複製的替代方案。
| 節點 | 輸入 | 預設公開輸出 |
|---|---|---|
FeatureHistogram | UInt8 [B,H,W] | Int32 [B,256] |
GriderFast | UInt8 [B,H,W] | Int32 [B,1+3*max_features] |
TrackDescriptor | UInt8 [B,H,W] | Int32 [B,1+3*max_features]; Int32 [B,max_features,8] |
TrackKLT | UInt8 [B,H,W]; UInt8 [B,H,W]; Int32 [B,num_points,2] | Float32 [B,num_points,2]; Int32 [B,num_points,1] |
每個批次項目的特徵格式為 [count,x0,y0,score0,...]。只讀取前 count 筆記錄,未使用容量不是特徵清單。TrackDescriptor 要求 descriptor_words == 8;每列描述子對應相同列的已選特徵。
網格選擇與邊界
grid_x 和 grid_y 將整張影像分成網格。容量為 K、網格數為 M 時,每格有 K / M 個名額,列優先順序的前 K % M 格各多一個。每格選擇最強分數,再將結果按分數遞減排列,同分按 (y,x) 遞增排列。稀疏網格不出借名額。min_px_dist 會跨網格邊界抑制過近的點,距離恰等於設定值則接受。抑制後不補入其他候選,因 此結果可能少於 max_features。
一般 FAST 包含 x=3、y=3、x=W-4 與 y=H-4 的中心點。TrackDescriptor 需要完整的 31×31 BRIEF 區塊,因此中心必須距各邊至少 15 像素。第 3 列沒有描述子是預期行為。
KLT 輸入與輸出
請依 前一張影像、目前影像、輸入點 順序傳入 TensorList。在此直接公開多輸入路徑上,非空的邏輯 route.name 必須符合設定的位置,不會重新排序清單。順序正確的未命名張量仍有效。缺少輸入、名稱矛盾、型別或形狀錯誤,以及無法存取的範圍,都會在提交前拒絕,後續影格也一樣。
重用相容的輸出張量時,建立淺層複本,僅依新公開位置重新命名或清除 route.name。請保留儲存、位移與實體路由中繼資料。此規則不會重新命名內部圖連接,也不取代明確的模型輸入路由處理器。
TrackKLT 預設公開點與狀態。detect_new_features != 0 會附加 目前 影像的偵測特徵。停用偵測時不配置隱藏特徵輸出。publish_error = true 在既有輸出後附加 Float32 [B,num_points,1]:未啟用偵測時索引為 2,啟用時為 3。既有輸出位置不變。
C++ 範例
提供兩個 640×480 UInt8 影像向量及 64×2 Int32 初始座標。以下各輸入都有獨立 EV74 儲存,傳回的組依序為點、狀態、誤差。
#include <neat.h>
#include <cstdint>
#include <vector>
using namespace simaai::neat;
TensorList track_pair(const std::vector<std::uint8_t>& previous,
const std::vector<std::uint8_t>& current,
const std::vector<std::int32_t>& xy) {
constexpr int width = 640, height = 480, count = 64;
auto image = [&](const auto& pixels, const char* name) {
auto tensor = Tensor::from_vector(pixels, {1, height, width}, TensorMemory::EV74);
tensor.layout = TensorLayout::HW;
tensor.axis_semantics = {TensorAxisSemantic::N, TensorAxisSemantic::H,
TensorAxisSemantic::W};
tensor.route.name = name;
return tensor;
};
auto points = Tensor::from_vector(xy, {1, count, 2}, TensorMemory::EV74);
points.route.name = "input_points";
TensorList inputs{image(previous, "prev_image"), image(current, "cur_image"), points};
InputOptions input;
input.payload_type = PayloadType::Tensor;
input.format = FormatTag::UINT8;
input.width = input.max_width = width;
input.height = input.max_height = height;
input.depth = input.max_depth = 1;
input.memory_policy = InputMemoryPolicy::Ev74;
input.buffer_name = "prev_image";
input.caps_override = "application/vnd.simaai.tensor, representation=(string)tensor-set, "
"storage=(string)tensorbuffer";
TrackKLTOptions klt;
klt.width = width;
klt.height = height;
klt.num_points = count;
klt.win_half = 7;
klt.max_level = 2;
klt.max_iters = 20;
klt.publish_error = true;
Graph graph;
graph.add(nodes::Input(input));
graph.add(nodes::TrackKLT(klt));
graph.add(nodes::Output());
RunOptions options;
options.output_memory = OutputMemory::Owned;
Run run = graph.build(inputs, options);
TensorList outputs;
try {
outputs = run.run(inputs, 30000);
} catch (...) {
run.close();
throw;
}
run.close();
return outputs;
}
品質控制
| 選項 | 預設值 | 意義 |
|---|---|---|
publish_error | false | 公開最終座標的平均絕對亮度殘差。output_error_name 預設為 output_error。 |
error_threshold | -1.0 | -1 表示停用,否則為 [0,255] 的有限門檻。殘差大於門檻時拒絕,相等時接受。未公開誤差時也可過濾。 |
min_eig_threshold | 0.0 | 0 表示停用,否則為有限正值的正規化最小特徵值門檻,用於紋理條件判定。 |
require_convergence | false | 要求最後的全解析度更新符合收斂條件。設為 false 時,達到反覆運算上限不代表失敗。 |
殘差是亮度差,不是像素位移或信心值。它在傳回座標上評估;+inf 表示未評估有效殘差。紋理指標將中央差分梯度矩陣的最小特徵值除以視窗面積及 255²,其尺度不可與 OpenCV 門檻互換。請使用代表性校正資料選擇門檻,並同時驗證有效追蹤保留率及錯誤追蹤拒絕率。
使用座標前請檢查狀態。求解前無效的初始點保留原座標且狀態為 0。有限的影像外計算點,或被品質門檻拒絕的候選,可能保留計算座標且狀態為 0。預設狀態只代表求解與幾何有效性,不保證真實世界對應正確。
移動、邊界與固定點數
細化位置離開目前影像區塊時,會重新置中並載入區塊,不會默默限制在 ±4 像素搜尋範圍。重新載入及反覆運算次數仍有上限。邊界區塊只從影像內進行 DMA,並複製邊緣像素。這會移除舊版隨金字塔層級改變的排除帶,但不保證任意移動、遮蔽或模糊紋理都可追蹤。
Core 初始點仍為 Int32,結果為 Float32。num_points 在建圖時固定。未使用的位置請填入 (-1,-1) 等無效座標並檢查狀態。(0,0) 是有效邊緣座標,不是停用標記。每次呼叫都會重建兩張影像的金字塔,不表示會重用前一影格金字塔。