因为一些扯淡的原因,需要得到畸变校正后图像像素和校正前图像的像素的一一对应关系。这个扯淡的原因当然是优化老版本的算法但是又不能乱改接口。
正文
这篇博文有一点介绍但是不太符合我的期望,所以我想到了一种方法可以尝试一下(其实这种方法在别的地方早就用过的):构造一个和原图一样大小的双通道图像,图像通道内的值分别是该点的坐标。然后和原图进行一样的坐标变化,尽量不改变坐标内的值,比如遇到 cv::INTER_LINEAR尽量改成最近邻差值(其实用线性插值也没什么影响,个人感觉最近邻插值更好点,当然只是感觉。这种感觉估计还不对。反正差的话也就是1个像素以内)然后可以得到:(还挺好看)
这样的一张图,放大看:
对应的像素,这时候只要和原图进行一样的坐标变换,就可以通过它知道原图每个像素分别跑到哪里去了。于是乎:
cv::Mat posLeft(SJ_Left.size(), CV_32SC2, cv::Scalar::all(0)), posLeft_Homo, posRght;
for (int i = 0; i < SJ_Left.rows; i++) {
for (int j = 0; j < SJ_Left.cols; j++) {
posLeft.at<cv::Vec2i>(i, j)[0] = i; //y
posLeft.at<cv::Vec2i>(i, j)[1] = j; //x
}
}
cv::split(posLeft, channels);
posRght = posLeft.clone();
cv::undistort(posLeft, posLeft, intrinsic_matrix1, distortion_coeffs1);
定位到cv::undistort()源码, 试试单通道:
把源码抠出来,发现两个地方出问题:
感兴趣的同学自己去看源码,这里不深入搞了,线上在催,我没空写了,直接扔出来解决方案:删了多余的,改数据类型:
把用来做定位的图换成:CV_32FC2就搞定了,但是: 这么做好像还不对
因为我按照像素找几个亮点去找对应检验时候发现是不对的,十有八九是remap时候在线性插值整的两个通道数据混了。 这里码一下,这个问题我没深究,所以我在文章开头说了推荐最近邻插值,不用线性插值,谁知道源码里面在算映射灰度时候对双通道图像用的是什么规则做的映射,这里最近邻插值只要改一下remap的参数就行。 但是好像也不是那么准,我用的方法:分离两个通道分别做映射:(而且用的undistort)
放大看:
对比就知道,第一通道就是变换后对应的灰度值,后两个通道就是该像素在原图的坐标。
搞定收工。