Axa*_*diw 20 camera opencv markers camera-calibration ios
我有使用OpenCV精确检测标记的问题.
我录制了这个问题的视频:http://youtu.be/IeSSW4MdyfU
如你所见,我正在检测的标记在某些摄像机角度稍微移动.我在网上看到这可能是相机校准问题,所以我会告诉你们我是如何校准相机的,也许你能告诉我我做错了什么?
在开始时我正在从各种图像中收集数据,并将校准角存储在这样的_imagePoints矢量中
std::vector<cv::Point2f> corners;
_imageSize = cvSize(image->size().width, image->size().height);
bool found = cv::findChessboardCorners(*image, _patternSize, corners);
if (found) {
cv::Mat *gray_image = new cv::Mat(image->size().height, image->size().width, CV_8UC1);
cv::cvtColor(*image, *gray_image, CV_RGB2GRAY);
cv::cornerSubPix(*gray_image, corners, cvSize(11, 11), cvSize(-1, -1), cvTermCriteria(CV_TERMCRIT_EPS+ CV_TERMCRIT_ITER, 30, 0.1));
cv::drawChessboardCorners(*image, _patternSize, corners, found);
}
_imagePoints->push_back(_corners);
Run Code Online (Sandbox Code Playgroud)
收集到足够的数据后,我用这段代码计算相机矩阵和系数:
std::vector< std::vector<cv::Point3f> > *objectPoints = new std::vector< std::vector< cv::Point3f> >();
for (unsigned long i = 0; i < _imagePoints->size(); i++) {
std::vector<cv::Point2f> currentImagePoints = _imagePoints->at(i);
std::vector<cv::Point3f> currentObjectPoints;
for (int j = 0; j < currentImagePoints.size(); j++) {
cv::Point3f newPoint = cv::Point3f(j % _patternSize.width, j / _patternSize.width, 0);
currentObjectPoints.push_back(newPoint);
}
objectPoints->push_back(currentObjectPoints);
}
std::vector<cv::Mat> rvecs, tvecs;
static CGSize size = CGSizeMake(_imageSize.width, _imageSize.height);
cv::Mat cameraMatrix = [_userDefaultsManager cameraMatrixwithCurrentResolution:size]; // previously detected matrix
cv::Mat coeffs = _userDefaultsManager.distCoeffs; // previously detected coeffs
cv::calibrateCamera(*objectPoints, *_imagePoints, _imageSize, cameraMatrix, coeffs, rvecs, tvecs);
Run Code Online (Sandbox Code Playgroud)
结果就像你在视频中看到的那样.
我究竟做错了什么?这是代码中的问题吗?我应该使用多少图像来执行校准(此时我正在尝试在校准结束前获得20-30张图像).
我应该使用包含错误检测到的棋盘角落的图像,如下所示:

或者我应该只使用正确检测到的棋盘,如下所示:

