分类 OpenCV_图像_视觉_算法 下的文章

测试背景:

     利用一块棋盘格标定板,和一个装在车辆驾驶室上方的单目相机,然后求解该单目相机离地面的高度以及姿态(相对理想水平面相机坐标系),

采集一张图片,分别用OpenCV的算法与Matlab的算法进行求解,并比较其结果.


一、 棋盘格角点检测比较(使能亚像素角点检测)

      matlab函数:

                        detectCheckerboardPoints()

      opencv函数:

                        cv::findChessboardCorners()和cv::cornerSubPix()


通过绘制角点比较,opencv检测的角点在远处误差较大,检测结果比Matlab要差:







二、PnP问题求解的精度比较

        将Matlab检测的棋盘格角点作为Matlab和OpenCV求解的PnP问题的输入源。通过结果比较,在同样的角点输入的前提下,OpenCV和Matlab对PnP问题的结果精度基本相同,误差很小。













三、棋盘格角点检测比较(关闭亚像素角点检测)

        如果OpenCV不添加亚像素角点检测,其角点检测精度反而更优:

        cv::TermCriteria criteria = cv::TermCriteria( cv::TermCriteria::EPS + cv::TermCriteria::COUNT, 40, 0.001 );

         cv::cornerSubPix(gray, image_points, cv::Size(11,11), cv::Size(-1,-1), criteria);






总结:

        (1): Matlab比OpenCV的求解精度更优,差异主要体现在棋盘格角点的检测更精准;

        (2): 但标定板离相机较远时,如果OpenCV开启亚像素角点检测优化(cv::cornerSubPix),其结果反而更差!!!

        (3): 当OpenCV关闭亚像素检测角点优化代码时,其最终的单目相机外参结果与Matlab的结果误差很小。



1、RGB转YUV

    float   R = (float)r;
    float   G = (float)g;
    float   B = (float)b;

    float   Y =  0.299*R + 0.587*G + 0.114*B;
    float   U = -0.169*R - 0.331*G + 0.5  *B + 128.0;

    float   V =  0.5  *R - 0.419*G - 0.081*B + 128.0;




void    Draw_Point_YUV420SP(cv::Mat &image, const cv::Point &pt, const Eigen::Vector3f &RGB)
{
    Eigen::Vector3f     YUV(0,0,0);
    const   Eigen::Vector3f     yuv_offset(0.0, 128.0, 128.0);
    int  W = image.cols;
    int  H = image.rows*2/3;
    if(pt.x<0||pt.x>=W || pt.y<0 || pt.y>=H)
        return;
    Eigen::Matrix3f     rgb2yuv;
    rgb2yuv<<0.299,0.587,0.114,-0.169,- 0.331,0.5,0.5,-0.419,-0.081;
    YUV = rgb2yuv*RGB;
    YUV += yuv_offset;
    YUV[0] = std::min(float(255.0), std::max(float(0.0), YUV[0]));
    YUV[1] = std::min(float(255.0), std::max(float(0.0), YUV[1]));
    YUV[2] = std::min(float(255.0), std::max(float(0.0), YUV[2]));
    unsigned char y=static_cast<unsigned char>(YUV[0]);
    unsigned char u=static_cast<unsigned char>(YUV[1]);
    unsigned char v=static_cast<unsigned char>(YUV[2]);

    unsigned char *pY = image.data;
    unsigned char *pUV = image.data + W*H;
    //计算YUV索引
    pY[pt.y*W+pt.x] = y;
    int  uv_id = (pt.y/2)*W + pt.x - pt.x%2; // UV的列和Y的列相同
    pUV[uv_id] = u;
    pUV[uv_id+1] = v;
    return;
}





2: YUV转RGB



    YUV420SP

         const unsigned char *pY = buf.data();
         const unsigned char *pUV = pY + width*height;
         cv::Mat  img = cv::Mat::zeros(height, width, CV_8UC3);
         for(int v=0; v<height; v++){   
             for(int u=0; u<width; u++){    
                 auto &BGR = img.at<cv::Vec3b>(v, u);
                 float Y = static_cast<float>(pY[v*width+u]);
                 int  vu_id = (v/2)*width + u - u%2;
                 float U = static_cast<float>(pUV[vu_id]);
                 float V = static_cast<float>(pUV[vu_id+1]);
                 float r = Y + 1.403*(V - 128);
                 float g = Y - 0.343*(U - 128) - 0.714*(V - 128);
                 float b = Y + 1.77*(U - 128);  
                 r = r<0.0?0.0:r;               
                 r = r>255.0?255:r;             
                 g = g<0.0?0.0:g;               
                 g = g>255.0?255:g;             
                 b = b<0.0?0.0:b;               
                 b = b>255.0?255:b;
                 BGR[0] = static_cast<unsigned char>(b);
                 BGR[1] = static_cast<unsigned char>(g);
                 BGR[2] = static_cast<unsigned char>(r);
             }
         }
         cv::imwrite("out.png", img);