如何利用c++ OpenCV实现从投影图像恢复仿射特性

  

如何利用C++ OpenCV 实现从投影图像恢复仿射特性,针对这个问题,这篇文章详细介绍了相对应的分析和解答,希望可以帮助更多想解决这个问题的小伙伴找到更简单易行的方法。

原理

我们通过相机拍摄的图片存在各种畸变,其中投影畸变使得原本平行的直线不再平行,就会产生照片中近大远小的效果,要校正这一畸变,书中给了很多方法,这里是其中的一种。

我们可以将投影变换拆分成相似变换、仿射变换和投影变换三部分, 如下图,

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

其中相似变换和仿射变换不会改变infinite line,只有投影变换会改变。因此只要找到畸变图像中的这条线,就能够恢复图像的仿射特性(相当于逆转投影变换)。而要确定这条线的位置,就得至少知道线上的两个点。我们知道,所有平行线的交点都在infinite line上面,因此,我们只需要找到图像上的两对平行线(原本是平行,图像上不再平行),求出对应的两个交点,就能找到infinite line了,如下图

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

进而可以图像的恢复仿射特性。

实现思路

首先我们的畸变图像如下图,

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

利用公式:

l = x1 × x2

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

可以通过x1、x2的齐次坐标求出两点连线l的齐次坐标。在图中我们找到两对平行线l1、l2和l3、l4,如下图

如何利用C++ OpenCV 实现从投影图像恢复仿射特性

利用公式:

x = l1 × l2

可以通过l1、l2以及l3、l4的齐次坐标分别求出两对平行线的交点A12、A34,直线A12A34就是我们要找的infinite line。假设该直线的齐次坐标为(l1,l2,l3),那么通过矩阵:

H = ((1,0,0),(0,1,0),(l1,l2,l3))

就能够将直线(l1,l2,l3)变换成(0,0,1),即将该直线还原成为infinite line。同理我们也可以利用H矩阵,通过公式:

x = Hx'

还原投影畸变。

主要代码

代码一共需要运行两次

第一次运行的主函数:

int main()
  {
  Mat  src =, imread (“distortion.jpg",, IMREAD_GRAYSCALE);
  IplImage  * src1 =, cvLoadImage (“distortion.jpg");//第一步,通过鼠标获取图片中某个点的坐标,运行第一步时注释掉纠正(points_3d, src, src1);,将获取到的八个点写入//points_3d[8]坐标数组中,因为是齐次坐标,x3 =1
  GetMouse (src1);//输入畸变图上的8个关键点
  Point3d  points_3d [8],=, {, Point3d (99,, 147,,,, Point3d (210,, 93,,,, Point3d (144,, 184,,,, Point3d (261,, 122,, 1),
  Point3d (144,, 184,,,, Point3d (99,, 147,,,, Point3d (261,, 122,,,, Point3d (210,, 93,, 1),};//第二步,校正图像,运行此步骤时注释掉GetMouse (src1);,解除注释纠正(points_3d, src, src1);//纠正(points_3d, src, src1);
  imshow (“yuantu", src);
  waitKey (0);
  }

其他函数:

void  on_mouse (int 事件,int  x,, int  y, int 旗帜,void *,科大)   {   ,,,CvFont 字体;   ,,,cvInitFont(和字体,,CV_FONT_HERSHEY_SIMPLEX,, 0.5, 0.5, 0,, 1,, CV_AA);      ,,,if  (event ==, CV_EVENT_LBUTTONDOWN)   ,,,{   ,,,,,,,CvPoint  pt =, cvPoint (x, y);   ,,,,,,,char 临时[16];   ,,,,,,,sprintf (temp,,“(% d % d)“,, pt.x,, pt.y);   ,,,,,,,cvPutText (src,临时,pt,,,字体,,cvScalar (255,, 255,, 255,, 0));   ,,,,,,,cvCircle (src, pt,, 2,, cvScalar (255, 0, 0, 0),, CV_FILLED,, CV_AA,, 0);   ,,,,,,,cvShowImage (“src",, src);   ,,,}   }      void  GetMouse (IplImage  * img)   {   ,,,src =, img;   ,,,cvNamedWindow (“src",, 1);   ,,,cvSetMouseCallback (“src",, on_mouse,, 0);      ,,,cvShowImage (“src",, src);   ,,,waitKey (0);   }

在弹出来的图片中点击任意地方可获得改点的图像坐标(x1, x2),如下图:

如何利用c++ OpenCV实现从投影图像恢复仿射特性