SLMaster icon indicating copy to clipboard operation
SLMaster copied to clipboard

有关投影仪标定精度的问题

Open Raymonddhr opened this issue 1 year ago • 13 comments

在看了大佬的文章之前,我才用的就是4步相移法+格雷码的编码方法进行解码,其中条纹数量为16条,光机是DLP3010,分辨率为1280*720,相机的标定采用圆形标定板,得到的重投影误差大概在0.07左右,但是当我用横竖相位进行解码,转化为投影仪角度下的坐标时,也是采用opencv的标定程序,发现无论怎么标定,投影仪的标定重投影误差都在1点多个像素,这是为啥呢?请大佬指教 这个是我的投影图像: image image image image 其中一组位姿状态下的横竖相位图(绝对相位): Absolute_pha_h Absolute_pha_v

Raymonddhr avatar May 10 '24 15:05 Raymonddhr

这个是投影图像 1

Raymonddhr avatar May 10 '24 15:05 Raymonddhr

建议按流程检查以下选项:

  1. 将特征点的相位映射至投影仪坐标系下生成图像,烧录并重投影至标定板上,查看偏离现象
  2. 若有偏离,必然解相存在问题:检查周期像素是否为整数、相位是否从0开始、解相以及相位映射部分程序是否存在问题

Practice3DVision avatar May 11 '24 00:05 Practice3DVision

我把投影的条纹图拿去解码试了下,发现竖向条纹解码的时候,相位不是从0开始的,好像是因为有这个问题,竖向分辨率是720,如果投影格雷码的话,第五张格雷码的范围是720/32=22.5,这就导致了刚开始半条黑的条纹是22.5的像素范围,这个没办法制作出这种图像,我把他变成23了,这个会不会有影响,因为横向格雷码没这个问题,1280/32=40

Raymonddhr avatar May 11 '24 06:05 Raymonddhr

解出来的绝对相位一定是从零开始的吗,我看了下我解出来的理论相位, image image 我的相位最小值是-0.00393707000000000,这个是解绝对相位出问题了吗

Raymonddhr avatar May 11 '24 06:05 Raymonddhr

得到原因是我解绝对相位出了点问题,但是当我修复了问题之后,重新标定,投影仪的标定重投影误差还是有0.9个像素,这是为啥呢

Raymonddhr avatar May 11 '24 12:05 Raymonddhr

这个是转换后的投影仪视角图: circle_image 这个是相机采集到的图像: cicle12 能帮忙看看是哪里还有问题吗,因为转化过来时亚像素坐标,我在投影仪视角图上是四舍五入

Raymonddhr avatar May 11 '24 12:05 Raymonddhr

