透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping)。通用的变换公式为:

u,v是原始图片左边,对应得到变换后的图片坐标x,y,其中
变换矩阵可以拆成4部分,表示线性变换,比如scaling,shearing和ratotion。用于平移,产生透视变换。所以可以理解成仿射等是透视变换的特殊形式。经过透视变换之后的图片通常不是平行四边形(除非映射视平面和原来平面平行的情况)。

重写之前的变换公式可以得到:

所以,已知变换对应的几个点就可以求取变换公式。反之,特定的变换公式也能新的变换后的图片。简单的看一个正方形到四边形的变换:
变换的4组对应点可以表示成:

根据变换公式得到:

定义几个辅助变量:

都为0时变换平面与原来是平行的,可以得到:

不为0时,得到:

求解出的变换矩阵就可以将一个正方形变换到四边形。反之,四边形变换到正方形也是一样的。于是,我们通过两次变换:四边形变换到正方形+正方形变换到四边形就可以将任意一个四边形变换到另一个四边形。

看一段代码:

PerspectiveTransform::PerspectiveTransform(float inA11, float inA21, 
                                          float inA31, float inA12, 
                                          float inA22, float inA32, 
                                          float inA13, float inA23, 
                                          float inA33) : 
  a11(inA11), a12(inA12), a13(inA13), a21(inA21), a22(inA22), a23(inA23),
  a31(inA31), a32(inA32), a33(inA33) {}

PerspectiveTransform PerspectiveTransform::quadrilateralToQuadrilateral(float x0, float y0, float x1, float y1,
    float x2, float y2, float x3, float y3, float x0p, float y0p, float x1p, float y1p, float x2p, float y2p,
    float x3p, float y3p) {
  PerspectiveTransform qToS = PerspectiveTransform::quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3);
  PerspectiveTransform sToQ =
    PerspectiveTransform::squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p);
  return sToQ.times(qToS);
}

PerspectiveTransform PerspectiveTransform::squareToQuadrilateral(float x0, float y0, float x1, float y1, float x2,
    float y2, float x3, float y3) {
  float dx3 = x0 - x1 + x2 - x3;
  float dy3 = y0 - y1 + y2 - y3;
  if (dx3 == 0.0f && dy3 == 0.0f) {
    PerspectiveTransform result(PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0f,
                                    0.0f, 1.0f));
    return result;
  } else {
    float dx1 = x1 - x2;
    float dx2 = x3 - x2;
    float dy1 = y1 - y2;
    float dy2 = y3 - y2;
    float denominator = dx1 * dy2 - dx2 * dy1;
    float a13 = (dx3 * dy2 - dx2 * dy3) / denominator;
    float a23 = (dx1 * dy3 - dx3 * dy1) / denominator;
    PerspectiveTransform result(PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0
                                    + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0f));
    return result;
  }
}

PerspectiveTransform PerspectiveTransform::quadrilateralToSquare(float x0, float y0, float x1, float y1, float x2,
    float y2, float x3, float y3) {
  // Here, the adjoint serves as the inverse:
  return squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3).buildAdjoint();
}

PerspectiveTransform PerspectiveTransform::buildAdjoint() {
  // Adjoint is the transpose of the cofactor matrix:
  PerspectiveTransform result(PerspectiveTransform(a22 * a33 - a23 * a32, a23 * a31 - a21 * a33, a21 * a32
                                  - a22 * a31, a13 * a32 - a12 * a33, a11 * a33 - a13 * a31, a12 * a31 - a11 * a32, a12 * a23 - a13 * a22,
                                  a13 * a21 - a11 * a23, a11 * a22 - a12 * a21));
  return result;
}

PerspectiveTransform PerspectiveTransform::times(PerspectiveTransform other) {
  PerspectiveTransform result(PerspectiveTransform(a11 * other.a11 + a21 * other.a12 + a31 * other.a13,
                                  a11 * other.a21 + a21 * other.a22 + a31 * other.a23, a11 * other.a31 + a21 * other.a32 + a31
                                  * other.a33, a12 * other.a11 + a22 * other.a12 + a32 * other.a13, a12 * other.a21 + a22
                                  * other.a22 + a32 * other.a23, a12 * other.a31 + a22 * other.a32 + a32 * other.a33, a13
                                  * other.a11 + a23 * other.a12 + a33 * other.a13, a13 * other.a21 + a23 * other.a22 + a33
                                  * other.a23, a13 * other.a31 + a23 * other.a32 + a33 * other.a33));
  return result;
}

void PerspectiveTransform::transformPoints(vector<float> &points) {
  int max = points.size();
  for (int i = 0; i < max; i += 2) {
    float x = points[i];
    float y = points[i + 1];
    float denominator = a13 * x + a23 * y + a33;
    points[i] = (a11 * x + a21 * y + a31) / denominator;
    points[i + 1] = (a12 * x + a22 * y + a32) / denominator;
  }
}

对一张透视图片变换回正面图的效果:

