我的个人博客:谋仁·Blog
微信公众号:谋仁的麻袋
CSDN:曹谋仁


Point2f类

图像由一个个像素点组成,我们为了存储每一个像素点,通常用Point类中(x,y)坐标来表示。Point2f表示Point类的两个数据x,y为float类型。
为了将原图中的某一块区域处理成鸟瞰图,我们首先要用Point2f来确定几个点来框定待处理区域。在这里,我们将要将一张斜放的扑克牌处理成鸟瞰图。故用四个点就足够确定其范围。
然后再建立一个Point2f类数组存放与原图框定区域对应的处理后的鸟瞰图在新窗口中的位置。相应代码:

1
2
3
Point2f srcPoint[4] = { {530,143},{773,193},{403,394}, {674,455} };//原图中框定四个点
Point2f dstPoint[4] = { {0.0f,0.0f},{cardWidth,0.0f},{0.0f,cardHeight}, {cardWidth,cardHeight} };//分别对应鸟瞰图四个点

getPerspectiveTransform函数

函数作用:根据输入和输出点获得图像透视变换的矩阵
重载一:
函数定义:

1
2
3
4
5
Mat getPerspectiveTransform(
const Point2f src[],
const Point2f dst[],
int solveMethod = DECOMP_LU
);

参数解释:

  • src[]:输入点数组
  • dst[]:输出点数组
  • solveMethod:传递给cv::solve(DecompTypes) 解决一个或多个线性系统或最小二乘问题,DECOMP_LU是默认值。有关DecompTypes源代码是(解释已附在注释中):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
enum DecompTypes {
/** Gaussian elimination with the optimal pivot element chosen. */
DECOMP_LU = 0,//最佳主轴元素的高斯消元法
/** singular value decomposition (SVD) method; the system can be over-defined and/or the matrix
src1 can be singular */
DECOMP_SVD = 1,//奇异值分解(SVD)方法
/** eigenvalue decomposition; the matrix src1 must be symmetrical */
DECOMP_EIG = 2,//特征值分解法
/** Cholesky \f$LL^T\f$ factorization; the matrix src1 must be symmetrical and positively
defined */
DECOMP_CHOLESKY = 3,//Cholesky分解法
/** QR factorization; the system can be over-defined and/or the matrix src1 can be singular */
DECOMP_QR = 4,//QR分解法
/** while all the previous flags are mutually exclusive, this flag can be used together with
any of the previous; it means that the normal equations
\f$\texttt{src1}^T\cdot\texttt{src1}\cdot\texttt{dst}=\texttt{src1}^T\texttt{src2}\f$ are
solved instead of the original system
\f$\texttt{src1}\cdot\texttt{dst}=\texttt{src2}\f$ */
DECOMP_NORMAL = 16//使用正规方程公式,可以去前面的标志一起使用
};

重载二函数定义:

1
2
3
4
5
Mat getPerspectiveTransform(
InputArray src, //输入图像
InputArray dst, //输出图像
int solveMethod = DECOMP_LU//同上
);

warpPerspective函数

函数作用:对图像进行透视变换
函数定义:

1
2
3
4
5
6
7
8
9
void warpPerspective( 
InputArray src,
OutputArray dst,
InputArray M,
Size dsize,
int flags = INTER_LINEAR,
int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar()
);

参数解释:

  • src:Mat类,输入图像
  • dst:Mat类,透视变换后输出图像,与src数据类型相同
  • M:透视变换矩阵
  • dsize:输出图像大小
  • flags:插值方法标志,源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
enum InterpolationFlags{
/** nearest neighbor interpolation */
INTER_NEAREST = 0,
/** bilinear interpolation */
INTER_LINEAR = 1,
/** bicubic interpolation */
INTER_CUBIC = 2,
/** resampling using pixel area relation. It may be a preferred method for image decimation, as
it gives moire'-free results. But when the image is zoomed, it is similar to the INTER_NEAREST
method. */
INTER_AREA = 3,
/** Lanczos interpolation over 8x8 neighborhood */
INTER_LANCZOS4 = 4,
/** Bit exact bilinear interpolation */
INTER_LINEAR_EXACT = 5,
/** Bit exact nearest neighbor interpolation. This will produce same results as
the nearest neighbor method in PIL, scikit-image or Matlab. */
INTER_NEAREST_EXACT = 6,
/** mask for interpolation codes */
INTER_MAX = 7,
/** flag, fills all of the destination image pixels. If some of them correspond to outliers in the
source image, they are set to zero */
WARP_FILL_OUTLIERS = 8,
/** flag, inverse transformation

For example, #linearPolar or #logPolar transforms:
- flag is __not__ set: \f$dst( \rho , \phi ) = src(x,y)\f$
- flag is set: \f$dst(x,y) = src( \rho , \phi )\f$
*/
WARP_INVERSE_MAP = 16
};
  • borderMode:像素边界外推方法的标志,源代码:
1
2
3
4
5
6
7
8
9
10
11
12
enum BorderTypes {
BORDER_CONSTANT = 0, //!< `iiiiii|abcdefgh|iiiiiii` with some specified `i`
BORDER_REPLICATE = 1, //!< `aaaaaa|abcdefgh|hhhhhhh`
BORDER_REFLECT = 2, //!< `fedcba|abcdefgh|hgfedcb`
BORDER_WRAP = 3, //!< `cdefgh|abcdefgh|abcdefg`
BORDER_REFLECT_101 = 4, //!< `gfedcb|abcdefgh|gfedcba`
BORDER_TRANSPARENT = 5, //!< `uvwxyz|abcdefgh|ijklmno`

BORDER_REFLECT101 = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_DEFAULT = BORDER_REFLECT_101, //!< same as BORDER_REFLECT_101
BORDER_ISOLATED = 16 //!< do not look outside of ROI
};
  • Scalar& borderValue:边界的颜色设置,一般默认是0

    示例

    目的:将原图中斜放的♠K进行透视变换得到鸟瞰图。
    原图如下:

    源代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace cv;
using namespace std;
#ifdef _DEBUG
#pragma comment(lib,"opencv_world453d.lib")
#else
#pragma comment(lib,"opencv_world453.lib")
#endif // _DEBUG

/********************将一张斜放的扑克牌生成鸟瞰图*********************/
int main()
{
Mat transMatrix, imgOut;
float cardWidth = 250;
float cardHeight = 350;
string path = "D:\\My Bags\\图片\\cards.jpg";
Mat imgIn = imread(path);//读取原图像
Point2f srcPoint[4] = { {530,143},{773,193},{403,394}, {674,455} };//原图中框定四个点
Point2f dstPoint[4] = { {0.0f,0.0f},{cardWidth,0.0f},{0.0f,cardHeight}, {cardWidth,cardHeight} };//分别对应鸟瞰图四个点
transMatrix = getPerspectiveTransform(srcPoint, dstPoint);//得到透视变换的矩阵
warpPerspective(imgIn, imgOut, transMatrix, Size(cardWidth, cardHeight));//进行透视扭曲
imshow("原图", imgIn);
imshow("鸟瞰图", imgOut);
waitKey(0);
return 0;
}

运行结果:
原图
原图
♠K鸟瞰图:
鸟瞰图