From 8fef95463940f1440570758b41cdb869c32d1f5c Mon Sep 17 00:00:00 2001 From: Walter Perdan Date: Sat, 6 Jun 2026 13:53:44 +0200 Subject: [PATCH] Add WebARKitCamera::loadCameraParamFromBuffer (camera_para.dat / ARParam) Load real camera calibration from an ArtoolkitX camera_para.dat buffer instead of the synthetic 70-degree-FOV defaults: - WebARKitCamera::loadCameraParamFromBuffer: arParamLoadFromBuffer -> arParamChangeSize(w,h) -> fill intrinsic matrix (K = first 3 columns of the calibrated 3x4 mat) and distortion (v4: k1,k2,p1,p2,k3=0; v5: copied direct). - WebARKitTracker::loadCameraParam: refresh m_camMatrix, m_distortionCoeff and the GL projection (m_cameraProjectionMatrix) from the loaded ARParam. Verified end-to-end downstream: the projection changes to the real calibration (fx/fy + non-zero principal-point offset) and tracking is unaffected. Refs: webarkit/WebARKitLib#35 Co-Authored-By: Claude Opus 4.8 --- WebARKit/WebARKitCamera.cpp | 53 +++++++++++++++++++ .../WebARKitTracker.cpp | 29 ++++++++++ .../WebARKitOpticalTracking/WebARKitTracker.h | 3 ++ WebARKit/include/WebARKitCamera.h | 5 ++ 4 files changed, 90 insertions(+) diff --git a/WebARKit/WebARKitCamera.cpp b/WebARKit/WebARKitCamera.cpp index 98b4006..75e177c 100644 --- a/WebARKit/WebARKitCamera.cpp +++ b/WebARKit/WebARKitCamera.cpp @@ -1,12 +1,65 @@ #include #include #include +// Use the umbrella (not directly): ar.h includes param.h +// in the correct order so ARParam/ARParamLT are defined before ar.h uses them. +// It transitively declares arParamLoadFromBuffer / arParamChangeSize. +#include +#include namespace webarkit { WebARKitCamera::WebARKitCamera() : xsize(-1), ysize(-1), diagonal_fov_degrees(70.0) { cmat.fill(0.0); } WebARKitCamera::~WebARKitCamera() {} +bool WebARKitCamera::loadCameraParamFromBuffer(const void* buffer, int size, int width, int height) { + if (!buffer || size <= 0 || width <= 0 || height <= 0) { + return false; + } + ARParam param, scaled; + if (arParamLoadFromBuffer(buffer, (size_t)size, ¶m) < 0) { + WEBARKIT_LOGe("loadCameraParamFromBuffer: not a valid camera_para.dat buffer.\n"); + return false; + } + if (arParamChangeSize(¶m, width, height, &scaled) < 0) { + WEBARKIT_LOGe("loadCameraParamFromBuffer: arParamChangeSize failed.\n"); + return false; + } + + xsize = width; + ysize = height; + + // Intrinsic matrix K = first 3 columns of the calibrated 3x4 projection + // matrix (the 4th column is the projection offset, ~0 for a pinhole). + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + cmat.at(i * 3 + j) = (double)scaled.mat[i][j]; + } + } + focal_length = cmat.at(0); + + // Distortion -> OpenCV distCoeffs (k1,k2,p1,p2[,k3,...]). + // This vendored lib is v4-era (AR_DIST_FACTOR_NUM_MAX = 9). For v4, the + // OpenCV-compatible coefficients are dist_factor[0..3] with k3 = 0 (matching + // ArtoolkitX OCVT). A future v5 (.dat with OpenCV rational model) would copy + // dist_factor directly. + // TODO: verify the v4 ArtoolkitX -> OpenCV distortion mapping against a real + // camera_para.dat before relying on distortion (intrinsics are the main win). + kc.fill(0.0); + if (scaled.dist_function_version >= 5) { + for (int i = 0; i < 6 && i < AR_DIST_FACTOR_NUM_MAX; ++i) { + kc.at(i) = (double)scaled.dist_factor[i]; + } + } else { + kc.at(0) = (double)scaled.dist_factor[0]; // k1 + kc.at(1) = (double)scaled.dist_factor[1]; // k2 + kc.at(2) = (double)scaled.dist_factor[2]; // p1 + kc.at(3) = (double)scaled.dist_factor[3]; // p2 + kc.at(4) = 0.0; // k3 + } + return true; +} + bool WebARKitCamera::setupCamera(int width, int height) { if (width <= 0 || height <= 0) { return false; diff --git a/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.cpp b/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.cpp index aa5f1bb..365fedc 100644 --- a/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.cpp +++ b/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.cpp @@ -190,6 +190,31 @@ class WebARKitTracker::WebARKitTrackerImpl { std::array getCameraProjectionMatrix() { return m_cameraProjectionMatrix; }; + // Override the synthetic FOV-based camera with a real ArtoolkitX + // camera_para.dat (ARParam) buffer, then refresh the intrinsic matrix, + // distortion coefficients and GL projection. Call after initialize() and + // before reading getCameraProjectionMatrix(). + bool loadCameraParam(const void* buffer, int size) { + if (!_camera->loadCameraParamFromBuffer(buffer, size, _frameSizeX, _frameSizeY)) { + WEBARKIT_LOGe("loadCameraParam: failed to load camera_para buffer.\n"); + return false; + } + std::array camData = _camera->getCameraData(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 3; ++j) { + m_camMatrix(i, j) = camData[i * 3 + j]; + } + } + std::array dist = _camera->getDistortionCoefficients(); + m_distortionCoeff = cv::Mat::zeros(5, 1, cv::DataType::type); + for (int i = 0; i < 5; ++i) { + m_distortionCoeff.at(i, 0) = dist[i]; + } + webarkit::cameraProjectionMatrix(camData, 0.1, 1000.0, _frameSizeX, _frameSizeY, m_cameraProjectionMatrix); + WEBARKIT_LOGi("Loaded real camera calibration from camera_para.dat.\n"); + return true; + } + bool isValid() { return _valid; }; protected: @@ -832,6 +857,10 @@ std::array WebARKitTracker::getCameraProjectionMatrix() { return _trackerImpl->getCameraProjectionMatrix(); } +bool WebARKitTracker::loadCameraParam(const void* buffer, int size) { + return _trackerImpl->loadCameraParam(buffer, size); +} + bool WebARKitTracker::isValid() { return _trackerImpl->isValid(); } } // namespace webarkit \ No newline at end of file diff --git a/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/include/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.h b/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/include/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.h index 6494877..c1c172b 100644 --- a/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/include/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.h +++ b/WebARKit/WebARKitTrackers/WebARKitOpticalTracking/include/WebARKitTrackers/WebARKitOpticalTracking/WebARKitTracker.h @@ -41,6 +41,9 @@ class WebARKitTracker { std::array getCameraProjectionMatrix(); + // Load real camera calibration from an ArtoolkitX camera_para.dat buffer. + bool loadCameraParam(const void* buffer, int size); + bool isValid(); private: diff --git a/WebARKit/include/WebARKitCamera.h b/WebARKit/include/WebARKitCamera.h index 33b65f6..01ee528 100644 --- a/WebARKit/include/WebARKitCamera.h +++ b/WebARKit/include/WebARKitCamera.h @@ -11,6 +11,11 @@ class WebARKitCamera { bool setupCamera(int width, int height); + // Load real camera calibration from an ArtoolkitX camera_para.dat buffer + // (ARParam), rescaled to width x height. Fills the intrinsic matrix and + // distortion from the file instead of the synthetic FOV-based defaults. + bool loadCameraParamFromBuffer(const void* buffer, int size, int width, int height); + void printSettings(); std::array getCameraData() const;