我一直在尝试使用圆形网格而不是棋盘,但现在结果要糟糕得多.
如有问题我如何检测标记:我正在使用solvepnp功能:
solvePnP(modelPoints, imagePoints, [_arEngine currentCameraMatrix], _userDefaultsManager.distCoeffs, rvec, tvec);
Run Code Online (Sandbox Code Playgroud)
使用如下指定的modelPoints:
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, -kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
markerPoints3D.push_back(cv::Point3d(-kMarkerRealSize / 2.0f, kMarkerRealSize / 2.0f, 0));
Run Code Online (Sandbox Code Playgroud)
并且imagePoints是处理图像中标记角的坐标(我使用自定义算法来做到这一点)
为了正确调试您的问题,我需要所有代码:-)
我假设您正在按照@kobejohn在其评论中引用的教程(校准和位姿)中建议的方法进行操作,以便您的代码遵循以下步骤:
cv::calibrateCamera),并因此获得相机的固有参数(称为intrinsic)和镜头畸变参数(称为distortion)。
并在其中找到一些相关点(我们将您在图像中找到的点image_custom_target_vertices和world_custom_target_vertices相应的3D点称为调用点)。R)和平移矢量(称为t),并调用cv::solvePnP类似的方法cv::solvePnP(world_custom_target_vertices,image_custom_target_vertices,intrinsic,distortion,R,t) world_cube_vertices),你得到8个2D图像点(我们称它们image_cube_vertices)通过调用的方式cv2::projectPoints像这样的cv::projectPoints(world_cube_vertices,R,t,intrinsic,distortion,image_cube_vertices)draw功能绘制立方体。现在,绘制过程的最终结果取决于所有先前计算的数据,我们必须找到问题所在:
校准:如您在答案中观察到的那样,在3)中,应丢弃未正确检测到拐角的图像。您需要重新投影误差的阈值才能丢弃“不良”的棋盘目标图像。引用校准教程:
重投影误差
重投影误差可以很好地估计找到的参数的精确度。该值应尽可能接近零。给定固有,失真,旋转和平移矩阵,我们首先使用cv2.projectPoints()将对象点转换为图像点。然后,我们计算在变换中得到的绝对值与拐角发现算法之间的绝对值。为了找到平均误差,我们计算了所有校准图像的误差的算术平均值。
通常,您可以通过一些实验找到合适的阈值。有了这个额外的步骤,你将得到更好的值intrinsic和distortion。
找到您自己的自定义目标:在我看来,您似乎没有解释如何在我标记为第4点的步骤中找到自己的自定义目标。你得到期望了image_custom_target_vertices吗?您会丢弃结果为“不良”的图像吗?
相机的姿势:我认为在5)中使用的intrinsic是3)中的内容,您确定同时相机没有任何变化吗?参考Callari的摄像机校准第二规则:
相机校准的第二条规则:“校准后,请勿触摸镜头”。特别是,您可能无法重新对焦或更改光圈值,因为对焦和光圈都会影响非线性镜头失真,并且(视情况而定,视镜头而定)会影响非线性。当然,您完全可以自由更改曝光时间,因为它根本不影响镜头的几何形状。
然后draw功能可能会出现一些问题。
因此,我对我的代码进行了很多实验,但仍然没有解决主要问题(移动对象),但我已经设法回答了我提出的一些校准问题。
首先 - 为了获得良好的校准结果,您必须使用具有正确检测到的网格元素/圆圈位置的图像!。在校准过程中使用所有捕获的图像(即使是那些未正确检测到的图像)将导致校准不良。
我尝试过各种校准模式:
CALIB_CB_ASYMMETRIC_GRID) 的结果比任何其他图案都要差得多。我所说的更糟糕的结果是指它会产生很多错误检测到的角点,如下所示:

我已经尝试过,CALIB_CB_CLUSTERING但并没有多大帮助 - 在某些情况下(不同的光照环境)它变得更好,但效果并不明显。
CALIB_CB_SYMMETRIC_GRID) - 比不对称网格更好的结果,但仍然比标准网格(棋盘)差得多。它经常会产生如下错误:
findChessboardCorners) - 此方法产生最好的可能结果 - 它不会经常产生未对齐的角,并且几乎每次校准都会产生与对称圆网格的最佳可能结果类似的结果对于每次校准,我都会使用 20-30 张来自不同角度的图像。我尝试过使用 100 多张图像,但与少量图像相比,它在校准结果方面并没有产生明显的变化。值得注意的是,大量的测试图像会增加以非线性方式计算相机参数所需的时间(100 张 480x360 分辨率的测试图像在 iPad4 中计算需要 25 分钟,而约 50 张图像则需要 4 分钟)
我也尝试过solvePNP参数 - 但也没有给我任何可接受的结果:我已经尝试了所有 3 种检测方法(ITERATIVE、EPNP和P3P),但我还没有看到明显的变化。
我还尝试过useExtrinsicGuessset to true,并且我已经使用了rvec和tvec来自之前的检测,但这导致检测到的立方体完全消失。
我已经没有想法了——还有什么可能影响这些不断变化的问题呢?
| 归档时间: |
|
| 查看次数: |
6467 次 |
| 最近记录: |