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

透视变换
透视变换的原理和公式推导见如下博客
【图像处理】透视变换 Perspective Transformation
【OpenCV】透视变换 Perspective Transformation(续)
opencv之仿射变换
图像几何变换之透视变换
图像变换——向前映射和向后映射
opencv 相关函数
Mat getPerspectiveTransform(const Point2f* src, const Point2f* dst)
// Calculate a perspective transform from four pairs of the corresponding points.
// src – Coordinates of quadrangle vertices in the source image.
// dst – Coordinates of the corresponding quadrangle vertices in the destination image.void warpPerspective(InputArray src, OutputArray dst, InputArray M, Size dsize, int flags=INTER_LINEAR, int borderMode=BORDER_CONSTANT, const Scalar& borderValue=Scalar())
// Apply a perspective transform to an image.
// src – Source image.
// dst – Destination image that has the size dsize and the same type as src.
// M – 3*3 transformation matrix.
// dsize – Size of the destination image.
// flags – Combination of interpolation methods and the optional flag WARP_INVERSE_MAP that means that M is the inverse transformation (dstsrc).
// borderMode – Pixel extrapolation method. When borderMode=BORDER_TRANSPARENT, it means that the pixels in the destination image that corresponds to the “outliers” in the source image are not modified by the function.
// borderValue – Value used in case of a constant border. By default, it is 0.void perspectiveTransform(InputArray src, OutputArray dst, InputArray mtx)
Parameters:
src – Source two-channel or three-channel floating-point array. Each element is a 2D/3D vector to be transformed.
dst – Destination array of ***the same size and type as src*** .
mtx – 3x3 or 4x4 floating-point transformation matrix.
- c++ 代码实现
void ImageTransform::perspective_form(Mat &srcimg, Mat &dstimg, Mat &offset)
{Point2f quad_src[4];Point2f quad_dst[4];quad_src[0] = Point2f(0.0*srcimg.cols, 0.0*srcimg.rows);quad_src[1] = Point2f(srcimg.cols - 1, 0.0*srcimg.rows);quad_src[2] = Point2f(0.0*srcimg.cols, srcimg.rows - 1);quad_src[3] = Point2f(srcimg.cols - 1, srcimg.rows - 1);quad_dst[0] = Point2f(0.1*srcimg.cols, 0.1*srcimg.rows);quad_dst[1] = Point2f(srcimg.cols - 1, 0.0*srcimg.rows);quad_dst[2] = Point2f(0.0*srcimg.cols, srcimg.rows - 1);quad_dst[3] = Point2f(0.9*srcimg.cols, srcimg.rows - 1);Mat persMat = getPerspectiveTransform(quad_src, quad_dst);vector<Point2f> points, points_tran;for (int row = 0; row < srcimg.rows; row++){for (int col = 0; col < srcimg.cols; col++){points.push_back(Point2f(col, row));}}perspectiveTransform(points, points_tran, persMat);int count = 0;for (int row = 0; row < srcimg.rows; row++){uchar *pixel = srcimg.ptr<uchar>(row);float *dxy = offset.ptr<float>(row);for (int col = 0; col < srcimg.cols; col++){int x = static_cast<int>(points_tran[count].x);int y = static_cast<int>(points_tran[count].y);uchar *new_pixel = dstimg.ptr<uchar>(y);new_pixel[3 * x] = pixel[3 * col]; //最近邻插值new_pixel[3 * x + 1] = pixel[3 * col + 1];new_pixel[3 * x + 2] = pixel[3 * col + 2];dxy[2 * col] = points_tran[count].y - row;dxy[2 * col + 1] = points_tran[count].x - col;count++;}}return;}

程序运行结果