int main(){
 Mat img=imread("boy.png");
 int img_height = img.rows;
 int img_width = img.cols;
 Mat img_trans = Mat::zeros(img_height,img_width,CV_8UC3);
 PerspectiveTransform tansform = PerspectiveTransform::quadrilateralToQuadrilateral(
  0,0,
  img_width-1,0,
  0,img_height-1,
  img_width-1,img_height-1,
  150,250, // top left
  771,0, // top right
  0,1023,// bottom left
  650,1023
  );
 vector<float> ponits;
 for(int i=0;i<img_height;i++){
  for(int j=0;j<img_width;j++){
   ponits.push_back(j);
   ponits.push_back(i);
  }
 }
 tansform.transformPoints(ponits);
 for(int i=0;i<img_height;i++){
  uchar*  t= img_trans.ptr<uchar>(i);
  for (int j=0;j<img_width;j++){
   int tmp = i*img_width+j;
   int x = ponits[tmp*2];
   int y = ponits[tmp*2+1];
   if(x<0||x>(img_width-1)||y<0||y>(img_height-1))
    continue;
   uchar* p = img.ptr<uchar>(y);
   t[j*3] = p[x*3];
   t[j*3+1] = p[x*3+1];
   t[j*3+2] = p[x*3+2];
  }
 }
 imwrite("trans.png",img_trans);
 return 0;
}

另外在OpenCV中也实现了基础的透视变换操作,有关函数使用请见下一篇:【OpenCV】透视变换 Perspective Transformation(续)http://www.linuxidc.com/Linux/2014-12/110370.htm

转载于:https://www.cnblogs.com/Trove/p/6843999.html

【图像处理】透视变换 Perspective Transformation相关推荐

  1. 【OpenCV】透视变换 Perspective Transformation(续)

    透视变换的原理和矩阵求解请参见前一篇<透视变换 Perspective Transformation>.在OpenCV中也实现了透视变换的公式求解和变换函数. 求解变换公式的函数: [cp ...

  2. 【OpenCV】透视变换 Perspective Transformation

    透视变换的原理和矩阵求解请参见前一篇<透视变换 Perspective Transformation>.在OpenCV中也实现了透视变换的公式求解和变换函数. 求解变换公式的函数: Mat ...

  3. 【CG】透视变换(Perspective Transformation)

    起源 透视与消失点 单点透视 - 1 个消失点 两点透视 - 2个消失点 三点透视 - 3个消失点 透视投影变换 透视变换矩阵 透视变换矩阵与 Homography.相机内参的关系 透视与车载环境的联 ...

  4. 【图像处理】透视变换 Perspective Transformation(含续加部分)

    本文博文地址:https://blog.csdn.net/xiaowei_cqu/article/details/26471527#commentsedit 续文博文地址:https://blog.c ...

  5. 【图像处理】透视变换 Perspective Transformation(小细节修正和推导流程补充)

    这部分的推导,首先是求解∆x3,∆y3,然后通过得到的方程组,求解可得a13,a23,然后通过∆x1,∆x2分别求得a21,a11,同样的通过∆y1,∆y2求得a22和a12,至此透视变换矩阵所有元素 ...

  6. 透视变换(perspective transformation)

    透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping).如下图所示 透视变换 ...

  7. 图像处理中的投影变换(Perspective Transformation)

    透视变换(Perspective Transformation)是将图片投影到一个新的视平面(Viewing Plane),也称作投影映射(Projective Mapping).通用的变换公式为: ...

  8. 『CV学习笔记』图像处理透视变换(Python+Opencv)

    图像处理透视变换(Opencv) 文章目录 一. 透视变换定义 二. 代码实现 2.1. order_points函数 2.2. four_point_transform函数 2.3. 程序主函数 三 ...

  9. 透视变换(perspective transformation)和射影(投影)变换(projective transformation)

    透视变换(perspective transformation)和射影(投影)变换(projective transformation) 0几点说明 投影和变换的区别. 投影分为:平行投影或者正射投影 ...

最新文章

  1. 转:C#读取Excel文件 (2009年9月28日)
  2. Spring.Net官网翻译
  3. pg 递归算法_16. 图的________优先搜索遍历算法是一种递归算法,图的________优先搜索遍历算法需要使用队列。...
  4. 本地安装gem install --local redis-stat-0.4.13.gem
  5. 嵌入式linux完整top命令,linux的top命令详解
  6. node.js开发环境配置
  7. libsvm回归参数寻优cgp_【lightgbm/xgboost/nn代码整理二】xgboost做二分类,多分类以及回归任务...
  8. Statefulset:部署有状态的多副本应用
  9. 模拟数据集上训练神经网络,网络解决二分类问题练习
  10. 毕业不到一年的前端开发同学的焦虑
  11. Silverlig“.NET研究”ht性能优化纪要
  12. 游戏挂机时计算机设置在哪里,蜂窝助手怎么挂机 游戏蜂窝电脑版挂机设置教程...
  13. ureport2报表详细使用(六)-图表展示
  14. Qt Style Sheet实践(二):组合框QComboBox的定制
  15. 流体连续性方程【The Equation of Continuity】
  16. linux插网卡不能识别,linux-解决添加的网卡无法识别的问题
  17. 【Web前端】彼岸の花——网上花店(网页制作)
  18. iOS的三种常见计时器(NStimer、CADisplayLink、dispatch_source_t)的使用
  19. 【论文阅读】Attention Based Spatial-Temporal GCN...Traffic Flow Forecasting[基于注意力的时空图卷积网络交通流预测](1)
  20. python爬虫爬取拉勾网职业信息

热门文章

  1. EXPORT_SYMBOL的作用是什么
  2. 轻松解决Windows7声卡驱动不全问题
  3. 2011 年最重要的 10 个开源软件
  4. CSS布局代码:两列布局实例
  5. telegraf input的配置
  6. [iOS]过渡动画之高级模仿 airbnb
  7. Ubuntu 下添加OpenERP command 快捷启动方式
  8. 如何使Sybase ASE中对象名不区分大小写?
  9. 从春晚说起:总有一种无耻让我们泪流满面
  10. ASP.NET基础教程-DataView对象的属性、方法、枚举成员