fix: capture full frame with ROI restoration
This commit is contained in:
parent
ee4a6625eb
commit
46f025327b
@ -106,6 +106,100 @@ struct VizumCamera::Impl {
|
|||||||
#ifdef ENABLE_VIZUM_CAMERA
|
#ifdef ENABLE_VIZUM_CAMERA
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
|
class DetectRoiRestoreGuard
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
DetectRoiRestoreGuard(VZNLHANDLE device,
|
||||||
|
const SVzNLROIRect& leftROI,
|
||||||
|
const SVzNLROIRect& rightROI)
|
||||||
|
: m_device(device), m_leftROI(leftROI), m_rightROI(rightROI)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RestoreNow()
|
||||||
|
{
|
||||||
|
if (m_restored)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
const int ret = VzNL_ConfigDetectROI(m_device, &m_leftROI, &m_rightROI);
|
||||||
|
if (ret != 0) {
|
||||||
|
char errorMsg[256] = {0};
|
||||||
|
VzNL_GetErrorInfo(ret, errorMsg);
|
||||||
|
LOG_ERROR("[VizumCamera] Failed to restore detection ROI: {} (error code: {})",
|
||||||
|
errorMsg, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
m_restored = true;
|
||||||
|
LOG_INFO("[VizumCamera] Detection ROI restored: left=[{}, {}, {}, {}], "
|
||||||
|
"right=[{}, {}, {}, {}]",
|
||||||
|
m_leftROI.left, m_leftROI.right, m_leftROI.top, m_leftROI.bottom,
|
||||||
|
m_rightROI.left, m_rightROI.right, m_rightROI.top, m_rightROI.bottom);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
~DetectRoiRestoreGuard()
|
||||||
|
{
|
||||||
|
if (!m_restored && !RestoreNow())
|
||||||
|
LOG_ERROR("[VizumCamera] Emergency detection ROI restoration failed");
|
||||||
|
}
|
||||||
|
|
||||||
|
DetectRoiRestoreGuard(const DetectRoiRestoreGuard&) = delete;
|
||||||
|
DetectRoiRestoreGuard& operator=(const DetectRoiRestoreGuard&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
VZNLHANDLE m_device = nullptr;
|
||||||
|
SVzNLROIRect m_leftROI{};
|
||||||
|
SVzNLROIRect m_rightROI{};
|
||||||
|
bool m_restored = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool NormalizeToDeviceFrame(SLImage& image, uint32_t frameWidth, uint32_t frameHeight)
|
||||||
|
{
|
||||||
|
if (image.empty() || frameWidth == 0 || frameHeight == 0
|
||||||
|
|| image.originX < 0 || image.originY < 0 || image.channels <= 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t right = static_cast<uint64_t>(image.originX) + image.width;
|
||||||
|
const uint64_t bottom = static_cast<uint64_t>(image.originY) + image.height;
|
||||||
|
if (right > frameWidth || bottom > frameHeight)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (image.originX == 0 && image.originY == 0
|
||||||
|
&& image.width == frameWidth && image.height == frameHeight) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t bytesPerChannel = image.bitDepth > 8 ? 2u : 1u;
|
||||||
|
const size_t pixelBytes = static_cast<size_t>(image.channels) * bytesPerChannel;
|
||||||
|
const size_t sourceRowBytes = static_cast<size_t>(image.width) * pixelBytes;
|
||||||
|
if (image.data.size() < sourceRowBytes * image.height)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SLImage fullImage;
|
||||||
|
fullImage.width = frameWidth;
|
||||||
|
fullImage.height = frameHeight;
|
||||||
|
fullImage.originX = 0;
|
||||||
|
fullImage.originY = 0;
|
||||||
|
fullImage.channels = image.channels;
|
||||||
|
fullImage.bitDepth = image.bitDepth;
|
||||||
|
fullImage.data.assign(static_cast<size_t>(frameWidth) * frameHeight * pixelBytes, 0);
|
||||||
|
|
||||||
|
const size_t targetRowBytes = static_cast<size_t>(frameWidth) * pixelBytes;
|
||||||
|
const size_t targetXBytes = static_cast<size_t>(image.originX) * pixelBytes;
|
||||||
|
for (uint32_t row = 0; row < image.height; ++row) {
|
||||||
|
const size_t sourceOffset = static_cast<size_t>(row) * sourceRowBytes;
|
||||||
|
const size_t targetOffset = (static_cast<size_t>(image.originY) + row) * targetRowBytes
|
||||||
|
+ targetXBytes;
|
||||||
|
std::memcpy(fullImage.data.data() + targetOffset,
|
||||||
|
image.data.data() + sourceOffset, sourceRowBytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
image = std::move(fullImage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
const char* DeviceStatusName(int status)
|
const char* DeviceStatusName(int status)
|
||||||
{
|
{
|
||||||
switch (static_cast<EVzDeviceWorkStatus>(status)) {
|
switch (static_cast<EVzDeviceWorkStatus>(status)) {
|
||||||
@ -826,6 +920,8 @@ bool VizumCamera::ConvertVzImageToSLImage(void* vzImagePtr, SLImage& slImage)
|
|||||||
|
|
||||||
slImage.width = vzImage->nWidth;
|
slImage.width = vzImage->nWidth;
|
||||||
slImage.height = vzImage->nHeight;
|
slImage.height = vzImage->nHeight;
|
||||||
|
slImage.originX = vzImage->ptOriPos.x;
|
||||||
|
slImage.originY = vzImage->ptOriPos.y;
|
||||||
slImage.channels = vzImage->nChannels;
|
slImage.channels = vzImage->nChannels;
|
||||||
slImage.bitDepth = vzImage->byBitDepth;
|
slImage.bitDepth = vzImage->byBitDepth;
|
||||||
|
|
||||||
@ -864,6 +960,100 @@ bool VizumCamera::GetRightImage(SLImage& image)
|
|||||||
return !image.empty();
|
return !image.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VizumCamera::CaptureFullFrameLeftImage(SLImage& image, std::string& frameId)
|
||||||
|
{
|
||||||
|
image.clear();
|
||||||
|
frameId.clear();
|
||||||
|
#ifdef ENABLE_VIZUM_CAMERA
|
||||||
|
const std::lock_guard<std::mutex> deviceLock(m_deviceAccessMutex);
|
||||||
|
if (!m_isConnected || !m_deviceHandle) {
|
||||||
|
LOG_ERROR("[VizumCamera] Full-frame capture failed: device not connected");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SVzNLROIRect oldLeftROI{};
|
||||||
|
SVzNLROIRect oldRightROI{};
|
||||||
|
int ret = VzNL_GetConfigDetectROI(m_deviceHandle, &oldLeftROI, &oldRightROI);
|
||||||
|
if (ret != 0) {
|
||||||
|
char errorMsg[256] = {0};
|
||||||
|
VzNL_GetErrorInfo(ret, errorMsg);
|
||||||
|
LOG_ERROR("[VizumCamera] Full-frame capture cannot read detection ROI: {} "
|
||||||
|
"(error code: {})", errorMsg, ret);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
SVzVideoResolution resolution{};
|
||||||
|
ret = VzNL_GetResolution(m_deviceHandle, &resolution);
|
||||||
|
if (ret != 0 || resolution.nFrameWidth == 0 || resolution.nFrameHeight == 0) {
|
||||||
|
char errorMsg[256] = {0};
|
||||||
|
VzNL_GetErrorInfo(ret, errorMsg);
|
||||||
|
LOG_ERROR("[VizumCamera] Full-frame capture cannot read device resolution: {} "
|
||||||
|
"(error code: {}, size={}x{})", errorMsg, ret,
|
||||||
|
resolution.nFrameWidth, resolution.nFrameHeight);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
DetectRoiRestoreGuard restoreGuard(m_deviceHandle, oldLeftROI, oldRightROI);
|
||||||
|
const SVzNLROIRect fullLeftROI{0, static_cast<int>(resolution.nFrameWidth),
|
||||||
|
0, static_cast<int>(resolution.nFrameHeight)};
|
||||||
|
const SVzNLROIRect fullRightROI = fullLeftROI;
|
||||||
|
ret = VzNL_ConfigDetectROI(m_deviceHandle, &fullLeftROI, &fullRightROI);
|
||||||
|
if (ret != 0) {
|
||||||
|
char errorMsg[256] = {0};
|
||||||
|
VzNL_GetErrorInfo(ret, errorMsg);
|
||||||
|
LOG_ERROR("[VizumCamera] Failed to apply temporary full-frame ROI: {} "
|
||||||
|
"(error code: {}, size={}x{})", errorMsg, ret,
|
||||||
|
resolution.nFrameWidth, resolution.nFrameHeight);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LOG_INFO("[VizumCamera] Temporary full-frame ROI applied: {}x{}; CalibROI unchanged",
|
||||||
|
resolution.nFrameWidth, resolution.nFrameHeight);
|
||||||
|
|
||||||
|
SVzNLImageData* leftImage = nullptr;
|
||||||
|
SVzNLImageData* rightImage = nullptr;
|
||||||
|
ret = VzNL_GetEyeImage(m_deviceHandle, &leftImage, &rightImage, 3000);
|
||||||
|
bool converted = false;
|
||||||
|
if (ret == 0 && leftImage) {
|
||||||
|
converted = ConvertVzImageToSLImage(leftImage, image);
|
||||||
|
LOG_INFO("[VizumCamera] Full-frame SDK image received: size={}x{}, origin=({}, {})",
|
||||||
|
leftImage->nWidth, leftImage->nHeight,
|
||||||
|
leftImage->ptOriPos.x, leftImage->ptOriPos.y);
|
||||||
|
} else {
|
||||||
|
char errorMsg[256] = {0};
|
||||||
|
VzNL_GetErrorInfo(ret, errorMsg);
|
||||||
|
LOG_ERROR("[VizumCamera] Full-frame image acquisition failed: {} (error code: {})",
|
||||||
|
errorMsg, ret);
|
||||||
|
}
|
||||||
|
if (leftImage)
|
||||||
|
VzNL_ReleaseImage(&leftImage);
|
||||||
|
if (rightImage)
|
||||||
|
VzNL_ReleaseImage(&rightImage);
|
||||||
|
|
||||||
|
const bool normalized = converted
|
||||||
|
&& NormalizeToDeviceFrame(image, resolution.nFrameWidth, resolution.nFrameHeight);
|
||||||
|
if (converted && !normalized) {
|
||||||
|
LOG_ERROR("[VizumCamera] SDK full-frame image cannot be placed in device frame: "
|
||||||
|
"image={}x{} origin=({}, {}), device={}x{}",
|
||||||
|
image.width, image.height, image.originX, image.originY,
|
||||||
|
resolution.nFrameWidth, resolution.nFrameHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool restored = restoreGuard.RestoreNow();
|
||||||
|
if (!normalized || !restored) {
|
||||||
|
image.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint64_t id = ++m_frameCounter;
|
||||||
|
frameId = "VZ_FULL_" + std::to_string(id);
|
||||||
|
LOG_INFO("[VizumCamera] Full-frame capture completed and ROI restored: frameId={}, "
|
||||||
|
"output={}x{} origin=(0, 0)", frameId, image.width, image.height);
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int timeoutMs)
|
bool VizumCamera::CapturePointCloudWithAutoDetect(PointCloud& pointCloud, int timeoutMs)
|
||||||
{
|
{
|
||||||
LOG_INFO("[VizumCamera] CapturePointCloudWithAutoDetect called, timeoutMs={}", timeoutMs);
|
LOG_INFO("[VizumCamera] CapturePointCloudWithAutoDetect called, timeoutMs={}", timeoutMs);
|
||||||
|
|||||||
@ -127,6 +127,15 @@ public:
|
|||||||
*/
|
*/
|
||||||
bool GetRightImage(SLImage& image);
|
bool GetRightImage(SLImage& image);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 采集全幅左目图像并在返回前恢复原检测 ROI
|
||||||
|
* @param[out] image 原点归一到(0,0)的设备全分辨率图像
|
||||||
|
* @param[out] frameId 本次采集帧编号
|
||||||
|
* @return 采集、全幅归一化及左右检测 ROI 恢复是否全部成功
|
||||||
|
* @note 保持当前 CalibROI 状态不变;任何失败路径都会尝试恢复原左右 ROI
|
||||||
|
*/
|
||||||
|
bool CaptureFullFrameLeftImage(SLImage& image, std::string& frameId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief 启用/禁用矫正 ROI 图像输出(VzNL_EnableCalibROI)
|
* @brief 启用/禁用矫正 ROI 图像输出(VzNL_EnableCalibROI)
|
||||||
* @param enable true=启用;启用后 GetLeftImage/GetRightImage 返回 SDK 矫正图
|
* @param enable true=启用;启用后 GetLeftImage/GetRightImage 返回 SDK 矫正图
|
||||||
|
|||||||
@ -132,6 +132,8 @@ struct SLImage {
|
|||||||
uint32_t height = 0;
|
uint32_t height = 0;
|
||||||
int channels = 3;
|
int channels = 3;
|
||||||
int bitDepth = 8;
|
int bitDepth = 8;
|
||||||
|
int originX = 0; // SDK ROI image top-left in the full sensor frame
|
||||||
|
int originY = 0;
|
||||||
|
|
||||||
size_t size() const { return data.size(); }
|
size_t size() const { return data.size(); }
|
||||||
bool empty() const { return data.empty(); }
|
bool empty() const { return data.empty(); }
|
||||||
@ -142,6 +144,8 @@ struct SLImage {
|
|||||||
data.shrink_to_fit();
|
data.shrink_to_fit();
|
||||||
width = 0;
|
width = 0;
|
||||||
height = 0;
|
height = 0;
|
||||||
|
originX = 0;
|
||||||
|
originY = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user