问了下光机的厂商,没办法投影上述图像,所以我将每个圆心的横坐标形成条纹投影出来,如下所示: 4E6$YB$QQ7}2AMDI41{23S_tmb 大佬麻烦帮忙看看问题所在

Raymonddhr avatar May 11 '24 12:05 Raymonddhr

利用转换的坐标点进行matlab的投影仪标定,结果如下:可以看到重投影误差在0.8个像素,还是达不到使用的精度啊 image

Raymonddhr avatar May 11 '24 14:05 Raymonddhr

博主,想问下你在检测完圆心之后,圆心的坐标值是亚像素级别,你有做什么处理之后再转换到投影仪坐标下吗

Raymonddhr avatar May 12 '24 01:05 Raymonddhr

你可以考虑增加相移步数并做线性插值尝试。此外,你给的投影图片不知道是哪些点,请自行检阅。一般至少能够达到0.2左右精度。

自己查看源码吧,都是开源的:[code]: https://github.com/Practice3DVision/SLMaster/blob/d4590ec7e627e82b700d720f592618105b17c821/gui/src/CalibrateEngine.cpp#L815C1-L870C2

CalibrateEngine::remapProjectorPoint(const cv::Mat &honrizonPhaseMap,
                                     const cv::Mat &verticalPhaseMap,
                                     const cv::Point2f &camPoint) {
#ifdef LinearInter
    int index_Y_Upper = std::ceil(camPoint.y);
    int index_Y_Lower = std::floor(camPoint.y);
    int index_X_Upper = std::ceil(camPoint.x);
    int index_X_Lower = std::floor(camPoint.x);
    const float vPLU =
        verticalPhaseMap.ptr<float>(index_Y_Upper)[index_X_Lower];
    const float vPRU =
        verticalPhaseMap.ptr<float>(index_Y_Upper)[index_X_Upper];
    const float vPLD =
        verticalPhaseMap.ptr<float>(index_Y_Lower)[index_X_Lower];
    const float vPRD =
        verticalPhaseMap.ptr<float>(index_Y_Lower)[index_X_Upper];
    const float tPLU =
        honrizonPhaseMap.ptr<float>(index_Y_Upper)[index_X_Lower];
    const float tPRU =
        honrizonPhaseMap.ptr<float>(index_Y_Upper)[index_X_Upper];
    const float tPLD =
        honrizonPhaseMap.ptr<float>(index_Y_Lower)[index_X_Lower];
    const float tPRD =
        honrizonPhaseMap.ptr<float>(index_Y_Lower)[index_X_Upper];
    const float vfR1 =
        (index_X_Upper - camPoint.x) / (index_X_Upper - index_X_Lower) * vPLD +
        (camPoint.x - index_X_Lower) / (index_X_Upper - index_X_Lower) * vPRD;
    const float vfR2 =
        (index_X_Upper - camPoint.x) / (index_X_Upper - index_X_Lower) * vPLU +
        (camPoint.x - index_X_Lower) / (index_X_Upper - index_X_Lower) * vPRU;
    const float tfR1 =
        (index_X_Upper - camPoint.x) / (index_X_Upper - index_X_Lower) * tPLD +
        (camPoint.x - index_X_Lower) / (index_X_Upper - index_X_Lower) * tPRD;
    const float tfR2 =
        (index_X_Upper - camPoint.x) / (index_X_Upper - index_X_Lower) * tPLU +
        (camPoint.x - index_X_Lower) / (index_X_Upper - index_X_Lower) * tPRU;
    const float verticalPhaseValue =
        (index_Y_Upper - camPoint.y) / (index_Y_Upper - index_Y_Lower) * vfR1 +
        (camPoint.y - index_Y_Lower) / (index_Y_Upper - index_Y_Lower) * vfR2;
    const float transversePhaseValue =
        (index_Y_Upper - camPoint.y) / (index_Y_Upper - index_Y_Lower) * tfR1 +
        (camPoint.y - index_Y_Lower) / (index_Y_Upper - index_Y_Lower) * tfR2;
#else
    int index_Y = std::round(camPoint.y);
    int index_X = std::round(camPoint.x);
    const float verticalPhaseValue =
        verticalPhaseMap.ptr<float>(index_Y)[index_X];
    const float transversePhaseValue =
        honrizonPhaseMap.ptr<float>(index_Y)[index_X];
#endif
    const float xLocation =
        (verticalPhaseValue) / CV_2PI * projectorCaliParams_.verticalPitch_;
    const float yLocation =
        (transversePhaseValue) / CV_2PI * projectorCaliParams_.honrizonPitch_;
    return cv::Point2f(xLocation, yLocation);
}

Practice3DVision avatar May 12 '24 02:05 Practice3DVision

相对相位是能够满足0和2pi都取到的吗 0aae69944e1aa7fafdf77e9ab8e5c51 我这个最大相位离2pi还有点距离

Raymonddhr avatar May 12 '24 02:05 Raymonddhr

简言之,就是0-2pi这个包裹相位的范围是左闭右开的吧,还是说左右都是闭区间?

Raymonddhr avatar May 12 '24 03:05 Raymonddhr

而且你说的插值方法我早就用到过了,不就是双线性插值嘛,如下是我的投影图像,以及检测到的圆心,还有转换到光机下的圆心位置图像: 投影仪.zip 相机检测.zip

Raymonddhr avatar May 12 '24 05:05 Raymonddhr