前几天同事突然问我九点标定的几个函数名称,然后我才想起来还有这个重要的技能没有说,因此本篇会详细介绍一下九点标定法。(九点:指有序排列的九个特征点,一般为圆点或者十字)
九点标定的作用:
1.求解x和y方向的分辨率
2.求解图像坐标到xx坐标的仿射变换矩阵
(PS:关于仿射变换和透视变换的一般理解,仿射变换:一个矩形到另一个矩形的变换过程,透视变换:一个矩形到另一个不规则矩形的变换过程(不规则可以理解为有些边或者其他地方不是直线))
准备工作:九点标定板(3x3,已知行距,列距)。在相机视野范围内,让九点中某个点和XX坐标系的某个点重合,也就是九点在xx坐标系的坐标,是已知的
一、分辨率求解
经过图像处理,我们可以得到九个点的图像上的坐标,然后按照从左到右,从上到下的规律拍好,利用这些点去计算分辨率,大概的程序思路如下
//pt:点集;hj:行距;lj:列距
bool CvGetClibrateData(CvPoint *pt, double hj, double lj, double &dx, double &dy)
{
//pt的排列原则从左到右,从上到下,可以使用sort函数排序
//具体的sort就不写了,感兴趣的同学自己研究一下,在这里我默认他排好序了
//pt的排序结果
// 0 1 2
// 3 4 5
// 6 7 8
//因此接下来的求解方法全是数学问题
//x方向分辨率
dx = (pt[1].x - pt[0].x) + (pt[2].x - pt[1].x);
dx += (pt[4].x - pt[3].x) + (pt[5].x - pt[4].x);
dx += (pt[7].x - pt[6].x) + (pt[8].x - pt[7].x);
dx = dx / (6 * lj);
//y方向分辨率
dy = (pt[3].y - pt[0].y) + (pt[6].y - pt[3].y);
dy += (pt[4].y - pt[1].y) + (pt[7].y - pt[4].y);
dy += (pt[5].y - pt[2].y) + (pt[8].y - pt[5].y);
dy = dy / (6 * hj);
return ture;
}
二、仿射矩阵
从一个坐标系到另一个坐标系的变换,通常使用仿射矩阵。,我使用的是已经二次封装好的,但是没有源码,因此只能用OpenCv中的某些函数说明。
首先
CvMat* cvGetAffineTransform( const CvPoint2D32f* src,const CvPoint2D32f* dst, CvMat* map_matrix );
src:输入图像的三角形顶点坐标。
dst:输出图像的相应的三角形顶点坐标。
map_matrix:指向2×3输出矩阵的指针。
这个函数就是已知图像上三点坐标,和XX坐标系中对应的三点坐标,然后求解一个变化的矩阵。
得到这个矩阵之后,可以根据已知的图像点推算对应XX坐标系上的对应的的坐标(相关变换函数暂时没找到,用的是已经封装好的看不到源码,以后再加)
给出大致的思路,用cvGetAffineTransform或者cv2DRotationMatrix求解出矩阵(2x3的)
然后它的排列大概是下面这样
然后,对应坐标求解,大概是下面这样
2019/4/28更新内容,添加一个变化的代码
void GetTransPt(Point src, Mat trans, Point &dst)
{
if (trans.empty())
{
return;
}
int n=trans.channels();
Point2f p = Point2f(0, 0);
dst.x = trans.ptr<double>(0)[0] * src.x + trans.ptr<double>(0)[1] * src.y + trans.ptr<double>(0)[2];
dst.y = trans.ptr<double>(1)[0] * src.x + trans.ptr<double>(1)[1] * src.y + trans.ptr<double>(1)[2];
}