调用cv::aruco::estimatePoseCharucoBoard触发channels断言失败问题求助
问题分析与解决方案
核心问题定位
断言失败channels() == CV_MAT_CN(dtype)本质是矩阵通道数与数据类型不匹配,但你已确认灰度图(CV_8UC1)符合要求,问题不在输入图像,而是两处关键错误触发了看似无关的内存断言:
- 内参矩阵赋值完全颠倒,导致相机参数错误
estimatePoseCharucoBoard返回单元素姿态数组,你却用多元素的标记ID数组遍历,引发内存越界
修复步骤
1. 修正内参矩阵赋值
iOS的matrix_float3x3是列优先存储,原代码错误地将列向量按行赋值,正确逻辑:
cv::Mat intrinMat(3,3,CV_64F); // 对应内参矩阵:[fx, 0, cx; 0, fy, cy; 0, 0, 1] intrinMat.at<Float64>(0,0) = intrinsics.columns[0][0]; // fx intrinMat.at<Float64>(0,1) = intrinsics.columns[1][0]; // 0 intrinMat.at<Float64>(0,2) = intrinsics.columns[2][0]; // cx intrinMat.at<Float64>(1,0) = intrinsics.columns[0][1]; // 0 intrinMat.at<Float64>(1,1) = intrinsics.columns[1][1]; // fy intrinMat.at<Float64>(1,2) = intrinsics.columns[2][1]; // cy intrinMat.at<Float64>(2,0) = intrinsics.columns[0][2]; // 0 intrinMat.at<Float64>(2,1) = intrinsics.columns[1][2]; // 0 intrinMat.at<Float64>(2,2) = intrinsics.columns[2][2]; // 1
2. 修正姿态遍历逻辑
estimatePoseCharucoBoard返回整个Charuco板的单个姿态,而非每个标记的姿态,需区分两种场景处理:
if(charucoIds.size() > 0) { cv::aruco::estimatePoseCharucoBoard(charucoCorners, charucoIds, charucoBoard, intrinMat, distCoeffs, rvecs, tvecs); // Charuco板仅一个姿态,用特殊ID标记 if(!rvecs.empty()){ cv::Rodrigues(rvecs[0], rotMat); cv::Mat extrinsics = rotateRodriques(rotMat, tvecs[0]); SCNMatrix4 scnMatrix = [ArucoCV transformToSceneKitMatrix:extrinsics]; SKWorldTransform *transform = [SKWorldTransform new]; transform.arucoId = -1; // 标记为Charuco板 transform.transform = scnMatrix; [arrayMatrix addObject:transform]; } } else { cv::aruco::estimatePoseSingleMarkers(corners, markerSize, intrinMat, distCoeffs, rvecs, tvecs); // 单个标记姿态遍历,此处用ids[i]才正确 for (int i = 0; i < rvecs.size(); i++) { cv::Rodrigues(rvecs[i], rotMat); cv::Mat extrinsics = rotateRodriques(rotMat, tvecs[i]); SCNMatrix4 scnMatrix = [ArucoCV transformToSceneKitMatrix:extrinsics]; SKWorldTransform *transform = [SKWorldTransform new]; transform.arucoId = ids[i]; transform.transform = scnMatrix; [arrayMatrix addObject:transform]; } }
3. 调整畸变系数维度
若未专门标定8维畸变,改用OpenCV默认的5维参数:
cv::Mat distCoeffs = cv::Mat::zeros(5, 1, CV_64F);
4. 额外检查:确保输入为有效灰度图
若CVPixelBuffer不是kCVPixelFormatType_OneComponent8格式,需先转换为灰度图:
// 替换原greymat创建代码 void *baseaddress = CVPixelBufferGetBaseAddressOfPlane(pixelBuffer, 0); CGFloat width = CVPixelBufferGetWidth(pixelBuffer); CGFloat height = CVPixelBufferGetHeight(pixelBuffer); cv::Mat inputMat(height, width, CV_8UC4, baseaddress); cv::Mat greymat; cv::cvtColor(inputMat, greymat, cv::COLOR_BGRA2GRAY);
验证逻辑
修复后,检测到Charuco角点时返回单个板姿态,未检测到则返回单个标记姿态,避免数组越界引发的内存错误,从而解决断言失败问题。
内容的提问来源于stack exchange,提问作者geek
相关产品推荐
相关产品推荐

