07 采集 APS 图像
任务目标
我方相机是 HVS 融合视觉——同一颗粒既出事件(EVS)也出图像(APS)。前面几篇都在讲事件流,本篇讲图像流(APS)怎么采,并把 EVS 与 APS 同时开起来,跑出 HVS 双流的最小演示。HVS 概念见 HVS 融合视觉。
涉及类与概念
Shimeta::Frame::aps(BufferView):APS 帧原始字节,格式必须以Frame.format为准(USB/S100 通常为NV12,X5 为Gray8)。Shimeta::hv::Camera::GetFrame/SetImageCallback:同步 / 异步取 APS。Shimeta::hv::ImageData:异步回调里的图像包(pixels+ 宽高 +format+ts)。
v2.0 的关键变化
v2.0 不再直接给 cv::Mat。APS 以原始字节(BufferView)形式放在 Frame.aps / ImageData.pixels,应用必须根据 Frame.format 解码。旧版的 startImageCapture(cv::Mat) 与 getLatestImage() 已不存在。
同步:GetFrame + 解码 APS
#include <shimetapi/hv/camera.h>
#include <shimetapi/hv/device_config.h>
#include <opencv2/opencv.hpp>
int main() {
Shimeta::hv::Camera cam;
Shimeta::hv::DeviceConfig cfg;
cfg.backend = Shimeta::hv::Backend::Usb;
cfg.vendor_id = 0x1d6b;
cfg.product_id = 0x0105;
cam.Init(cfg);
if (!cam.StartStream()) return 1;
Shimeta::Frame f;
while (cam.GetFrame(f, 1000)) {
if (f.aps.data && f.format == Shimeta::PixelFormat::NV12) {
// NV12 = YUV420sp,总字节 w*h*3/2
cv::Mat nv12(f.height * 3 / 2, f.width, CV_8UC1,
const_cast<uint8_t*>(f.aps.data));
cv::Mat bgr;
cv::cvtColor(nv12, bgr, cv::COLOR_YUV420sp2BGR); // NV12 → BGR
cv::imshow("APS", bgr);
if (cv::waitKey(1) == 27) break; // ESC 退出
}
}
cam.StopStream();
cam.Destroy();
return 0;
}异步:SetImageCallback
cam.SetImageCallback([](const Shimeta::hv::ImageData& img) {
if (img.pixels.data && img.format == Shimeta::PixelFormat::NV12) {
cv::Mat nv12(img.height * 3 / 2, img.width, CV_8UC1,
const_cast<uint8_t*>(img.pixels.data));
cv::Mat bgr;
cv::cvtColor(nv12, bgr, cv::COLOR_YUV420sp2BGR);
// 转存 bgr 到主线程显示,勿在回调里直接 imshow
} else if (img.pixels.data && img.format == Shimeta::PixelFormat::Gray8) {
cv::Mat gray(img.height, img.width, CV_8UC1,
const_cast<uint8_t*>(img.pixels.data));
// X5:拷贝 gray 到主线程显示
}
});X5 的 Gray8 APS:
if (f.aps.data && f.format == Shimeta::PixelFormat::Gray8) {
cv::Mat gray(f.height, f.width, CV_8UC1,
const_cast<uint8_t*>(f.aps.data));
// 需要彩色显示时再 cvtColor(gray, bgr, cv::COLOR_GRAY2BGR)
}回调线程注意
图像回调在派发线程串行触发;cv::imshow 应在主线程,回调里建议只解码 + 拷贝,显示交给主循环。
HVS 双流:APS + EVS 同时采集
HVS 的价值就是图像 + 事件同采。v2.0 一次 GetFrame 拿到的 Frame 同时含 .aps 与 .evs(两路在芯片内像素级同步):
#include <shimetapi/codec/evt2_codec.h>
#include <vector>
Shimeta::codec::Evt2Decoder edec; // 有状态,循环外构造
Shimeta::Frame f;
while (cam.GetFrame(f, 1000)) {
// EVS:解码事件
std::vector<Shimeta::EventCD> events;
edec.Decode(f.evs.data, f.evs.size, events);
// APS:S100/USB 解码 NV12;X5 按 Gray8 直接构造 cv::Mat
// ...
}也可分别注册 SetFrameCallback(组合帧)、SetEventCallback(事件包)、SetImageCallback(图像)。
MIPI HVS
Backend::MipiHvs 的双 VC:VC0 出 EVS(RAW8 子帧流,用 MipiRaw8Decoder 解码)、VC1 出 APS。S100 经 ISP→PYM 输出 NV12;X5 走 VIN 直读并输出 Gray8。两者使用同一套 GetFrame / SetImageCallback 接口,但图像转换必须按 Frame.format 分支。MIPI 为 ARM-only,构建见 Toolkit — 快速开始。
编译运行
依赖 OpenCV、libusb 与 Hybrid Vision Toolkit;USB 权限、故障排除见 第一个 C++ 程序。RDK ARM64 MIPI 不使用 VID/PID 或 libusb。
进阶
- HVS 为什么是像素级融合:HVS 融合视觉
- 完整 API:Toolkit C++ API(USB)
- 事件流处理与可视化:指引 04、指引 05
